{"version":3,"file":"index.bundle.js?hash=e7a96fec4e323778f66f","mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAWA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA2GA;AACA;;;;;;;;;;;;;;;;;;;ACztCA;AAEA;AAEA;AAEA;AAIA;AACA;AAMA;AAGA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAAA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AAEA;AAIA;AAEA;AAEA;AAIA;AAGA;AAAA;AAGA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AACA;AAEA;AAIA;AAGA;AAAA;AAGA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AACA;AAEA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AAKA;;;;;;;;;;;;;;;;;;;;;;;;;AC/gIA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAEA;AAEA;AAAA;AAWA;AALA;AAMA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AArCA;AAwCA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAGA;AAAA;AACA;AACA;AACA;AAKA;AAAA;AACA;AACA;AACA;AAUA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AA7GA;AAgHA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAjIA;AAoIA;AAGA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AAGA;AAAA;AAEA;AAGA;AAAA;AAEA;AAGA;AAAA;AAEA;AAGA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAvKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACdA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAJA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClDA;AAYA;AAKA;AAYA;AAGA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAUA;AAqDA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9GA;AAGA;AAOA;AAAA;AACA;AAAA;AAIA;AAEA;AAAA;AADA;AA2CA;AAAA;AAxCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA2BA;AAAA;AAxBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9FA;AAEA;AACA;AACA;AAKA;AAAA;AAMA;AAJA;AACA;AACA;AAAA;AAGA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAzDA;AAAA;AADA;AAGA;AACA;AACA;AAbA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAAA;AACA;AAJA;AAAA;AADA;AAHA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAKA;AAAA;AAmBA;AANA;AACA;AACA;AAEA;AAdA;AACA;AACA;AAGA;AAAA;AAYA;AAGA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AAEA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AAIA;AACA;AAEA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAKA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAIA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AAEA;AAEA;AAEA;AAGA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAMA;AAAA;AACA;AAEA;AAIA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AArVA;AAwVA;AACA;AACA;AAEA;AAYA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAjXA;AAAA;AADA;AAcA;AACA;AACA;AACA;AA7BA;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AAJA;AAAA;AAOA;;;;;;;;;;;;;;;;ACLA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AAGA;AAEA;AAEA;AAEA;AAEA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;ACjCA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAuBA;AAtBA;AAKA;AACA;AAQA;AASA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAIA;AAIA;AAIA;AAIA;AAIA;AAEA;AACA;AAGA;AAEA;AACA;AAEA;AAEA;AAEA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AAIA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AAEA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;AClOA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAwBA;AAvBA;AAMA;AACA;AAiBA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAIA;AAIA;AAIA;AAIA;AAIA;AAEA;AACA;AAGA;AAEA;AACA;AAEA;AAEA;AACA;AAEA;AAAA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AAIA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpOA;AAGA;AAeA;AAAA;AACA;AAAA;AAIA;AAHA;AAIA;AAEA;AAAA;AAAA;AA4IA;AAAA;AA1IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAUA;AAAA;AAPA;AACA;AACA;AACA;AACA;AACA;AACA;AAeA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA2CA;AAAA;AAxCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA2CA;AAAA;AAxCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAoBA;AAAA;AAjBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAmBA;AAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAeA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAeA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAeA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAgBA;AAAA;AAbA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAgBA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAsBA;AAAA;AAnBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAYA;AAAA;AATA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAgBA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAgBA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAgBA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAkBA;AAAA;AAdA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAkBA;AAAA;AAdA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAkBA;AAAA;AAdA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAeA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAeA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAcA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAqBA;AAAA;AAlBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAmBA;AAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtlBA;AAEA;AACA;AACA;AAMA;AAAA;AAWA;AAPA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAEA;AAEA;AAEA;AAAA;AACA;AAGA;AAIA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AA/DA;AAkEA;AACA;AACA;AAEA;AAaA;AACA;AAAA;AAGA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AArLA;AAAA;AADA;AAKA;AACA;AACA;AACA;AAEA;AAnBA;AAiMA;AACA;AACA;AACA;AAHA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjMA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAOA;AAAA;AAuEA;AALA;AACA;AAEA;AAjEA;AAoDA;AAGA;AAGA;AACA;AAAA;AASA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AAIA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AAGA;AAMA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AAGA;AAEA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAKA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AAEA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAUA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAWA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAUA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAGA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAGA;AAGA;AAKA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AAr8BA;AAw8BA;AAEA;AAAA;AAEA;AA37BA;AAAA;AADA;AAmEA;AACA;AACA;AArFA;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AAEA;AAAA;AAUA;AATA;AAEA;AAQA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAGA;AAEA;AACA;AAEA;AAEA;AACA;AAEA;AAAA;AAGA;AAAA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AAlDA;AAqDA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AAEA;AAAA;AACA;AAAA;AAAA;AAGA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;AClGA;AACA;AACA;AACA;AAEA;AAAA;AAUA;AATA;AAEA;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAGA;AAEA;AACA;AAEA;AAEA;AACA;AAEA;AAAA;AAGA;AAAA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AAEA;AAAA;AACA;AAAA;AAAA;AAEA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;ACxEA;AACA;AACA;AACA;AACA;AAJA;AAAA;AAOA;;;;;;;;;;;;;;;;ACLA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AAGA;AAEA;AAEA;AAEA;AAEA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;ACjCA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAwBA;AAvBA;AAMA;AACA;AAiBA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAIA;AAIA;AAIA;AAIA;AAIA;AAEA;AACA;AAGA;AAEA;AACA;AAEA;AAEA;AACA;AAEA;AAAA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AAIA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;ACtOA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAsBA;AArBA;AAKA;AACA;AAgBA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAIA;AAIA;AAIA;AAIA;AAIA;AAEA;AACA;AAGA;AAEA;AACA;AAEA;AAEA;AAEA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AAIA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AAEA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7NA;AAWA;AAmBA;AAAA;AACA;AAAA;AAIA;AAHA;AAIA;AAEA;AAu9BA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAAA;AAj0BA;AAAA;AA3LA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAUA;AAAA;AAPA;AACA;AACA;AACA;AACA;AACA;AACA;AAUA;AAAA;AANA;AACA;AACA;AACA;AACA;AACA;AAmBA;AAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAyGA;AAAA;AAlBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAoBA;AAAA;AAjBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAuBA;AAAA;AApBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAaA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAiBA;AAAA;AAdA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAgBA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAgBA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAgBA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAeA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAaA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAaA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AASA;AAAA;AANA;AACA;AACA;AACA;AACA;AACA;AAqBA;AAAA;AAlBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAqBA;AAAA;AAlBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAiEA;AAAA;AA7DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA4DA;AAAA;AAzDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA4DA;AAAA;AAzDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA4DA;AAAA;AAzDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA6DA;AAAA;AA1DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAYA;AAAA;AATA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA+GA;AAAA;AANA;AACA;AACA;AACA;AACA;AACA;AAcA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAiBA;AAAA;AAbA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAiDA;AAAA;AAJA;AACA;AACA;AACA;AAcA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAyCA;AAAA;AArCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAwCA;AAAA;AArCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAkCA;AAAA;AA/BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAkCA;AAAA;AA/BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAiBA;AAAA;AAdA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjuCA;AACA;AACA;AACA;AACA;AAQA;AAAA;AAaA;AARA;AACA;AACA;AAEA;AACA;AACA;AATA;AA0FA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAEA;AAAA;AAKA;AACA;AA9FA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AAAA;AACA;AAGA;AAGA;AACA;AAAA;AAGA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAtGA;AA2HA;AACA;AACA;AAEA;AAaA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAOA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAMA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAtSA;AAAA;AADA;AAMA;AACA;AACA;AACA;AAEA;AACA;AAvBA;AAoTA;AACA;AACA;AACA;AACA;AAJA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpTA;AACA;AACA;AACA;AACA;AAIA;AAAA;AAOA;AAFA;AAAA;AAGA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AA7BA;AAAA;AADA;AAKA;AAZA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAGA;AAAA;AAAA;AAAA;AA4FA;AALA;AACA;AAEA;AAzFA;AAMA;AAAA;AAgCA;AAwBA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA;AAAA;AAAA;AAEA;AACA;AAOA;AAAA;AAgBA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAYA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAIA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AAUA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AAGA;AAKA;AAUA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAGA;AACA;AACA;AAMA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AAGA;AAAA;AAEA;AACA;AAGA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuBA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAIA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAIA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAIA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAIA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoDA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAaA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAmBA;AAGA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAIA;AACA;AACA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAIA;AACA;AACA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAIA;AACA;AACA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAIA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAGA;AAAA;AAEA;AACA;AAGA;AAAA;AAEA;AACA;AAGA;AAAA;AAEA;AACA;AAGA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AAAA;AACA;AAUA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAIA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAIA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAIA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AACA;AASA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAGA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAOA;AACA;AAEA;AACA;AAYA;AACA;AACA;AAKA;AAAA;AAQA;AACA;AAYA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAMA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAEA;AAMA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AAAA;AACA;AAz1CA;AA41CA;AAEA;AAAA;AAEA;AAh1CA;AAAA;AADA;AAwFA;AACA;AACA;AAzGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAGA;AAGA;AAAA;AA6CA;AArCA;AAGA;AAAA;AA6BA;AAAA;AACA;AACA;AAIA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAIA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAIA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAEA;AAGA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAUA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAAA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AAQA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AAEA;AAIA;AACA;AACA;AAAA;AAIA;AACA;AAEA;AACA;AAEA;AACA;AAGA;AACA;AAEA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAAA;AAIA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAGA;AAAA;AACA;AAAA;AAKA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;AC9fA;AACA;AACA;AACA;AACA;AAJA;AAAA;AAOA;;;;;;;;;;;;;;;;ACLA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AAGA;AAEA;AAEA;AAEA;AAEA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;ACjCA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAwBA;AAvBA;AAMA;AACA;AAiBA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAIA;AAIA;AAIA;AAIA;AAIA;AAEA;AACA;AAGA;AAEA;AACA;AAEA;AAEA;AACA;AAEA;AAAA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AAIA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;ACtOA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAuBA;AAtBA;AAKA;AACA;AAQA;AASA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAIA;AAIA;AAIA;AAIA;AAIA;AAEA;AACA;AAGA;AAEA;AACA;AAEA;AAEA;AAEA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AAIA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxNA;AAEA;AA8BA;AAAA;AACA;AAAA;AAIA;AAHA;AAIA;AAEA;AA42BA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AA5vBA;AAAA;AArJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAUA;AAAA;AAPA;AACA;AACA;AACA;AACA;AACA;AACA;AAeA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA2CA;AAAA;AAxCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA2CA;AAAA;AAxCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAoBA;AAAA;AAjBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAmBA;AAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAsBA;AAAA;AAnBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAYA;AAAA;AATA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAeA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAgBA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAgBA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAgBA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAeA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAaA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAuBA;AAAA;AApBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAiBA;AAAA;AAdA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAqBA;AAAA;AAlBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAmBA;AAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAwDA;AAAA;AApDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAuDA;AAAA;AApDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAuDA;AAAA;AApDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAuDA;AAAA;AApDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA0BA;AAAA;AAvBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAkBA;AAAA;AAdA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA4CA;AAAA;AAxCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA2CA;AAAA;AAxCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAaA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAeA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAgBA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAiDA;AAAA;AAJA;AACA;AACA;AACA;AAcA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACz9BA;AAEA;AACA;AACA;AAOA;AAAA;AAWA;AAPA;AACA;AACA;AAEA;AACA;AAPA;AA0FA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAEA;AAAA;AAKA;AACA;AAhGA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AAAA;AACA;AAGA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAqBA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAlOA;AAAA;AADA;AAKA;AACA;AACA;AACA;AAEA;AApBA;AA+OA;AACA;AACA;AACA;AACA;AAJA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/OA;AAUA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAAA;AAAA;AAAA;AAmFA;AALA;AACA;AAEA;AAhFA;AAMA;AAAA;AA+BA;AAaA;AACA;AAIA;AAEA;AACA;AAOA;AAMA;AAAA;AAYA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AAEA;AAIA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AAGA;AAMA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AAGA;AAEA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAKA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AASA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAEA;AACA;AAIA;AAAA;AAEA;AACA;AAIA;AAAA;AAEA;AACA;AAIA;AAAA;AAEA;AACA;AAIA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAGA;AAAA;AAEA;AACA;AAGA;AAAA;AAEA;AACA;AAGA;AAAA;AAEA;AACA;AAGA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AAAA;AACA;AAUA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAIA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAIA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAIA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AACA;AASA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAGA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAGA;AAGA;AAKA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAEA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAIA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAKA;AAEA;AACA;AAIA;AAAA;AAGA;AACA;AAAA;AACA;AAEA;AAEA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AAlrCA;AAqrCA;AAEA;AAAA;AAEA;AAjqCA;AAAA;AADA;AA+EA;AACA;AACA;AAxGA;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AAEA;AACA;AAEA;AACA;AAGA;AAAA;AAAA;AAAA;AAWA;AAPA;AAQA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAEA;AAEA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAOA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AACA;AA/EA;AAkFA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AAEA;AAnFA;;;;;;;;;;;;;;;;;;;;;ACVA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAFA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1BA;AAEA;AACA;AACA;AACA;AAIA;AAAA;AAUA;AALA;AAEA;AACA;AAAA;AAGA;AAGA;AACA;AAAA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AAEA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AA9EA;AAAA;AADA;AAMA;AACA;AAEA;AAjBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AAQA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACXA;AAMA;AAAA;AACA;AAAA;AAIA;AAHA;AAIA;AAAA;AAAA;AAWA;AAAA;AATA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AAGA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/BA;AAMA;AAAA;AACA;AAAA;AAIA;AAHA;AAIA;AAAA;AAAA;AAWA;AAAA;AATA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AAGA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpCA;AACA;AACA;AACA;AAEA;AAGA;AAEA;AAEA;AAAA;AAWA;AARA;AASA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAEA;AAEA;AACA;AAEA;AAEA;AAEA;AAEA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAWA;AAAA;AACA;AACA;AACA;AAKA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAhHA;AAAA;AAZA;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAHA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxCA;AACA;AACA;AACA;AAQA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAoBA;AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtCA;AAEA;AACA;AAWA;AAAA;AAEA;AAAA;AAIA;AAHA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AA8EA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAyJA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AA5SA;AAAA;AANA;AACA;AACA;AACA;AACA;AACA;AAaA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAaA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAaA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAoBA;AAAA;AAjBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAaA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAoMA;AAAA;AApJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAyCA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzZA;AAQA;AAGA;AACA;AAEA;AAGA;AAAA;AAaA;AANA;AACA;AACA;AACA;AACA;AAPA;AAWA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAGA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AAtDA;AAyDA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AAEA;AAAA;AACA;AAWA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAGA;AAIA;AAAA;AAEA;AACA;AAAA;AAGA;AAAA;AAEA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAKA;AAAA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AAEA;AAKA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAEA;AA5PA;AAAA;AADA;AAQA;AACA;AACA;AACA;AACA;AA5BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AAQA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAGA;AAAA;AAqCA;AAPA;AACA;AACA;AACA;AAEA;AAlCA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAKA;AAIA;AAMA;AACA;AAWA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AAEA;AAEA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAAA;AAGA;AAEA;AAEA;AAEA;AAIA;AAEA;AAAA;AAEA;AAGA;AAEA;AAAA;AAEA;AAGA;AAEA;AAAA;AAEA;AAGA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAIA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AAEA;AACA;AAAA;AAEA;AAEA;AAEA;AACA;AAAA;AAEA;AAEA;AAEA;AACA;AAAA;AAEA;AAEA;AAEA;AACA;AAAA;AAEA;AAEA;AAGA;AAEA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AAAA;AACA;AAtQA;AAyQA;AACA;AAMA;AACA;AASA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAzWA;AA4WA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAhbA;AAkbA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAIA;AAIA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAIA;AAGA;AAOA;AAAA;AAGA;AACA;AAEA;AAKA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAIA;AAMA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAUA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AAAA;AAKA;AAAA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAEA;AAOA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AAMA;AAAA;AAEA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AAGA;AAAA;AAGA;AAAA;AACA;AAGA;AAEA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAMA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAUA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAMA;AAEA;AACA;AAEA;AAIA;AAEA;AAEA;AACA;AAGA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAGA;AAAA;AAGA;AACA;AAEA;AACA;AAAA;AAGA;AAIA;AAIA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAKA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AArqCA;AAAA;AADA;AA+BA;AACA;AACA;AACA;AACA;AAvDA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACKA;AAEA;AACA;AAWA;AAAA;AAEA;AAAA;AAIA;AAHA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AA8EA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAyJA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AA5SA;AAAA;AANA;AACA;AACA;AACA;AACA;AACA;AAaA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAaA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAaA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAoBA;AAAA;AAjBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAaA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAoMA;AAAA;AApJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAyCA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzZA;AAQA;AAGA;AACA;AAEA;AAGA;AAAA;AAaA;AANA;AACA;AACA;AACA;AACA;AAPA;AAWA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAGA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AAAA;AAtDA;AAyDA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AAEA;AAAA;AACA;AAWA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAGA;AAIA;AAAA;AAEA;AACA;AAAA;AAGA;AAAA;AAEA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAKA;AAAA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AAEA;AAKA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAEA;AA5PA;AAAA;AADA;AAQA;AACA;AACA;AACA;AACA;AA5BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AAQA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAMA;AAAA;AA8BA;AAPA;AACA;AACA;AACA;AAEA;AAfA;AAGA;AAAA;AACA;AAcA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAEA;AAAA;AACA;AAGA;AAKA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AA9JA;AAiKA;AAOA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAGA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAIA;AACA;AACA;AAEA;AAKA;AAIA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AAKA;AAEA;AAIA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAGA;AAEA;AAGA;AAGA;AAIA;AAGA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AAlYA;AAqYA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAKA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAMA;AAIA;AAEA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAGA;AAAA;AACA;AAGA;AAEA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAEA;AAMA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAEA;AAIA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AAIA;AACA;AACA;AAAA;AAEA;AACA;AAKA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AAhiBA;AAmiBA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAMA;AACA;AAAA;AACA;AACA;AAzlBA;AA4lBA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAMA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAaA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAKA;AAAA;AAEA;AAEA;AAIA;AAAA;AAEA;AAMA;AAAA;AACA;AACA;AAGA;AAMA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAEA;AAIA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AAEA;AACA;AAEA;AAAA;AACA;AA38BA;AA88BA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAEA;AAKA;AAAA;AACA;AACA;AAEA;AA9/BA;AAAA;AADA;AAwBA;AACA;AACA;AACA;AACA;AAlDA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACKA;AAEA;AACA;AAWA;AAAA;AAEA;AAAA;AAIA;AAHA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AA8EA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAyJA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AA5SA;AAAA;AANA;AACA;AACA;AACA;AACA;AACA;AAaA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAaA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAaA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAoBA;AAAA;AAjBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAaA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAoMA;AAAA;AApJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAyCA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzZA;AAQA;AAGA;AACA;AAEA;AAGA;AAAA;AAaA;AANA;AACA;AACA;AACA;AACA;AAPA;AAWA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAGA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AAAA;AAtDA;AAyDA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAGA;AAIA;AAAA;AAEA;AACA;AAAA;AAGA;AAAA;AAEA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAKA;AAAA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AAEA;AAKA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAEA;AAvPA;AAAA;AADA;AAQA;AACA;AACA;AACA;AACA;AA5BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AAQA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAMA;AAAA;AA+BA;AARA;AACA;AACA;AACA;AAEA;AACA;AAhBA;AAGA;AAAA;AACA;AAeA;AACA;AAAA;AAGA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAKA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAnLA;AAsLA;AAQA;AAIA;AAKA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAGA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAIA;AACA;AACA;AAEA;AAKA;AAIA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAEA;AAIA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAGA;AAEA;AAGA;AACA;AACA;AAAA;AAGA;AAGA;AAIA;AAGA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AAlcA;AAqcA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAKA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAMA;AAIA;AAEA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAEA;AAMA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAEA;AAIA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AAIA;AACA;AACA;AAAA;AAEA;AACA;AAKA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AA9mBA;AAinBA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAMA;AACA;AAAA;AACA;AACA;AA5qBA;AA+qBA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AAAA;AAEA;AAQA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAQA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAKA;AAAA;AAEA;AAEA;AAIA;AAAA;AAEA;AAMA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAKA;AAAA;AAEA;AAOA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AAEA;AACA;AAAA;AAGA;AAEA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAEA;AAIA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AAEA;AACA;AAEA;AAAA;AACA;AA9lCA;AAimCA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAEA;AAKA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AAppCA;AAAA;AADA;AAwBA;AACA;AACA;AACA;AACA;AAEA;AArDA;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAUA;AALA;AAMA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AAEA;AACA;AAEA;AAEA;AAGA;AAGA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AA3EA;AA4FA;AAAA;AACA;AAGA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAtGA;;;;;;;;;;;;;;;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAFA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/BA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAmDA;AAlDA;AAOA;AACA;AA2CA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAIA;AAIA;AAIA;AAIA;AAIA;AAEA;AACA;AAGA;AAEA;AACA;AAEA;AAEA;AAEA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAMA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AAMA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAGA;AACA;AAIA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAIA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAWA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAMA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAMA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAKA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AARA;AAAA;AAWA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAWA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC5oBA;AAQA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAkBA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChCA;AAEA;AASA;AAAA;AACA;AAAA;AAIA;AAHA;AAIA;AAEA;AA6HA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAxKA;AAAA;AAtCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA6BA;AAAA;AA1BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAoDA;AAAA;AAjDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA4FA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC5OA;AACA;AACA;AACA;AACA;AACA;AAGA;AAGA;AAAA;AASA;AAPA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAIA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAMA;AAAA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAIA;AAIA;AAIA;AAEA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAKA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAIA;AAzOA;AA4OA;AAMA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AAzPA;AAAA;AADA;AAGA;AACA;AACA;AAEA;AACA;AAlBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAAA;AAbA;AA6CA;AANA;AACA;AAEA;AACA;AA7BA;AAEA;AAIA;AAIA;AAEA;AAEA;AACA;AAKA;AACA;AACA;AAUA;AAIA;AACA;AAAA;AACA;AACA;AAIA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAIA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AAOA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AA1QA;AA6QA;AAAA;AAIA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AAEA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAGA;AAEA;AACA;AAjYA;AAoYA;AAAA;AACA;AAIA;AAGA;AAIA;AAEA;AAAA;AACA;AAnZA;AA4ZA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAIA;AAQA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAGA;AACA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AAEA;AAGA;AACA;AAGA;AACA;AAEA;AACA;AAEA;AAEA;AAEA;AAGA;AACA;AAEA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAOA;AACA;AAKA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AAEA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AA3pBA;AA8pBA;AAEA;AAAA;AACA;AAGA;AAIA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAEA;AApqBA;AAAA;AADA;AA2BA;AACA;AACA;AAEA;AA3CA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACMA;AAEA;AAUA;AAAA;AACA;AAAA;AAIA;AAHA;AAIA;AAEA;AA+HA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAgBA;AAAA;AAAA;AAzLA;AAAA;AAtCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA6BA;AAAA;AA1BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAsDA;AAAA;AAnDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAuGA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9PA;AACA;AACA;AACA;AACA;AACA;AAEA;AAIA;AAAA;AASA;AAPA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AAEA;AAAA;AAEA;AACA;AAGA;AAIA;AAAA;AAEA;AAEA;AAAA;AAEA;AACA;AAGA;AACA;AACA;AAEA;AAMA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAEA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AAGA;AAIA;AAIA;AAIA;AAEA;AAEA;AACA;AAGA;AACA;AAAA;AAEA;AAKA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AAIA;AAxOA;AA2OA;AAMA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AAxPA;AAAA;AADA;AAGA;AACA;AACA;AAEA;AACA;AAlBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAAA;AAbA;AA8CA;AANA;AACA;AAEA;AACA;AA9BA;AAEA;AAIA;AAKA;AAEA;AAEA;AACA;AAKA;AACA;AACA;AAUA;AAGA;AACA;AAIA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAIA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAGA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAIA;AACA;AAIA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AAOA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAIA;AAAA;AACA;AACA;AAQA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AAAA;AACA;AAGA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AA3RA;AA8RA;AAAA;AAIA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AAEA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AAEA;AACA;AAOA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAIA;AACA;AAEA;AAKA;AACA;AACA;AAIA;AAAA;AAGA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AAvbA;AAgcA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAIA;AAOA;AACA;AACA;AAOA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAKA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAKA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AAIA;AAMA;AACA;AACA;AACA;AAAA;AACA;AAIA;AACA;AAIA;AACA;AAEA;AAEA;AAEA;AAGA;AACA;AAEA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAOA;AACA;AAKA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAGA;AACA;AAAA;AAGA;AAEA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AAEA;AAAA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;AAEA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AAluBA;AAquBA;AAEA;AAAA;AACA;AAGA;AAIA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAEA;AA3uBA;AAAA;AADA;AA4BA;AACA;AACA;AAEA;AA5CA;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AAYA;AARA;AAKA;AAIA;AAAA;AACA;AAEA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAvFA;AA0FA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAvGA;AA0GA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AAEA;AA3GA;;;;;;;;;;;;;;;;;;;;;ACTA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAFA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1BA;AACA;AACA;AACA;AACA;AACA;AACA;AAQA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChBA;AAGA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AAIA;AAHA;AAcA;AAEA;AACA;AAEA;AAAA;AAAA;AAAA;AAPA;AAAA;AARA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAUA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/BA;AAEA;AACA;AACA;AACA;AACA;AACA;AAIA;AAAA;AAiBA;AALA;AACA;AAEA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AAAA;AACA;AAIA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAEA;AAIA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAtNA;AAyNA;AACA;AAEA;AAMA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAEA;AAjPA;AAAA;AADA;AAaA;AACA;AACA;AAzBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAGA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AAIA;AAHA;AAcA;AAEA;AACA;AAEA;AAAA;AAAA;AAAA;AAPA;AAAA;AARA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAUA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAgBA;AAAA;AAzBA;AAoDA;AArBA;AAQA;AAAA;AACA;AAKA;AACA;AAQA;AAAA;AACA;AACA;AACA;AAIA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AAKA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAxFA;AA2FA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AAEA;AACA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAlIA;AAqIA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAMA;AAKA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAjNA;AAsNA;AAEA;AAAA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AAEA;AACA;AACA;AAAA;AAIA;AACA;AAAA;AAEA;AAvOA;AAAA;AAAA;AAzBA;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAHA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnCA;AAKA;AACA;AAUA;AAAA;AAEA;AAEA;AAAA;AAKA;AAHA;AAoCA;AAAA;AAAA;AAjBA;AAAA;AACA;AACA;AAQA;AACA;AACA;AACA;AACA;AACA;AAlBA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAqCA;AAAA;AAdA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAQA;AAAA;AAJA;AACA;AACA;AACA;AAgBA;AAAA;AAbA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAyBA;AAAA;AArBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAQA;AAAA;AAJA;AACA;AACA;AACA;AAwBA;AAAA;AArBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/JA;AAUA;AAEA;AACA;AACA;AAIA;AAAA;AAWA;AAPA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAGA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AA/CA;AAgDA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAEA;AAIA;AAKA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AAaA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAGA;AAOA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAtLA;AA4MA;AAUA;AAAA;AAEA;AAAA;AACA;AAKA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAIA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AAEA;AAxPA;AAAA;AADA;AAKA;AACA;AACA;AACA;AACA;AACA;AA3BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAEA;AAEA;AACA;AACA;AACA;AAIA;AAAA;AAsCA;AALA;AACA;AAEA;AAAA;AAGA;AA3BA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAYA;AAAA;AACA;AAGA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAgBA;AAnFA;AAsFA;AACA;AAAA;AACA;AACA;AAGA;AAIA;AACA;AAKA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAKA;AAEA;AAAA;AAEA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAEA;AAjOA;AAAA;AADA;AAkCA;AACA;AACA;AA9CA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AAEA;AAEA;AAOA;AAEA;AAEA;AAEA;AAcA;AAEA;AAGA;AAEA;AACA;AACA;AAgBA;AAEA;AAEA;AAEA;AACA;AAIA;AAEA;AAmEA;AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvIA;AAKA;AAiBA;AAAA;AAEA;AAAA;AAIA;AAHA;AA0MA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAvOA;AAAA;AACA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AAjBA;AAAA;AADA;AAwBA;AAAA;AAJA;AACA;AACA;AACA;AAaA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAkBA;AAAA;AAfA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAkBA;AAAA;AAfA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAkBA;AAAA;AAfA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAkBA;AAAA;AAfA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAQA;AAAA;AANA;AACA;AACA;AACA;AACA;AACA;AAcA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAmBA;AAAA;AAfA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAkBA;AAAA;AAfA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAkBA;AAAA;AAfA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAaA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AASA;AAAA;AANA;AACA;AACA;AACA;AACA;AACA;AA8CA;AAAA;AAHA;AACA;AACA;AAsBA;AAAA;AAnBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAUA;AAAA;AAPA;AACA;AACA;AACA;AACA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AAOA;AAAA;AAHA;AACA;AACA;AAQA;AAAA;AAHA;AACA;AACA;AAsBA;AAAA;AAnBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AAUA;AAAA;AAPA;AACA;AACA;AACA;AACA;AACA;AACA;AAQA;AAAA;AAJA;AACA;AACA;AACA;AAWA;AAAA;AARA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAUA;AAAA;AAPA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnYA;AAUA;AAEA;AACA;AACA;AAGA;AAAA;AAWA;AAPA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AA/BA;AAgCA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAIA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AAIA;AAIA;AAKA;AACA;AACA;AAAA;AAEA;AAOA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAOA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AA9JA;AAiKA;AAKA;AAAA;AAGA;AAaA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AA3LA;AA8LA;AAKA;AAAA;AAGA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAYA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAGA;AAEA;AAGA;AAEA;AAIA;AACA;AAAA;AAKA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AAYA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AAMA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAEA;AAAA;AAEA;AA/RA;AAAA;AADA;AAKA;AACA;AACA;AACA;AACA;AACA;AA1BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAQA;AAEA;AACA;AACA;AACA;AACA;AAIA;AAAA;AAgEA;AANA;AACA;AAEA;AACA;AAzBA;AAkBA;AAUA;AAAA;AACA;AAhEA;AAMA;AAAA;AAEA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAoCA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AAEA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AAEA;AAEA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAGA;AAEA;AACA;AAGA;AAGA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAMA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAIA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AAEA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAGA;AAAA;AACA;AAGA;AAIA;AAEA;AAriBA;AAwiBA;AAKA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AAEA;AAAA;AACA;AAtkBA;AAykBA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AArmBA;AAAA;AADA;AA2DA;AACA;AACA;AAEA;AAhFA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACOA;AAsBA;AAEA;AAAA;AAIA;AAIA;AAEA;AAAA;AACA;AACA;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAKA;AAHA;AAoCA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAsDA;AA2dA;AAAA;AAAA;AA1iBA;AACA;AAAA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AAkhBA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AA5iBA;AAAA;AAdA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA0CA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAcA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAcA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAcA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAWA;AAAA;AANA;AACA;AACA;AACA;AACA;AACA;AAcA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAcA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAaA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAeA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAcA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAaA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAaA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAcA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAcA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA8EA;AAAA;AA3EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA4CA;AAAA;AAzCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA+CA;AAAA;AA5CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAuDA;AAAA;AApDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAwBA;AAAA;AArBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAoDA;AAAA;AAjDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAuBA;AAAA;AApBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAuBA;AAAA;AApBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAiBA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1pBA;AAWA;AAGA;AACA;AACA;AACA;AAEA;AACA;AAKA;AAAA;AAeA;AATA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAGA;AAzCA;AAgDA;AACA;AAEA;AACA;AAAA;AAEA;AAOA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AAGA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAKA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAQA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAKA;AAAA;AAEA;AAAA;AACA;AACA;AAjoBA;AAooBA;AAIA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AASA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AArqBA;AAwqBA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AAEA;AAIA;AACA;AAGA;AACA;AAKA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAEA;AAIA;AACA;AAAA;AAKA;AAAA;AAGA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AAQA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAzzBA;AA4zBA;AAAA;AACA;AAIA;AACA;AAIA;AAAA;AACA;AAOA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAOA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAQA;AAEA;AAIA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAMA;AAAA;AAGA;AACA;AACA;AACA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAIA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAIA;AAIA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAIA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAIA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAIA;AAIA;AACA;AAAA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAIA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAQA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAMA;AACA;AACA;AAAA;AACA;AAGA;AASA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAKA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAIA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AACA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAQA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AAIA;AAIA;AAEA;AAAA;AAQA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AAYA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAEA;AAtkDA;AAAA;AADA;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AArCA;;;;;;;;;;;;;;;;ACAA;AAmBA;;;;;;;;;;;;;;;;ACjBA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAIA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChCA;AAEA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AAGA;AAAA;AA6FA;AANA;AACA;AAEA;AACA;AArFA;AAGA;AAwBA;AAaA;AAsCA;AAUA;AAAA;AACA;AAGA;AAAA;AACA;AAQA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AAEA;AAIA;AAIA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AAEA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAGA;AACA;AACA;AAGA;AAGA;AAGA;AAGA;AAEA;AACA;AAOA;AAIA;AAIA;AACA;AAIA;AAEA;AAGA;AAIA;AAGA;AACA;AAIA;AAIA;AAIA;AAEA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AAKA;AAAA;AACA;AAGA;AAKA;AAAA;AACA;AAGA;AAKA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AAIA;AACA;AACA;AAEA;AAKA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAaA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAKA;AACA;AACA;AAAA;AAIA;AACA;AAGA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AAIA;AACA;AACA;AAEA;AACA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AAGA;AAAA;AAEA;AAGA;AACA;AAAA;AACA;AAIA;AAAA;AACA;AAIA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAKA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAEA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AASA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AAAA;AAEA;AAGA;AACA;AAAA;AACA;AAGA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAKA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAKA;AAGA;AAEA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsBA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAMA;AAIA;AAIA;AAAA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AAIA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAEA;AAGA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAMA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAYA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AAIA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAEA;AAEA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAIA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AA72DA;AAAA;AADA;AAwFA;AACA;AACA;AAEA;AA3GA;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AAIA;AAAA;AAAA;AAiCA;AANA;AACA;AAGA;AA3BA;AACA;AAMA;AAUA;AAaA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAKA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AASA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAMA;AAKA;AAAA;AACA;AAGA;AAGA;AACA;AAEA;AAAA;AACA;AAIA;AAAA;AAGA;AAEA;AAAA;AAGA;AAGA;AAKA;AAMA;AAEA;AAEA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AAOA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAIA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AAIA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;ACpVA;AACA;AACA;AAGA;AAAA;AAeA;AAHA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAIA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAIA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;AC5KA;AACA;AACA;AAGA;AAAA;AAUA;AADA;AANA;AACA;AACA;AAEA;AAIA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAMA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrFA;AAGA;AAWA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AAHA;AAwKA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAiBA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAmDA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AA5mBA;AAAA;AACA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AAAA;AAhBA;AAAA;AAdA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA8BA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAiBA;AAAA;AAdA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAyBA;AAAA;AAtBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAWA;AAAA;AARA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAyBA;AAAA;AArBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAsBA;AAAA;AAlBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAWA;AAAA;AANA;AACA;AACA;AACA;AACA;AACA;AAcA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAuDA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA4FA;AAAA;AAbA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAiBA;AAAA;AAbA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAiBA;AAAA;AAbA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAgTA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxqBA;AAUA;AAEA;AACA;AACA;AAGA;AAAA;AAWA;AAPA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AA/BA;AAgCA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AAEA;AAGA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAOA;AAIA;AAIA;AAKA;AACA;AACA;AAAA;AAEA;AAOA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AA5GA;AA+GA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AArLA;AAwLA;AAKA;AAAA;AAEA;AACA;AACA;AAAA;AAGA;AAaA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAtNA;AAyNA;AAIA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAYA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAGA;AAEA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAKA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AAaA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AAEA;AAMA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAEA;AAAA;AAEA;AApTA;AAAA;AADA;AAKA;AACA;AACA;AACA;AACA;AACA;AA1BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AASA;AAEA;AACA;AACA;AACA;AACA;AACA;AAIA;AAAA;AAgEA;AANA;AACA;AAEA;AACA;AA7DA;AAIA;AAEA;AAgBA;AACA;AACA;AAWA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AAYA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AAQA;AAAA;AAEA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AA/KA;AAkLA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAIA;AAGA;AAAA;AAGA;AAIA;AAGA;AAAA;AAKA;AACA;AAGA;AAAA;AAGA;AACA;AACA;AACA;AAEA;AAGA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAIA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAEA;AAEA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAIA;AAKA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAGA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAEA;AAEA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAGA;AACA;AAIA;AAEA;AAEA;AACA;AAIA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAIA;AAIA;AAGA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAjrBA;AAorBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AAAA;AAEA;AAEA;AAAA;AACA;AAGA;AAKA;AAEA;AAGA;AAEA;AAEA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAGA;AAAA;AACA;AArxBA;AAwxBA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AAKA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAEA;AAEA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AASA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuBA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AAGA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AAEA;AAEA;AAAA;AACA;AAz/BA;AA4/BA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAtkCA;AAAA;AADA;AA2DA;AACA;AACA;AAEA;AAlFA;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AASA;AALA;AAMA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAOA;AAEA;AAAA;AACA;AACA;AACA;AAOA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AA7EA;;;;;;;;;;;;;;;;;;;;ACPA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoCA;AAEA;AACA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvDA;AAGA;AAEA;AAEA;AAEA;AASA;AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjBA;AAIA;AACA;AAEA;AAEA;AAAA;AACA;AAAA;AAIA;AAHA;AAIA;AAAA;AACA;AACA;AAAA;AAgCA;AAAA;AA9BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AA8BA;AAAA;AA3BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrFA;AACA;AACA;AACA;AACA;AACA;AAEA;AAGA;AAAA;AAQA;AAHA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AAEA;AAjEA;AAAA;AADA;AAMA;AACA;AAhBA;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAKA;AAGA;AAAA;AAWA;AALA;AAOA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AAEA;AACA;AAEA;AAEA;AAGA;AAGA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAnGA;AAoHA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAlIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACfA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAHA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1CA;AAEA;AAKA;AAGA;AAEA;AASA;AAEA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAUA;AAqCA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChFA;AAOA;AAAA;AACA;AAAA;AAIA;AAmCA;AAAA;AAlCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAgBA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClEA;AAGA;AACA;AACA;AAKA;AAAA;AAMA;AAJA;AACA;AACA;AAAA;AAGA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AAGA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAIA;AACA;AAGA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAxHA;AAAA;AADA;AAGA;AACA;AACA;AAdA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAAA;AACA;AAJA;AAAA;AADA;AAHA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAKA;AAAA;AAiBA;AANA;AACA;AACA;AAEA;AAXA;AACA;AAGA;AAAA;AAUA;AAGA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AAEA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAGA;AAEA;AAAA;AACA;AAGA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AAOA;AACA;AAAA;AAGA;AAIA;AACA;AAAA;AACA;AAEA;AAAA;AAEA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAEA;AAIA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAGA;AAEA;AACA;AASA;AACA;AAEA;AACA;AAKA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AAGA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AAEA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAIA;AAMA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAIA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AAEA;AAhaA;AAAA;AADA;AAYA;AACA;AACA;AACA;AA1BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACKA;AAGA;AAWA;AAAA;AACA;AAAA;AAIA;AAHA;AAIA;AAEA;AAAA;AAAA;AAoBA;AAAA;AAlBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAcA;AAAA;AAXA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAeA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAiBA;AAAA;AAbA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAsBA;AAAA;AAlBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA2CA;AAAA;AAxCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA2CA;AAAA;AAxCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAmBA;AAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzNA;AACA;AACA;AACA;AACA;AACA;AAIA;AAAA;AAQA;AALA;AACA;AAEA;AALA;AAAA;AAQA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AAAA;AACA;AAGA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAGA;AAEA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAKA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AAEA;AAIA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AAEA;AA5RA;AAAA;AADA;AAIA;AACA;AACA;AAdA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACCA;AAEA;AACA;AACA;AACA;AACA;AAKA;AAAA;AA+CA;AALA;AACA;AAEA;AA1CA;AAAA;AA2BA;AAGA;AAGA;AACA;AAAA;AAWA;AAGA;AAEA;AAEA;AACA;AAAA;AAIA;AAxEA;AA2EA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6CA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAIA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAKA;AAMA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AAEA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAOA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAKA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAsGA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAIA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAGA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAIA;AAGA;AACA;AACA;AACA;AAAA;AACA;AA/qBA;AAkrBA;AAEA;AAAA;AAEA;AA1qBA;AAAA;AADA;AA2CA;AACA;AACA;AAxDA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACKA;AAGA;AAoBA;AAAA;AACA;AAAA;AAIA;AAHA;AAIA;AAEA;AAEA;AAAA;AAAA;AAgGA;AAAA;AA9FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmDA;AAcA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAeA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAkBA;AAAA;AAfA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAuBA;AAAA;AAnBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAqBA;AAAA;AAlBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA2CA;AAAA;AAxCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA2CA;AAAA;AAxCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAeA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA8BA;AAAA;AA1BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAoCA;AAAA;AAjCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAqDA;AAAA;AAlDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAqBA;AAAA;AAlBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAyCA;AAAA;AAtCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAyCA;AAAA;AAtCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AASA;AAAA;AANA;AACA;AACA;AACA;AACA;AACA;AAeA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAeA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAiBA;AAAA;AAdA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7kBA;AACA;AACA;AACA;AACA;AACA;AAMA;AAAA;AAUA;AAPA;AACA;AACA;AACA;AAEA;AAPA;AAAA;AAUA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AAAA;AACA;AAKA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAGA;AAEA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AAGA;AAAA;AACA;AAGA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAKA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AAEA;AAIA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAIA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAIA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAIA;AACA;AAAA;AACA;AAEA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AAEA;AAtUA;AAAA;AADA;AAIA;AACA;AACA;AACA;AACA;AAlBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AAGA;AAIA;AAAA;AAQA;AAJA;AAEA;AAAA;AAGA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AAEA;AAtDA;AAAA;AADA;AAKA;AACA;AAfA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAAA;AAoFA;AALA;AACA;AAEA;AA/EA;AAAA;AAiEA;AAGA;AACA;AAIA;AAAA;AASA;AAGA;AAEA;AAEA;AACA;AAEA;AAEA;AACA;AACA;AAAA;AACA;AAKA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6CA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AAAA;AAcA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AAUA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AAMA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AAUA;AAAA;AAKA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAIA;AACA;AAGA;AACA;AAMA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAJA;AAMA;AACA;AAGA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAIA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWA;AACA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkFA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2JA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAeA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AAMA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAIA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAIA;AACA;AACA;AACA;AAEA;AAEA;AAIA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAIA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAn9BA;AAs9BA;AAEA;AAQA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AAIA;AAIA;AACA;AAEA;AAAA;AACA;AAGA;AAEA;AAIA;AAEA;AACA;AAAA;AACA;AAGA;AAIA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAIA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAIA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AASA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAOA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAKA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWA;AACA;AACA;AACA;AAAA;AACA;AAz0CA;AA40CA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AAEA;AAt2CA;AAAA;AADA;AAgFA;AACA;AACA;AA9FA;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAWA;AANA;AAOA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAEA;AAEA;AAEA;AAGA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAIA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAjHA;AAoHA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAEA;AAlHA;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAHA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrCA;AACA;AAEA;AAOA;AACA;AACA;AAEA;AAIA;AAOA;AACA;AAEA;AAcA;AAcA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClDA;AAOA;AAEA;AAAA;AAEA;AAAA;AAKA;AAHA;AAoBA;AACA;AAAA;AAAA;AAFA;AAAA;AAfA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAkBA;AAAA;AAbA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAYA;AAAA;AATA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtEA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAWA;AANA;AAEA;AACA;AACA;AAPA;AAUA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAIA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AAvEA;AAAA;AADA;AAMA;AACA;AAEA;AACA;AAjBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAEA;AACA;AACA;AACA;AAIA;AAAA;AAQA;AAJA;AAEA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAjDA;AAAA;AADA;AAKA;AACA;AAdA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAEA;AACA;AACA;AACA;AACA;AAIA;AAAA;AASA;AAHA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AAAA;AAEA;AArEA;AAAA;AADA;AAMA;AAEA;AAjBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACMA;AAGA;AAOA;AAIA;AAAA;AAEA;AAAA;AAIA;AAWA;AAAA;AAVA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAeA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AASA;AAAA;AANA;AACA;AACA;AACA;AACA;AACA;AAeA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAyBA;AAAA;AAtBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAeA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAWA;AAAA;AARA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAsBA;AAAA;AAnBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAKA;AACA;AAGA;AACA;;;;;;;;;;;;;;;;ACrIA;AACA;AACA;AAFA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACZA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAcA;AAJA;AAEA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AAEA;AACA;AAAA;AAEA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAEA;AAAA;AACA;AACA;AAGA;AAKA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAEA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AAEA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AAEA;AAEA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AAEA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AAEA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAEA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAGA;AAEA;AAAA;AAEA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AA7SA;AAAA;AADA;AAWA;AACA;AAnBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACKA;AAUA;AAAA;AAEA;AAAA;AAIA;AAUA;AAAA;AATA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAeA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAeA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAgBA;AAAA;AAbA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7EA;AAEA;AACA;AACA;AACA;AAGA;AAAA;AAaA;AAJA;AAEA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAKA;AACA;AAGA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBA;AACA;AAEA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwCA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwBA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuBA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6BA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAEA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AAnRA;AAAA;AADA;AAUA;AACA;AAlBA;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AASA;AALA;AAMA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AAEA;AACA;AAEA;AAEA;AAEA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AA/DA;AAkEA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AA3EA;;;;;;;;;;;;;;;;;;;;;;;ACRA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAHA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAYA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChBA;AAGA;AACA;AAGA;AAGA;AAAA;AAEA;AAAA;AAIA;AAHA;AAIA;AACA;AAAA;AAAA;AA+BA;AAAA;AA7BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAmBA;AAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAmBA;AAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAuBA;AAAA;AAnBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAqBA;AAAA;AAlBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAuBA;AAAA;AAnBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAqBA;AAAA;AAlBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AA4BA;AAAA;AAzBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA4BA;AAAA;AAzBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChPA;AAGA;AACA;AAGA;AAGA;AAAA;AAEA;AAAA;AAIA;AAHA;AAIA;AACA;AAAA;AAAA;AAoCA;AAAA;AAlCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAmBA;AAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAmBA;AAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAuBA;AAAA;AAnBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAqBA;AAAA;AAlBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAuBA;AAAA;AAnBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAqBA;AAAA;AAlBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AA4BA;AAAA;AAzBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA4BA;AAAA;AAzBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC3PA;AAEA;AACA;AACA;AACA;AAKA;AAAA;AAOA;AALA;AAEA;AACA;AAAA;AAGA;AAEA;AAAA;AACA;AAGA;AAEA;AAEA;AACA;AACA;AAIA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AAGA;AAIA;AAIA;AAIA;AAEA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AAEA;AA3HA;AAAA;AADA;AAGA;AACA;AAEA;AAfA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAAA;AAoBA;AALA;AAEA;AACA;AAfA;AAkBA;AAAA;AACA;AAGA;AAEA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAAA;AACA;AACA;AAIA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAGA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAGA;AACA;AAEA;AACA;AAGA;AACA;AAEA;AACA;AAEA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AAIA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAnYA;AAAA;AADA;AAgBA;AACA;AAEA;AA5BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACMA;AAGA;AACA;AAGA;AAGA;AAAA;AAEA;AAAA;AAIA;AAHA;AAIA;AACA;AAAA;AAAA;AAoCA;AAAA;AAlCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAmBA;AAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAmBA;AAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAuBA;AAAA;AAnBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAqBA;AAAA;AAlBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAuBA;AAAA;AAnBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAqBA;AAAA;AAlBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AA4BA;AAAA;AAzBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA4BA;AAAA;AAzBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;;;;;;;;;;;;;;;;;;;;;;AC3PA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAUA;AANA;AAOA;AAAA;AACA;AACA;AAIA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AAEA;AAGA;AAEA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAGA;AAAA;AACA;AACA;AACA;AAKA;AAAA;AACA;AACA;AACA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AAhHA;;;;;;;;;;;;;;;;;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAFA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnCA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AA0BA;AAIA;AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzDA;AAIA;AAAA;AAEA;AAEA;AACA;AAAA;AA4BA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AA/BA;AAAA;AA1BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAyCA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7EA;AAQA;AAEA;AACA;AACA;AACA;AAOA;AAAA;AA+BA;AAPA;AACA;AACA;AACA;AACA;AACA;AApBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAaA;AA9BA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AA2BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AAAA;AACA;AAGA;AAEA;AAEA;AAEA;AAEA;AACA;AAEA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAIA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AAIA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAIA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAGA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAAA;AAIA;AAAA;AACA;AA/UA;AAkVA;AACA;AACA;AACA;AAIA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AAEA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAGA;AAAA;AACA;AAneA;AAseA;AACA;AACA;AAAA;AAEA;AAIA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAAA;AAIA;AAAA;AACA;AAGA;AAEA;AAEA;AAAA;AAAA;AAAA;AAOA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AAAA;AACA;AACA;AAGA;AAEA;AAAA;AACA;AACA;AAGA;AAKA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AAGA;AAAA;AAEA;AA7kBA;AAAA;AADA;AAyBA;AACA;AACA;AACA;AACA;AACA;AAjDA;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AALA;AAAA;AAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACPA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAGA;AAAA;AAAA;AAiDA;AACA;AACA;AACA;AACA;AACA;AAlDA;AACA;AACA;AAUA;AACA;AACA;AAMA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAsBA;AAAA;AACA;AAEA;AAMA;AAIA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AAIA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAGA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAGA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAIA;AAEA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAIA;AAGA;AACA;AAEA;AACA;AAIA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AAAA;AAGA;AACA;AAEA;AAIA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AAKA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAIA;AAEA;AAEA;AACA;AAMA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAEA;AAOA;AAAA;AAEA;AAAA;AAGA;AAEA;AACA;AAAA;AAGA;AACA;AAIA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AAAA;AAEA;AAEA;AAAA;AAGA;AAEA;AAEA;AAEA;AACA;AAEA;AAEA;AAEA;AAEA;AACA;AAEA;AAEA;AAAA;AACA;AAEA;AAEA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAIA;AAAA;AACA;AAIA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAQA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAKA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAGA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAIA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AA9sBA;AAAA;AAAA;AAAA;AADA;AAVA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAEA;AACA;AACA;AACA;AAEA;AAGA;AAAA;AAkBA;AALA;AACA;AACA;AACA;AAZA;AACA;AACA;AAAA;AAaA;AAjBA;AAAA;AACA;AAmBA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAEA;AAEA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAGA;AAEA;AAEA;AAEA;AAEA;AAEA;AAGA;AACA;AAMA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAhOA;AAAA;AADA;AAcA;AACA;AACA;AACA;AA1BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACEA;AAEA;AAGA;AAAA;AAOA;AALA;AACA;AACA;AACA;AAAA;AAGA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAlBA;AAAA;AADA;AAGA;AACA;AACA;AACA;AAZA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAIA;AAAA;AAEA;AAEA;AAIA;AAHA;AAiCA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAhCA;AAAA;AA3BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA0CA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClFA;AAQA;AAEA;AACA;AACA;AACA;AAOA;AAAA;AAgCA;AARA;AACA;AACA;AACA;AAEA;AACA;AArBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAcA;AA/BA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AA4BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AAAA;AACA;AAGA;AAEA;AAEA;AAEA;AAEA;AACA;AAEA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAIA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AAIA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAIA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAGA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAAA;AAIA;AAAA;AACA;AA/UA;AAkVA;AACA;AACA;AACA;AAIA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AAEA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAGA;AAAA;AACA;AAneA;AAseA;AACA;AACA;AAAA;AAEA;AAIA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAAA;AAIA;AAAA;AACA;AAGA;AAEA;AAEA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AAAA;AACA;AACA;AAGA;AAEA;AAAA;AACA;AACA;AAGA;AAKA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AAGA;AAAA;AAEA;AAzkBA;AAAA;AADA;AAyBA;AACA;AACA;AACA;AACA;AAEA;AAlDA;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AALA;AAAA;AAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACPA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAGA;AAAA;AAAA;AAiDA;AACA;AACA;AACA;AACA;AACA;AAlDA;AACA;AACA;AAUA;AACA;AACA;AAMA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAsBA;AAAA;AACA;AAEA;AAMA;AAIA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AAIA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAGA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAGA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAIA;AAEA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAIA;AAGA;AACA;AAEA;AACA;AAIA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AAGA;AACA;AAEA;AAIA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AAKA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAIA;AAEA;AAEA;AACA;AAMA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAEA;AAQA;AAAA;AAEA;AAAA;AAGA;AAEA;AACA;AAAA;AAGA;AACA;AAIA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AAAA;AAEA;AAEA;AAAA;AAGA;AAEA;AAEA;AAEA;AACA;AAEA;AAEA;AAEA;AAEA;AACA;AAEA;AAEA;AAAA;AACA;AAEA;AAEA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAIA;AAAA;AACA;AAIA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAQA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAKA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAGA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAIA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAztBA;AAAA;AAAA;AAAA;AADA;AAVA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACEA;AAEA;AAGA;AAAA;AAQA;AANA;AACA;AACA;AAEA;AAAA;AAGA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAnBA;AAAA;AADA;AAGA;AACA;AACA;AACA;AAZA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAEA;AACA;AACA;AACA;AAEA;AAGA;AAAA;AAmBA;AANA;AACA;AACA;AAEA;AAbA;AACA;AACA;AAAA;AAcA;AAlBA;AAAA;AACA;AAoBA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAEA;AAEA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAOA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAGA;AAEA;AAEA;AAEA;AAEA;AAEA;AAGA;AACA;AAMA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAtOA;AAAA;AADA;AAcA;AACA;AACA;AACA;AA1BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AAEA;AAGA;AACA;AACA;AAEA;AAAA;AASA;AALA;AAMA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AAGA;AAGA;AAEA;AAGA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAGA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AA3GA;AA6GA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AA7GA;AAAA;AAXA;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAHA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzCA;AACA;AACA;AACA;AAIA;AAEA;AACA;AACA;AAIA;AAEA;AACA;AACA;AACA;AAmBA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnCA;AAGA;AACA;AACA;AAQA;AAAA;AACA;AAAA;AAIA;AAHA;AAIA;AACA;AACA;AAAA;AAAA;AAUA;AAAA;AARA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA6EA;AAAA;AA1EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA0BA;AAAA;AAvBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAkBA;AAAA;AAfA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA0BA;AAAA;AAvBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAyBA;AAAA;AAtBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAmBA;AAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA2FA;AAAA;AAxFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA2FA;AAAA;AAxFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrZA;AAEA;AACA;AACA;AAIA;AAAA;AAYA;AARA;AACA;AACA;AACA;AAEA;AACA;AAIA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AApCA;AAAA;AADA;AAKA;AACA;AACA;AACA;AACA;AAEA;AAlBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACMA;AAGA;AACA;AACA;AAOA;AAAA;AACA;AAAA;AAIA;AAHA;AAIA;AACA;AACA;AAAA;AAAA;AAuFA;AAAA;AArFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA0BA;AAAA;AAvBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAkBA;AAAA;AAfA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA0BA;AAAA;AAvBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAyBA;AAAA;AAtBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAmBA;AAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA2FA;AAAA;AAxFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA2FA;AAAA;AAxFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/YA;AAEA;AACA;AACA;AACA;AACA;AAIA;AAAA;AAAA;AAQA;AAJA;AACA;AACA;AAIA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAIA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AAIA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AA/EA;AAkFA;AAEA;AACA;AACA;AAGA;AAIA;AAIA;AAEA;AACA;AAEA;AAIA;AAEA;AAIA;AAEA;AACA;AACA;AAGA;AAIA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAIA;AAGA;AAEA;AAIA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAKA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAIA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAMA;AAMA;AAGA;AACA;AAKA;AACA;AAAA;AACA;AAGA;AAGA;AAAA;AACA;AAGA;AAKA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAEA;AAAA;AACA;AACA;AASA;AAAA;AAWA;AACA;AAAA;AAEA;AAAA;AAMA;AAEA;AApTA;AAAA;AADA;AAKA;AACA;AACA;AAtBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AAEA;AACA;AAIA;AAAA;AAMA;AAJA;AACA;AACA;AAAA;AAGA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AA7DA;AAAA;AADA;AAGA;AACA;AACA;AAZA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAWA;AAEA;AACA;AACA;AACA;AACA;AACA;AAMA;AAAA;AAyFA;AARA;AACA;AACA;AACA;AAEA;AACA;AAjFA;AAAA;AAUA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AASA;AACA;AACA;AA0BA;AAEA;AAUA;AAaA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAIA;AAIA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAEA;AAEA;AAAA;AACA;AAUA;AAIA;AACA;AAKA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAEA;AAQA;AAIA;AAEA;AAEA;AAEA;AAEA;AAEA;AAGA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAIA;AAIA;AAIA;AAEA;AASA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAzTA;AA4TA;AAIA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAIA;AAMA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AAMA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAWA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAMA;AAAA;AACA;AAGA;AACA;AAEA;AAEA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA9mBA;AAinBA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAMA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAhuBA;AAmuBA;AACA;AACA;AAAA;AAGA;AAIA;AAKA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AAEA;AACA;AAAA;AACA;AAEA;AAIA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAMA;AAIA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAKA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAUA;AACA;AACA;AACA;AAMA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAIA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AAMA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAnmCA;AAsmCA;AACA;AAAA;AAGA;AACA;AAEA;AAAA;AAIA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AAIA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AAAA;AAKA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAMA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AA3rCA;AAAA;AADA;AAkFA;AACA;AACA;AACA;AACA;AAEA;AA/GA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACMA;AAGA;AACA;AACA;AAOA;AAAA;AACA;AAAA;AAIA;AAHA;AAIA;AACA;AACA;AAAA;AAAA;AAoFA;AAAA;AAlFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA0BA;AAAA;AAvBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAkBA;AAAA;AAfA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA0BA;AAAA;AAvBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAyBA;AAAA;AAtBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAmBA;AAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA2FA;AAAA;AAxFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA2FA;AAAA;AAxFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClZA;AACA;AACA;AAEA;AAGA;AACA;AAEA;AAAA;AAWA;AALA;AAMA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAGA;AAEA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AAOA;AACA;AACA;AAGA;AAKA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAEA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA7HA;AA4IA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAlJA;AAqJA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAGA;AAAA;AAEA;AAGA;AAAA;AACA;AACA;AAEA;AApKA;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAFA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnCA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA4BA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtDA;AAIA;AAQA;AAAA;AAEA;AAEA;AAIA;AAHA;AAIA;AACA;AAAA;AAAA;AAgKA;AAAA;AA9JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAkBA;AAAA;AAfA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAmBA;AAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAmBA;AAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAmBA;AAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAkBA;AAAA;AAfA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAkBA;AAAA;AAfA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAkBA;AAAA;AAfA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA4BA;AAAA;AAzBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA6BA;AAAA;AAzBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAiCA;AAAA;AA7BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAgCA;AAAA;AA7BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA+BA;AAAA;AA5BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAmCA;AAAA;AAhCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAmBA;AAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA6CA;AAAA;AAzCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtiBA;AAEA;AAYA;AAEA;AACA;AACA;AACA;AAEA;AAGA;AAAA;AAiBA;AANA;AACA;AACA;AACA;AACA;AAZA;AAEA;AACA;AAEA;AAUA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AACA;AAIA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AAWA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAEA;AAEA;AACA;AAAA;AAGA;AAEA;AAAA;AACA;AAGA;AAKA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AA1MA;AA6MA;AACA;AACA;AACA;AAIA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAIA;AAAA;AAEA;AACA;AAAA;AACA;AAgCA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAhTA;AAmTA;AACA;AACA;AACA;AAAA;AAEA;AAIA;AAAA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAIA;AAAA;AAGA;AAEA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAMA;AAAA;AAGA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAOA;AAEA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAIA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAIA;AAIA;AAEA;AAGA;AAGA;AAEA;AAGA;AAGA;AAEA;AAGA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAKA;AAGA;AApjBA;AAAA;AADA;AAYA;AACA;AACA;AACA;AACA;AA9CA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACOA;AAEA;AACA;AAaA;AAEA;AACA;AACA;AACA;AAIA;AAAA;AAgCA;AANA;AACA;AACA;AACA;AACA;AATA;AACA;AACA;AAUA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAIA;AACA;AACA;AACA;AAAA;AAEA;AAIA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAGA;AAKA;AAAA;AAEA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAEA;AAIA;AAAA;AAGA;AAEA;AACA;AAEA;AAOA;AACA;AAAA;AAGA;AAAA;AAGA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAKA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AAEA;AAIA;AAAA;AACA;AACA;AAMA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAMA;AAAA;AAEA;AAAA;AAEA;AAGA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAcA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAWA;AACA;AACA;AACA;AAIA;AACA;AAEA;AACA;AAEA;AAEA;AAGA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AACA;AAGA;AACA;AACA;AAIA;AACA;AACA;AAIA;AACA;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAIA;AAAA;AACA;AAEA;AACA;AACA;AAGA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AAAA;AAEA;AAEA;AAEA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AAKA;AACA;AAEA;AAEA;AAIA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AAAA;AAKA;AACA;AACA;AACA;AASA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AA5lBA;AA+lBA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AAIA;AAIA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAMA;AAEA;AACA;AAIA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBA;AACA;AACA;AACA;AAMA;AAAA;AACA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAcA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAKA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAMA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAIA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAKA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AAIA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAIA;AAMA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AAGA;AAAA;AAGA;AAAA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AA18BA;AAAA;AADA;AA2BA;AACA;AACA;AACA;AACA;AA9DA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AAWA;AAUA;AAEA;AACA;AACA;AACA;AACA;AAMA;AAAA;AAiFA;AANA;AACA;AACA;AACA;AACA;AA1EA;AAAA;AAqBA;AAUA;AAKA;AAKA;AAAA;AAuBA;AAEA;AACA;AAUA;AAEA;AAEA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAEA;AACA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAIA;AAEA;AAEA;AAGA;AAIA;AAEA;AAEA;AAEA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AAEA;AAAA;AAGA;AAEA;AACA;AAAA;AACA;AAEA;AAEA;AAIA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AAGA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAIA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAGA;AAEA;AACA;AACA;AAKA;AACA;AACA;AAEA;AACA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AACA;AACA;AAEA;AAEA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AAOA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AASA;AAKA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAOA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAIA;AAAA;AAEA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AA5oBA;AA+oBA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AArpBA;AAupBA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AA3qBA;AA8qBA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAGA;AACA;AAMA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AAAA;AAEA;AAEA;AAAA;AAGA;AAEA;AAAA;AAGA;AAEA;AAAA;AACA;AACA;AAAA;AAKA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAGA;AAGA;AAAA;AAGA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAEA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAGA;AAEA;AAEA;AAEA;AACA;AAEA;AAAA;AACA;AAIA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAIA;AACA;AACA;AAGA;AACA;AAAA;AAIA;AAKA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAMA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AAAA;AAKA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAAA;AAEA;AAGA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAKA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AASA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAIA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAMA;AAKA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAWA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAIA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAMA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAIA;AAKA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AAAA;AAEA;AAEA;AAAA;AAIA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AAIA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AAIA;AACA;AACA;AACA;AAMA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAKA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAIA;AACA;AACA;AACA;AAIA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AAr4CA;AAAA;AADA;AA4EA;AACA;AACA;AACA;AACA;AAjHA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACKA;AAIA;AAEA;AASA;AAAA;AAEA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AAgMA;AAAA;AA9LA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAiBA;AAAA;AAdA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAoBA;AAAA;AAjBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA0BA;AAAA;AAvBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA0BA;AAAA;AAvBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAoBA;AAAA;AAjBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAoBA;AAAA;AAjBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAkBA;AAAA;AAfA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAkBA;AAAA;AAfA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAkBA;AAAA;AAfA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA4BA;AAAA;AAzBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA4BA;AAAA;AAzBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA4CA;AAAA;AAzCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA4CA;AAAA;AAzCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAmBA;AAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAmBA;AAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAmBA;AAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA2BA;AAAA;AAvBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAWA;AAAA;AAPA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjnBA;AAEA;AAYA;AAEA;AACA;AACA;AACA;AAEA;AAGA;AAAA;AAiBA;AANA;AACA;AACA;AACA;AACA;AAZA;AAEA;AACA;AAEA;AAUA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AACA;AAIA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AAWA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAEA;AAEA;AACA;AAAA;AAGA;AAEA;AAAA;AACA;AAGA;AAKA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AA1MA;AA6MA;AACA;AACA;AACA;AAIA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAIA;AAAA;AAEA;AACA;AAAA;AACA;AAgCA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAhTA;AAmTA;AACA;AACA;AACA;AAAA;AAEA;AAIA;AAAA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAIA;AAAA;AAGA;AAEA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAMA;AAAA;AAGA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAMA;AAEA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAIA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAIA;AAIA;AAEA;AAGA;AAGA;AAEA;AAGA;AAGA;AAEA;AAGA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAKA;AAGA;AArjBA;AAAA;AADA;AAYA;AACA;AACA;AACA;AACA;AA9CA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACCA;AACA;AACA;AAaA;AAEA;AACA;AACA;AACA;AAKA;AAAA;AAoCA;AAPA;AACA;AACA;AACA;AACA;AACA;AAbA;AACA;AAEA;AAEA;AAWA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAIA;AACA;AACA;AACA;AAAA;AAEA;AAIA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAGA;AAKA;AAAA;AAEA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAEA;AAIA;AAAA;AAGA;AAEA;AACA;AAEA;AAOA;AACA;AAAA;AAGA;AAAA;AAGA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAKA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AAEA;AAKA;AAAA;AACA;AACA;AAMA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAMA;AAAA;AAEA;AAAA;AAEA;AAGA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAcA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAUA;AACA;AACA;AACA;AAEA;AAEA;AAGA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AACA;AAGA;AACA;AACA;AAIA;AACA;AACA;AAIA;AACA;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AAIA;AAAA;AACA;AAEA;AACA;AACA;AAGA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AAAA;AAEA;AAEA;AAEA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAIA;AACA;AAEA;AAIA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AAAA;AAKA;AACA;AACA;AACA;AASA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AA5mBA;AA+mBA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AAIA;AAIA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAMA;AAEA;AACA;AAIA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBA;AACA;AACA;AACA;AAMA;AAAA;AACA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAcA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAKA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAMA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAIA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAKA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AAIA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAIA;AAMA;AAAA;AACA;AAEA;AAKA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AAGA;AAAA;AAGA;AAAA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AAEA;AAOA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AAEA;AAOA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAEA;AAKA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAEA;AAlmCA;AAAA;AADA;AA8BA;AACA;AACA;AACA;AACA;AACA;AA5DA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AAGA;AAEA;AACA;AAIA;AAAA;AAXA;AAqBA;AAPA;AACA;AACA;AACA;AACA;AACA;AAPA;AAWA;AAEA;AAAA;AAIA;AACA;AACA;AAEA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBA;AACA;AAAA;AACA;AA7EA;AAgFA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAzFA;AAAA;AADA;AAIA;AACA;AACA;AACA;AACA;AACA;AAnBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AAWA;AAEA;AACA;AACA;AACA;AACA;AACA;AAMA;AAAA;AA2EA;AANA;AACA;AACA;AACA;AACA;AApEA;AAAA;AAoBA;AAUA;AAWA;AAKA;AAAA;AAYA;AACA;AAEA;AAUA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAEA;AACA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAIA;AAEA;AAEA;AAGA;AAIA;AAEA;AAEA;AAEA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AAEA;AAAA;AAGA;AAEA;AACA;AAAA;AACA;AAEA;AAEA;AAIA;AAEA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AAGA;AAAA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAIA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAGA;AAEA;AACA;AACA;AAKA;AACA;AACA;AAEA;AACA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AACA;AACA;AAEA;AAEA;AAEA;AAAA;AAEA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AAOA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AASA;AAKA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAOA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAIA;AAAA;AAEA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AA9pBA;AAiqBA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAvqBA;AAyqBA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AA7rBA;AAgsBA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAGA;AACA;AAMA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AA7xBA;AAgyBA;AAEA;AAQA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAGA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAKA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AAMA;AAGA;AAIA;AAAA;AAGA;AACA;AAKA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AAEA;AAEA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAGA;AAEA;AAEA;AAEA;AACA;AAEA;AAAA;AACA;AAIA;AACA;AAAA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAIA;AACA;AACA;AAGA;AACA;AAAA;AAIA;AAKA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAMA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AAAA;AAKA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAAA;AAEA;AACA;AACA;AAGA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAKA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AASA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAIA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAMA;AAKA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAWA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAIA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAMA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAIA;AAKA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AAAA;AAEA;AAEA;AAAA;AAIA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AAIA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AAIA;AACA;AACA;AACA;AAMA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAKA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAIA;AACA;AACA;AACA;AAIA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AAniDA;AAAA;AADA;AAsEA;AACA;AACA;AACA;AACA;AAlGA;;;;;;;;;;;;;;;;;ACEA;AAeA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;ACvDA;AAGA;AAGA;AACA;AACA;AAUA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;;ACzBA;AA6BA;AACA;AACA;AAAA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;ACpCA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAQA;AAPA;AAAA;AAQA;AAGA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAxCA;AA2CA;AAAA;AACA;AA5CA;AA+CA;AACA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnDA;AACA;AACA;AACA;AAIA;AAAA;AAIA;AADA;AAAA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAvBA;AAwBA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AAEA;AAlDA;AAAA;AADA;AAIA;AAVA;;;;;;;;;;;;;;;;;ACAA;AAEA;AAAA;AAEA;AADA;AAAA;AAGA;AACA;AAEA;AAGA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzBA;AACA;AACA;AACA;AAIA;AAAA;AAEA;AAKA;AACA;AAIA;AAGA;AAKA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAEA;AAAA;AAGA;AACA;AACA;AAEA;AAAA;AAGA;AAEA;AAAA;AAGA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AACA;AAEA;AAGA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAKA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAMA;AACA;AAIA;AAAA;AAIA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAtKA;AA+KA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AAEA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAvRA;AA0RA;AAAA;AACA;AAEA;AAEA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAzTA;AAAA;AADA;AANA;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAEA;AACA;AACA;AACA;AAKA;AACA;;;;;;;;;;;;;;;;;;ACXA;AACA;AAEA;AAAA;AAAA;AACA;AACA;AAAA;AAKA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;AC5EA;AACA;AACA;AAEA;AACA;AACA;AACA;AAGA;AAAA;AAAA;AAWA;AATA;AAEA;AACA;AACA;AACA;AA2JA;AA5KA;AA6KA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAOA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAhMA;AACA;AAAA;AAWA;AAAA;AACA;AAGA;AASA;AACA;AACA;AACA;AACA;AAGA;AACA;AAIA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAQA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAxGA;AA2GA;AAAA;AACA;AACA;AAAA;AAEA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAIA;AACA;AACA;AACA;AAOA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AAAA;AACA;AA+CA;AACA;AAGA;AACA;AAAA;AAGA;;;;;;;;;;;;;;;;;AClOA;AAEA;AAAA;AACA;AACA;AAiCA;AAAA;AAAA;AA5BA;AACA;AACA;AACA;AAGA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAKA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;;AC3CA;AAmBA;AAAA;AAKA;AACA;AAAA;AACA;AAGA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAIA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAKA;AACA;AACA;AACA;AAYA;AAGA;;;;;;;;;;;;;;;;;;;AC/FA;AACA;AACA;AAEA;AAAA;AAEA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpCA;AACA;AACA;AACA;AAEA;AAEA;AAGA;AAAA;AAiBA;AAdA;AACA;AASA;AAKA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAIA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AAEA;AACA;AAIA;AACA;AACA;AACA;AAEA;AACA;AAIA;AACA;AACA;AACA;AACA;AAEA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AAvPA;AAAA;AADA;AATA;;;;;;;;;;;;;;;;;ACAA;AAEA;AAAA;AAIA;AACA;AAEA;AA2CA;AAAA;AAAA;AAEA;AAAA;AAAA;AAxCA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AA1BA;AAAA;AACA;AA4BA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AAGA;AAAA;AACA;AAQA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;;;ACtEA;AACA;AAoBA;AAAA;AAEA;AAAA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AAEA;AAIA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAKA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAEA;AAnGA;AAAA;AArBA;;;;;;;;;;;;;;;;;;ACAA;AAEA;AAmBA;AAAA;AAIA;AAAA;AAGA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AAIA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AAAA;AAKA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAMA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AAIA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AAIA;AAAA;AAEA;AA3GA;AAAA;AArBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AASA;AACA;AACA;AAQA;AAAA;AAUA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAhBA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AArCA;AAqDA;AACA;AAAA;AAEA;AAIA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAIA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAKA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAxGA;AA2GA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAIA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAjJA;AAqJA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AA7JA;AA8JA;AAAA;AAAA;AA9JA;AA+JA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAGA;AAEA;AAAA;AACA;AAAA;AAIA;AAAA;AACA;AAAA;AAKA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AArMA;AAwMA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AArPA;AAwPA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA/PA;AAyQA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AA5RA;AA6RA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AA/SA;AAAA;AA7BA;AA+UA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;;;;;;;;;;;;;;;;AC7VA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAUA;AAAA;AAqBA;AAPA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AA9IA;AAmJA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AAAA;AAKA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAIA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAIA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAAA;AApcA;AAwcA;AACA;AACA;AAAA;AAEA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAKA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAKA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAIA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;AC3qBA;AACA;AASA;AACA;AAeA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAGA;AAAA;AACA;AAAA;AAjDA;AAqDA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAIA;AACA;AAAA;AAEA;AACA;AAIA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AAGA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;AClJA;AACA;AAEA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AA4BA;AAAA;AACA;AAEA;AAAA;AAAA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAAA;AAIA;AAAA;AACA;AAAA;AAIA;AACA;AAIA;AACA;AAEA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAIA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAvJA;AAmKA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AA9LA;AAiMA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAtMA;AAyMA;AACA;AAAA;AAGA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAIA;AAEA;AACA;AAAA;AAIA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAGA;AAzPA;AA0PA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AACA;AAGA;AA/QA;AAgRA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;AC7QA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAIA;AAQA;AAUA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAIA;AACA;AAAA;AAEA;AACA;AAGA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAIA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AAEA;AAAA;AAEA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;;;;;;AC7IA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAwBA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA7HA;AAgIA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AAEA;AAEA;AAGA;AACA;AAAA;AACA;AAOA;AACA;AAGA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AACA;AAEA;AACA;AAQA;AACA;AAAA;AACA;AAEA;AACA;AAOA;AACA;AAAA;AACA;AAEA;AACA;AAGA;AACA;AAAA;AACA;AAEA;AACA;AAGA;AACA;AAAA;AACA;AAEA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAIA;;;;;;;;;;;;;;;;AChYA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AAAA;AACA;AAGA;AAAA;AAAA;AACA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAUA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0FA;AApFA;AAAA;AAAA;AAAA;AAAA;AAmBA;AAAA;AAAA;AAAA;AAKA;AAAA;AAAA;AAAA;AAyCA;AAAA;AAAA;AAAA;AAAA;AAoBA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAxHA;AA+HA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AAGA;AACA;AAKA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AASA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAUA;AACA;AACA;AAEA;AACA;AAKA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AAEA;AAAA;AACA;AAGA;AAEA;AAEA;AAAA;AAGA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AACA;AAIA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AAEA;AAKA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AA1VA;AAmWA;AAEA;AAAA;AAAA;AAMA;AAAA;AAIA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAAA;AAMA;AAAA;AAIA;AAAA;AACA;AACA;AAEA;AAIA;AACA;AAAA;AAEA;AAEA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAIA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2CA;AACA;AACA;AAGA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AAAA;AAGA;AAOA;AAAA;AACA;AAGA;AACA;AAAA;AAIA;AACA;AAEA;AAEA;AACA;AAAA;AAGA;AAGA;AAAA;AAGA;AAAA;AAGA;AACA;AAAA;AAIA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAIA;AAAA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AA1hBA;AA8hBA;AACA;AAAA;AAGA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAGA;AAGA;AAGA;AAEA;AAEA;AACA;AAAA;AAIA;AACA;AAAA;AACA;AACA;AAAA;AAKA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAIA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AACA;AAAA;AAEA;AAKA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAKA;AACA;AAAA;AAIA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAEA;AAEA;AAAA;AAGA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAEA;AAGA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AASA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAEA;AAEA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AAEA;AAEA;AACA;AACA;AAIA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAEA;AAEA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAIA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AACA;AAAA;AAEA;AAKA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA3iCA;AAojCA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AAGA;AAEA;AAEA;AACA;AAEA;AACA;AAhlCA;AAmlCA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AAEA;AAAA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AAGA;AAEA;AAEA;AACA;AAKA;AACA;AAAA;AAKA;AAAA;AACA;AAEA;AAlpCA;AAAA;AAFA;AACA;AA2FA;AA5GA;;;;;;;;;;;;;;;;;;;;ACAA;AAGA;AACA;AACA;AAIA;AAAA;AACA;AACA;AAEA;AAAA;AAGA;AAOA;AAAA;AACA;AAxBA;AAmCA;AAGA;AAGA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAEA;AACA;AAEA;AAAA;AACA;AAEA;AAEA;AAIA;AAEA;AAEA;AAEA;AAAA;AAGA;AAGA;AAEA;AAAA;AAGA;AAEA;AAEA;AAEA;AAEA;AAGA;AAAA;AACA;AAEA;AAEA;AAEA;AAEA;AAAA;AAGA;AAEA;AAAA;AAGA;AAEA;AAEA;AAEA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AAAA;AAKA;AAAA;AACA;AAAA;AAGA;AAEA;AAAA;AAGA;AAEA;AAAA;AAGA;AAEA;AAIA;AAAA;AACA;AAAA;AAGA;AAEA;AAAA;AAGA;AAEA;AAAA;AAGA;AAEA;AAAA;AAGA;AAGA;AAAA;AAGA;AAEA;AAAA;AAGA;AAEA;AAEA;AAEA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;ACpPA;AAEA;AAAA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;;;;;;;;;;;;;;;;;ACxBA;AAKA;AAAA;AAAA;AAKA;AAJA;AAAA;AAiBA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAQA;AACA;AAEA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AAIA;;;;;;;;;;;;;;;;;;;ACnEA;AAGA;AAEA;AAGA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAOA;AAAA;AACA;AAxBA;AAmCA;AAGA;AAGA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAEA;AACA;AAEA;AAAA;AACA;AAEA;AAEA;AAIA;AACA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAAA;AAGA;AAGA;AAAA;AACA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAAA;AAGA;AAEA;AAAA;AAGA;AAEA;AAEA;AAEA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AAAA;AAGA;AAEA;AAAA;AAGA;AAEA;AAAA;AAGA;AAEA;AAAA;AAGA;AAEA;AAIA;AAAA;AACA;AAAA;AAGA;AAEA;AAAA;AAGA;AAEA;AAAA;AAGA;AAEA;AAAA;AAGA;AAEA;AAAA;AAGA;AAEA;AAAA;AAGA;AAEA;AAEA;AAEA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvPA;AAKA;AAGA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAOA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAIA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAIA;AAAA;AACA;AAIA;AAAA;AACA;AAIA;AAAA;AACA;AAIA;AAAA;AACA;AAIA;AAAA;AACA;AAIA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAAA;AAIA;AACA;AAEA;AAIA;AAAA;AAIA;AAGA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AAIA;AAAA;AACA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AA/KA;AAmLA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAIA;AAAA;AACA;AAGA;AAEA;AAEA;AAAA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAIA;AAAA;AACA;AAIA;AAAA;AACA;AAIA;AAAA;AACA;AAIA;AAAA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAKA;AAAA;AACA;AAAA;AAKA;AAAA;AACA;AAGA;AAEA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAIA;AACA;AACA;AAAA;AACA;AACA;AAIA;AAAA;AAEA;AAlSA;AAAA;AADA;AAZA;;;;;;;;;;;;;;;;;ACAA;AAEA;AAAA;AAIA;AACA;AACA;AAEA;AACA;AACA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AAGA;AAAA;AACA;AAAA;AAIA;AAAA;AACA;AAAA;AAIA;AAAA;AACA;AAAA;AAIA;AAAA;AACA;AAAA;AAIA;AAAA;AACA;AAAA;AAIA;AAAA;AACA;AAAA;AAIA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;ACxKA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAGA;AAGA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAIA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAEA;;;;;;;;;;;;;;;;AC5DA;AAAA;AAMA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAGA;AAAA;AACA;AAEA;AAEA;AAEA;AAEA;AAGA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AAgBA;AAAA;AAIA;AAEA;AAEA;AAAA;AACA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvGA;AACA;AACA;AACA;AACA;AAQA;AAAA;AAOA;AANA;AAGA;AACA;AAGA;AACA;AAAA;AACA;AAAA;AAAA;AAKA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAlCA;AA0CA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAIA;AAAA;AACA;AAEA;AAEA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAIA;AAAA;AACA;AAEA;AAAA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAIA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AAAA;AAKA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AACA;AAAA;AACA;AAEA;AA5JA;AAAA;AAFA;AACA;AAQA;AAnBA;;;;;;;;;;;;;;;;;ACAA;AAGA;AAAA;AAIA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAEA;;;;;;;;;;;;;;;;ACjBA;AAAA;AAqBA;AACA;AAWA;AACA;AACA;AAIA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAlDA;AAwDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;;;ACjGA;AAGA;AACA;AAIA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAEA;AAGA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AAEA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAKA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AAEA;AAGA;AAAA;AACA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAIA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAIA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AAEA;;;;;;;;;;;;;;;;;;ACxXA;AAGA;AASA;AAAA;AAWA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAjDA;AAoDA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAjEA;AAoEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AA/EA;AAkFA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAOA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAtJA;AA6JA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AAAA;AAEA;AACA;AAGA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAOA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAUA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AAIA;AAOA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAvQA;AA0QA;AAKA;AAAA;AACA;AAOA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAOA;AAAA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1SA;AACA;AACA;AACA;AACA;AACA;AAKA;AAAA;AAGA;AAAA;AACA;AAEA;AAWA;AAGA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AAIA;AACA;AACA;AACA;AAiBA;AAAA;AAAA;AAAA;AAAA;AACA;AAIA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAIA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAKA;AACA;AAAA;AAGA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AAAA;AACA;AAAA;AAAA;AAAA;AAQA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AAAA;AACA;AAGA;AAAA;AACA;AAOA;AASA;AAAA;AAEA;AAAA;AACA;AAAA;AAIA;AAAA;AACA;AAAA;AAIA;AACA;AAAA;AAEA;AAIA;AACA;AAAA;AAEA;AAAA;AACA;AAzQA;AA4QA;AACA;AACA;AACA;AAIA;AACA;AAGA;AACA;AAAA;AAEA;AAKA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AA1TA;AA6TA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAlVA;AAsVA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAIA;AACA;AAKA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAKA;AACA;AACA;AACA;AACA;AAAA;AAKA;AAAA;AAEA;AAcA;AAAA;AACA;AAIA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAIA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAIA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AApgBA;AA6gBA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAEA;AAEA;AACA;AACA;AAIA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AACA;AAAA;AAKA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAGA;AAAA;AAEA;AAAA;AACA;AAtlBA;AAylBA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAKA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAEA;AAEA;AAOA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAGA;AAAA;AACA;AAMA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAKA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AAKA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AAGA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAIA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAIA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAKA;AACA;AAAA;AAKA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AAOA;AAAA;AACA;AAAA;AAIA;AAAA;AACA;AAAA;AA94BA;AAk5BA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAIA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAMA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AAMA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AAAA;AAEA;AAAA;AAhiCA;AAiCA;AAjCA;AAmCA;AAnCA;AAAA;AAAA;AAuCA;AAAA;AAAA;AAvCA;AAAA;AAAA;AAFA;AACA;AATA;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAKA;AAIA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AAAA;AAKA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAIA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAKA;AACA;AACA;AAKA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAIA;AAGA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AA5HA;AA8HA;AAGA;AACA;AAAA;AAIA;AAGA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClJA;AACA;AACA;AAEA;AAIA;AAAA;AACA;AAQA;AAAA;AAEA;AANA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAYA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAMA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAQA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAIA;AAAA;AACA;AAEA;AAjIA;AAAA;AAFA;AACA;AAPA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACCA;AAKA;AACA;AAIA;AAAA;AACA;AACA;AA+CA;AAIA;AAAA;AAOA;AAvDA;AAAA;AACA;AAGA;AAAA;AACA;AAKA;AAAA;AAAA;AACA;AA3BA;AA8BA;AACA;AACA;AAEA;AACA;AAEA;AAIA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAIA;AAAA;AACA;AAGA;AAAA;AACA;AAcA;AAEA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAMA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAGA;AAzHA;AAAA;AAFA;AACA;AAVA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AA4BA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBA;AAfA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAUA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAIA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AA1PA;AAAA;AAFA;AACA;AAoBA;AAlDA;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AAEA;AAAA;AAHA;AAOA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxCA;AACA;AACA;AACA;AACA;AAOA;AAGA;AACA;AAEA;AAyCA;AAAA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AAEA;AACA;AAGA;AAIA;AACA;AAycA;AAAA;AAAA;AAAA;AAAA;AAxhBA;AAyhBA;AACA;AAAA;AACA;AAzbA;AAAA;AACA;AAjBA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAQA;AAtGA;AAuGA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AA9LA;AAuMA;AACA;AAMA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAMA;AACA;AAEA;AAKA;AAGA;AAAA;AACA;AACA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAIA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAnQA;AAsQA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA9QA;AAiRA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AApSA;AAuSA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAzYA;AA4YA;AACA;AAEA;AAAA;AA/YA;AAgZA;AAAA;AAAA;AAGA;AAAA;AAnZA;AAoZA;AAAA;AAAA;AAIA;AAxZA;AAwZA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAhcA;AAocA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAreA;AA2eA;AAEA;AAAA;AAEA;AAGA;AACA;AAAA;AACA;AACA;AAAA;AAEA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAKA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAiBA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAKA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAQA;AAIA;AACA;AAEA;AAAA;AACA;AAEA;AAhkBA;AAAA;AAFA;AACA;AAzDA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AAEA;AArDA;AAAA;AADA;AAHA;;;;;;;;;;;;;;;;;ACCA;AAGA;AAAA;AAMA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAEA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAEA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AA5EA;AA+EA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AAtFA;AAyFA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AAhGA;AAmGA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AA1GA;AA6GA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AApHA;AAuHA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;;AC3IA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA;AAIA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAEA;AAIA;AAIA;AACA;AAAA;AACA;AACA;AAIA;AACA;AAAA;AACA;AACA;AAIA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AAAA;AACA;AACA;AAIA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChKA;AACA;AACA;AACA;AAcA;AAAA;AACA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAAA;AAOA;AAEA;AAIA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAKA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AA7EA;AAAA;AAFA;AACA;AAhBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AAMA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAIA;AAEA;AAGA;AACA;AAAA;AAGA;AAEA;AAAA;AACA;AAEA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AAIA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAGA;AACA;AAAA;AAIA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAIA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAGA;AAEA;AAAA;AAGA;AAAA;AACA;AAIA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AACA;AAAA;AACA;AAEA;AAAA;AAAA;AACA;AAAA;AACA;AAzLA;AA0LA;AAAA;AAAA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AAEA;AAAA;AAGA;AACA;AASA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AAGA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAIA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AAIA;AACA;AAAA;AAIA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAEA;AAAA;AAIA;AAEA;AAEA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAzWA;AA4WA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AA5YA;AAmZA;AAAA;AAAA;AACA;AACA;AAAA;AAEA;AAMA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAjbA;AAkbA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAKA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA9cA;AAgdA;AAAA;AAAA;AACA;AAIA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAIA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAhfA;AAkfA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAIA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAIA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AASA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAEA;AAGA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAGA;AAEA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAGA;AACA;AAEA;AAGA;AAEA;AACA;AAAA;AACA;AAIA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AAGA;AAEA;AACA;AAAA;AACA;AAIA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAGA;AACA;AAGA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAGA;AACA;AAAA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAGA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAGA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AAAA;AAGA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAhvBA;AAwvBA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAKA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAWA;AAEA;AAAA;AACA;AAx0BA;AA20BA;AACA;AAAA;AAEA;AAEA;AAh1BA;AAi1BA;AACA;AACA;AAMA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAGA;AAp2BA;AAq2BA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAOA;AAAA;AAEA;AAj4BA;AAAA;AAAA;AAFA;AACA;AATA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AAEA;AAGA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAOA;AAEA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAlEA;AAsEA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAIA;AACA;AAAA;AACA;AAjGA;AAoGA;AAAA;AACA;AArGA;AAwGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AAvHA;AAAA;AADA;AANA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAYA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAaA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAGA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAlHA;AAqHA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AAGA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AAEA;AACA;AAEA;AAGA;AAAA;AAGA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AAAA;AAIA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AAAA;AAGA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AA5PA;AA6PA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAvZA;AA0ZA;AACA;AAAA;AAEA;AACA;AAGA;AAIA;AAraA;AAsaA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAGA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAUA;AAAA;AACA;AACA;AAKA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AAEA;AAAA;AAEA;AAAA;AACA;AAEA;AA1dA;AAAA;AADA;AAlBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AACA;AAIA;AAAA;AAoDA;AAKA;AAiBA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAnFA;AAAA;AACA;AAGA;AAAA;AACA;AAzBA;AA4BA;AAAA;AACA;AA7BA;AAgCA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAqCA;AAGA;AACA;AACA;AAEA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAjJA;AAoJA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAMA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AA5OA;AA+OA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AA5PA;AA+PA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAIA;AAAA;AASA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AAGA;AAEA;AAGA;AAGA;AAGA;AAGA;AAEA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAzaA;AAAA;AAFA;AACA;AAjBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AAEA;AACA;AAIA;AAAA;AAGA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AA2CA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAKA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AAxEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAvEA;AAiHA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AAEA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AAjKA;AAkKA;AAAA;AAAA;AACA;AAIA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAGA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAIA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAIA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAGA;AAEA;AAEA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AA7UA;AA8UA;AAAA;AAAA;AACA;AAEA;AAEA;AAAA;AAGA;AACA;AAAA;AAGA;AAMA;AAAA;AAGA;AAEA;AACA;AAAA;AAIA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AApXA;AAuXA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AAIA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AA/YA;AAgZA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAGA;AAIA;AAAA;AAGA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAEA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAvbA;AA+bA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAKA;AAAA;AAGA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AAIA;AAEA;AAIA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAleA;AAoeA;AAAA;AAAA;AACA;AAIA;AACA;AAAA;AAGA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAEA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAIA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AAAA;AAIA;AAGA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AAGA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAGA;AAIA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAAA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAAA;AAEA;AACA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAGA;AAEA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAGA;AACA;AAEA;AAGA;AAEA;AACA;AAAA;AACA;AAIA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAGA;AACA;AAGA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAGA;AACA;AAAA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAGA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAGA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AAEA;AAGA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAGA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AAEA;AAAA;AACA;AAAA;AAjzBA;AAozBA;AACA;AAAA;AAGA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAGA;AACA;AAEA;AAAA;AACA;AACA;AAIA;AACA;AAAA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAIA;AAAA;AACA;AACA;AACA;AAMA;AAEA;AACA;AAAA;AACA;AACA;AACA;AA92BA;AAg3BA;AAEA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAIA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAIA;AACA;AAEA;AAGA;AAEA;AACA;AAAA;AACA;AAIA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AAEA;AAAA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAGA;AAEA;AAAA;AAGA;AAAA;AAEA;AAz6BA;AAAA;AAFA;AACA;AATA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAEA;AACA;AACA;AAUA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AAaA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAtFA;AAyFA;AAGA;AACA;AAAA;AAIA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AAAA;AAEA;AAAA;AAGA;AAGA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AAGA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAMA;AAAA;AAAA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAoBA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAMA;AACA;AAAA;AAGA;AAKA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAKA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAEA;AAAA;AAEA;AAAA;AACA;AAEA;AAzYA;AAAA;AADA;AAbA;;;;;;;;;;;;;;;;;;;ACAA;AACA;AAIA;AACA;AACA;AACA;AAAA;AAKA;AASA;;;;;;;;;;;;;;;;;;;;;ACtBA;AACA;AACA;AACA;AAGA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AAAA;AAGA;AA6BA;;;;;;;;;;;;;;;;ACvEA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;ACRA;AAAA;AAOA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;AC3BA;AAAA;AACA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;ACRA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAoBA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAEA;AACA;AAEA;;;;;;;;;;;;;;;;ACrJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAXA;AAAA;AAaA;;;;;;;;;;;;;;;;ACbA;AAAA;AAYA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;AC5CA;AAAA;AAKA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;ACtBA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAIA;AAAA;AAEA;;;;;;;;;;;;;;;;;ACjBA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AAIA;AAKA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;ACxBA;AACA;AACA;AACA;AAEA;AAAA;AAIA;AAHA;AAKA;AAAA;AACA;AAEA;AAAA;AACA;AAAA;AAIA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAIA;AAAA;AACA;AAAA;AAIA;AAAA;AAEA;;;;;;;;;;;;;;;;;ACzCA;AAEA;AAAA;AAMA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAAA;AAIA;AAAA;AACA;AAAA;AAIA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAIA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;AChFA;AAAA;AAMA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;AClBA;AAAA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;ACbA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;ACTA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AACA;AATA;AACA;AAAA;AASA;AAAA;AAAA;AAAA;AAAA;AAOA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;;ACpDA;AAEA;AAAA;AAKA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AAEA;AAAA;AAIA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAIA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;ACjDA;AAAA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACTA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAEA;AASA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AAEA;AAAA;AAEA;AAEA;AAEA;AAIA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AAEA;AAEA;AAMA;AAAA;AAGA;AAAA;AAGA;AACA;AAEA;AAEA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAGA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AAAA;AAEA;AAEA;AAEA;AACA;AAAA;AAEA;AAWA;;;;;;;;;;;;;;;;AC9MA;AACA;AACA;AACA;AACA;AACA;AALA;AAAA;AAOA;;;;;;;;;;;;;;;;ACPA;AACA;AADA;AAAA;AAGA;;;;;;;;;;;;;;;;ACHA;AACA;AACA;AACA;AACA;AAJA;AAAA;AAMA;;;;;;;;;;;;;;;;ACNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAVA;AAAA;AAaA;;;;;;;;;;;;;;;;ACbA;AACA;AACA;AACA;AAHA;AAAA;AAMA;;;;;;;;;;;;;;;;ACNA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AA3BA;AAAA;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAhCA;AAAA;AAmCA;;;;;;;;;;;;;;;;ACnCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AArBA;AAAA;AAuBA;;;;;;;;;;;;;;;;ACvBA;AACA;AACA;AACA;AACA;AAJA;AAAA;AAMA;;;;;;;;;;;;;;;;ACNA;AACA;AACA;AAFA;AAAA;AAKA;;;;;;;;;;;;;;;;ACLA;AACA;AACA;AACA;AACA;AAJA;AAAA;;;;;;;;;;;;;;;;;;ACEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AATA;AAAA;AAwBA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;;;;;;;;;;;;;;;;ACxCA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAAA;AASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACFA;AAOA;AAAA;AAUA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAzCA;AAwDA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAGA;AAGA;AACA;AAEA;AAAA;AACA;AAzEA;AACA;AAAA;AAEA;AAAA;AACA;AAhDA;AAmDA;AACA;AAAA;AACA;AAmEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AA1KA;AA6KA;AACA;AACA;AACA;AACA;AAIA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAAA;AAKA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAIA;AACA;AACA;AACA;AACA;AAAA;AACA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAIA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA;AAAA;AAEA;AA1YA;AAAA;AA4YA;;;;;;;;;;;;;;;;;;;;;;AC1ZA;AACA;AACA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AARA;AAAA;AAuDA;AAAA;AAcA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AA1DA;AACA;AAAA;AAEA;AAAA;AACA;AAyDA;AAGA;AACA;AAAA;AAEA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAKA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAIA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAIA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAAA;AACA;AAGA;AACA;AAGA;AAGA;AAGA;AAEA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAIA;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAIA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAIA;AACA;AACA;AACA;AAAA;AACA;AAIA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAEA;AAEA;AAlSA;AAAA;AAAA;AAoSA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpWA;AAAA;AACA;AACA;AACA;AACA;AAIA;AAAA;AAGA;AACA;AAKA;AAAA;AAAA;AAcA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAIA;AAAA;AACA;AAIA;AAAA;AACA;AAIA;AAAA;AACA;AAIA;AAAA;AACA;AAIA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AArJA;AAuJA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAuBA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAKA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAIA;AAEA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAnXA;AAAA;AAFA;AACA;AAPA;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAVA;AAAA;AAaA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAvBA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACZA;AAGA;AAUA;AACA;AACA;AACA;AAHA;AAAA;AAYA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAUA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAMA;AACA;AACA;AACA;AAHA;AAAA;AAMA;AAAA;AAEA;AAEA;AAGA;AAEA;AAKA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AAAA;AAEA;AAEA;AAMA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAIA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AAAA;AAEA;AACA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAGA;AAAA;AAqBA;AACA;AAEA;AAAA;AApPA;AAqPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAIA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAEA;AAeA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AAMA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAEA;AAWA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AAMA;AAKA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAIA;AACA;AACA;AAQA;AAKA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtdA;AACA;AACA;AACA;AAKA;AAQA;AAaA;AAcA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAeA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAlJA;AAoKA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsBA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAhPA;AA0PA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsBA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAzUA;AA8VA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAeA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAeA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAEA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAEA;AAEA;;;;;;;;;;;;;;;;;AC1eA;AAEA;AAGA;AACA;AACA;AAOA;AACA;AAAA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;;;AC7CA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;;;;;;;;;;;;;;;;;;;;;;;ACXA;AACA;AAYA;AAIA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AAEA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAQA;AAoBA;AAKA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AAYA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAEA;;;;;;;;;;;;;;;;ACvIA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAcA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;;;ACxCA;AAWA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAIA;AAAA;AACA;AACA;AAIA;AAGA;AAAA;AACA;AACA;AAGA;AAEA;AAGA;AAAA;AACA;AACA;AAGA;AAEA;AAAA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;ACnGA;AACA;AAEA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAtDA;AAyDA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAOA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAIA;AACA;AAAA;AACA;AACA;AAEA;AAMA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkBA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AA9LA;AAgMA;AAAA;AACA;AACA;AAAA;AAEA;AApMA;AAuMA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAMA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAMA;AAAA;AACA;AACA;AACA;AAxPA;AA0PA;AACA;AACA;AAAA;AAIA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AA7QA;AAgRA;AACA;AACA;AACA;AAAA;AAIA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAtSA;AAySA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AAvVA;AA0VA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAGA;AAAA;AAGA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AA7WA;AAgXA;AACA;AACA;AAGA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AAEA;AAAA;AACA;AACA;AAGA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AApaA;AAAA;AALA;;;;;;;;;;;;;;;;ACaA;AAAA;AAMA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAIA;AAAA;AA9FA;AA+FA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAEA;AAEA;AAAA;AACA;AAEA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AAGA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AAGA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AAIA;AAAA;AAIA;AAAA;AAIA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AAGA;AAAA;AAEA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AAhNA;AAAA;AAAA;;;;;;;;;;;;;;;;;ACZA;AASA;AAAA;AAMA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAOA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AAAA;AAKA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAQA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAIA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AAOA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAEA;AAEA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAMA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;;ACrTA;AAKA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAOA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;;ACvBA;AAEA;AAOA;AAEA;AACA;AAAA;AAGA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;;AC7BA;AAEA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AAIA;AACA;AAAA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAAA;AAIA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAGA;AAAA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AAIA;AACA;AAAA;AACA;AACA;AAAA;AAGA;AAAA;AAKA;AAvEA;AAAA;;;;;;;;;;;;;;;;ACFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AATA;AAAA;AAWA;;;;;;;;;;;;;;;;ACTA;AAAA;AAOA;AAAA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;ACZA;AAAA;AASA;AAAA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;ACdA;AAAA;AAOA;AAAA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;ACZA;AAAA;AAOA;AAAA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;ACZA;AAAA;AASA;AAAA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;ACdA;AAAA;AAOA;AAAA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;ACbA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAIA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;ACxDA;AAAA;AASA;AAAA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;ACdA;AAAA;AAWA;AAAA;AAEA;;;;;;;;;;;;;;;;ACbA;AAAA;AASA;AAAA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;AChBA;AACA;AACA;AACA;AAHA;AAAA;AAKA;;;;;;;;;;;;;;;;ACHA;AAAA;AAOA;AAAA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;ACZA;AAAA;AAQA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;ACZA;AAAA;AAWA;AAAA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;ACjBA;AACA;AACA;AACA;AAEA;AAAA;AAIA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;ACzBA;AAAA;AAMA;AACA;AACA;AAAA;AACA;AACA;AASA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AASA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7DA;AACA;AACA;AAIA;AAAA;AAgBA;AAfA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAKA;AAGA;AACA;AAAA;AAEA;AACA;AAEA;AAIA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAKA;AAAA;AAEA;AAxEA;AAAA;AAFA;AACA;AALA;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AAEA;AACA;AACA;AACA;AAMA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAFA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;ACrCA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAGA;AAAA;AAkBA;AAhBA;AACA;AACA;AAeA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAEA;AAGA;AAGA;AAGA;AACA;AAEA;AAGA;AAEA;AAAA;AACA;AAAA;AApEA;AAwEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAIA;AACA;AACA;AACA;AACA;AAAA;AACA;AAIA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAIA;AACA;AAAA;AACA;AArKA;AAwKA;AACA;AACA;AAAA;AACA;AACA;AA5KA;AA+KA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AAAA;AAGA;AAEA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AAMA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAIA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpRA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAcA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC5BA;AAGA;AAAA;AACA;AAAA;AAIA;AAUA;AAAA;AATA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtBA;AAEA;AAAA;AACA;AAAA;AAIA;AAaA;AAAA;AAZA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWA;AAIA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxBA;AAYA;AAEA;AAEA;AACA;AACA;AACA;AAKA;AAAA;AAsBA;AARA;AACA;AACA;AACA;AACA;AACA;AACA;AAlBA;AACA;AACA;AAEA;AAAA;AAiBA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAIA;AACA;AAAA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AAEA;AAAA;AAOA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAIA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AAMA;AAIA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAIA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AAKA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAMA;AAEA;AA9NA;AAiOA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAvQA;AA0QA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAYA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAAA;AAEA;AAAA;AAGA;AAIA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AAAA;AACA;AAEA;AACA;AAGA;AACA;AAIA;AAAA;AAIA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AAxaA;AA2aA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AAGA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAIA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AA9fA;AAigBA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAKA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAIA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAIA;AAAA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AAGA;AAIA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAIA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAKA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAKA;AAAA;AAGA;AAMA;AAAA;AACA;AAAA;AAGA;AAGA;AAEA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAKA;AAEA;AAEA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAIA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAIA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAIA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAGA;AAEA;AA52CA;AA+2CA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAEA;AAl2CA;AAAA;AADA;AAeA;AACA;AACA;AACA;AACA;AACA;AACA;AA5CA;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AAHA;AAAA;AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACLA;AACA;AACA;AAGA;AAAA;AAYA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AA7BA;AAAA;AADA;AAJA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAEA;AACA;AACA;AAIA;AAAA;AAAA;AAsBA;AAJA;AACA;AACA;AAdA;AAKA;AAEA;AACA;AAEA;AAQA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAKA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AAEA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AAIA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAKA;AACA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAeA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AAEA;AACA;AAMA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AAhTA;AAAA;AADA;AAmBA;AACA;AACA;AA5BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAEA;AACA;AACA;AAKA;AAAA;AAiCA;AALA;AACA;AACA;AACA;AA9BA;AAEA;AAAA;AAiCA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAoCA;AAEA;AAEA;AAGA;AAEA;AACA;AAEA;AAEA;AACA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AArLA;AAwLA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAEA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAlOA;AAAA;AADA;AA6BA;AACA;AACA;AACA;AAxCA;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AAAA;AATA;AAoBA;AATA;AACA;AACA;AAIA;AAKA;AACA;AAAA;AAIA;AAAA;AACA;AACA;AAIA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AAEA;AAEA;AAAA;AAEA;AAGA;AAEA;AAAA;AACA;AA9GA;AAiHA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AAGA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;AC9KA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAFA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChCA;AACA;AAGA;AAEA;AAEA;AACA;AACA;AACA;AAGA;AAEA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AA+BA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1DA;AAGA;AACA;AAWA;AAAA;AACA;AAAA;AAIA;AAHA;AA0DA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAvBA;AAAA;AApDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA4BA;AAAA;AAHA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAyBA;AAAA;AAtBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AAOA;AAAA;AAJA;AACA;AACA;AACA;AAOA;AAAA;AAJA;AACA;AACA;AACA;AAmBA;AAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AASA;AAAA;AANA;AACA;AACA;AACA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AAOA;AAAA;AAJA;AACA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AASA;AAAA;AANA;AACA;AACA;AACA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAOA;AAAA;AAJA;AACA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AAOA;AAAA;AAJA;AACA;AACA;AACA;AAOA;AAAA;AAJA;AACA;AACA;AACA;AAOA;AAAA;AAJA;AACA;AACA;AACA;AA8FA;AAAA;AA3FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACncA;AAQA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAKA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuBA;AANA;AACA;AACA;AACA;AACA;AAnBA;AAEA;AACA;AACA;AAkBA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AArSA;AA2SA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAGA;AAEA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAKA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA;AAIA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAMA;AAGA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AAAA;AAEA;AAEA;AACA;AAMA;AAAA;AACA;AACA;AAEA;AA32BA;AAAA;AADA;AAkBA;AACA;AACA;AACA;AACA;AA7CA;;;;;;;;;;;;;;;;ACGA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;;ACtBA;AAEA;AAAA;AAcA;AAhBA;AAoBA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAIA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;ACvGA;AACA;AACA;AACA;AAHA;AAAA;AAKA;;;;;;;;;;;;;;;;ACLA;AACA;AACA;AAFA;AAAA;AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACJA;AACA;AACA;AAGA;AAAA;AAWA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAAA;AAEA;AAdA;AAAA;AADA;AAJA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAIA;AAAA;AAAA;AAAA;AA8DA;AALA;AACA;AACA;AACA;AA3DA;AASA;AAGA;AAsBA;AA6BA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAKA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AA/KA;AAkLA;AACA;AAEA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AACA;AAGA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AAGA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAIA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAKA;AAKA;AAAA;AACA;AAGA;AACA;AAIA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwBA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AAIA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AAIA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAMA;AAIA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AAEA;AAGA;AAEA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AAIA;AAEA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AAEA;AAEA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAKA;AAIA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AASA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAKA;AACA;AAEA;AAAA;AACA;AAGA;AAp9BA;AAAA;AADA;AA0DA;AACA;AACA;AACA;AAzEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACKA;AAGA;AACA;AAYA;AAAA;AACA;AAAA;AAIA;AAHA;AAoDA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAhCA;AAAA;AA9CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAqCA;AAAA;AAHA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAyBA;AAAA;AAtBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AAOA;AAAA;AAJA;AACA;AACA;AACA;AAOA;AAAA;AAJA;AACA;AACA;AACA;AAmBA;AAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AASA;AAAA;AANA;AACA;AACA;AACA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AAOA;AAAA;AAJA;AACA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AASA;AAAA;AANA;AACA;AACA;AACA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAOA;AAAA;AAJA;AACA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AAOA;AAAA;AAJA;AACA;AACA;AACA;AAOA;AAAA;AAJA;AACA;AACA;AACA;AAOA;AAAA;AAJA;AACA;AACA;AACA;AA8FA;AAAA;AA3FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxcA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAIA;AAAA;AAdA;AA8BA;AAdA;AACA;AAgBA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AAEA;AAEA;AAEA;AACA;AACA;AAEA;AAAA;AAGA;AAEA;AAAA;AACA;AAGA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrEA;AACA;AAGA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAsCA;AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChFA;AAIA;AAAA;AAEA;AAAA;AAIA;AAHA;AA6CA;AAEA;AAAA;AAAA;AAAA;AAjCA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA+BA;AAAA;AA5BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAMA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzDA;AAOA;AAGA;AACA;AACA;AACA;AAMA;AAAA;AAeA;AAPA;AACA;AACA;AACA;AACA;AACA;AAZA;AACA;AAIA;AAAA;AAUA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAtEA;AAuEA;AAEA;AACA;AACA;AAOA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AAEA;AAEA;AAnGA;AAmGA;AAAA;AAGA;AACA;AAAA;AAIA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAAA;AAKA;AAKA;AAAA;AACA;AAGA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AA3QA;AA4QA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAAA;AAAA;AAMA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAGA;AAKA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAzUA;AAqVA;AAAA;AACA;AAGA;AAEA;AAEA;AAAA;AACA;AA9VA;AAiWA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AApYA;AAyYA;AACA;AAAA;AAIA;AACA;AAAA;AACA;AACA;AAGA;AAGA;AAKA;AAAA;AAGA;AACA;AAEA;AAEA;AAEA;AAGA;AAAA;AAGA;AAAA;AAGA;AAMA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAGA;AACA;AACA;AACA;AAKA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AAEA;AAIA;AAAA;AAIA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAzfA;AA4fA;AAKA;AACA;AAAA;AAGA;AAEA;AAEA;AACA;AAEA;AAEA;AAGA;AAGA;AAGA;AACA;AAEA;AAAA;AAEA;AAAA;AAIA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AAGA;AACA;AACA;AACA;AAKA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAIA;AAAA;AAEA;AA/kBA;AAAA;AADA;AASA;AACA;AACA;AACA;AACA;AACA;AAhCA;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AAJA;AAAA;AAMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACLA;AACA;AACA;AAGA;AAAA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAIA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAAA;AAAA;AAOA;AA3CA;AAAA;AADA;AALA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAGA;AAAA;AA0BA;AAJA;AACA;AACA;AAvBA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAUA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AAEA;AAIA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAIA;AAEA;AAIA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAIA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AA7QA;AAiRA;AACA;AACA;AACA;AAEA;AAEA;AAMA;AAGA;AACA;AACA;AAIA;AAEA;AAGA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AAKA;AAGA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAIA;AAEA;AACA;AAKA;AAGA;AAAA;AAGA;AACA;AAAA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAEA;AAMA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAIA;AAEA;AAEA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAvcA;AA0cA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AAIA;AAKA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAOA;AAGA;AAEA;AAAA;AAUA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAMA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAIA;AAEA;AACA;AAAA;AAGA;AAAA;AAEA;AA5iBA;AAAA;AADA;AAuBA;AACA;AACA;AApCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAIA;AAAA;AAEA;AAAA;AAIA;AAHA;AA6CA;AACA;AAAA;AAAA;AAhCA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA+BA;AAAA;AA5BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxDA;AAEA;AACA;AACA;AACA;AACA;AAIA;AAAA;AAaA;AALA;AACA;AACA;AACA;AAVA;AACA;AACA;AACA;AACA;AAAA;AAUA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAIA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAEA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAKA;AAGA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AA7HA;AAAA;AADA;AASA;AACA;AACA;AACA;AArBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAIA;AAAA;AAEA;AAAA;AAIA;AAHA;AA6CA;AACA;AAAA;AAAA;AAhCA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA+BA;AAAA;AA5BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAKA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxDA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAYA;AALA;AACA;AAEA;AARA;AAEA;AAAA;AASA;AAGA;AACA;AACA;AA1BA;AA2BA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AAKA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AA5JA;AA+JA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AAIA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AAKA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAeA;AAAA;AACA;AAEA;AA1PA;AAAA;AADA;AAQA;AACA;AACA;AAjBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAIA;AAAA;AAEA;AAAA;AAIA;AAHA;AA2CA;AACA;AAAA;AAAA;AA9BA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA6BA;AAAA;AA1BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAKA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtDA;AAGA;AAEA;AACA;AAIA;AAAA;AASA;AAJA;AACA;AACA;AALA;AAAA;AAQA;AAGA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AArFA;AAAA;AADA;AAMA;AACA;AACA;AAjBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAIA;AAAA;AAEA;AAAA;AAIA;AAHA;AA2CA;AACA;AAAA;AAAA;AA9BA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA6BA;AAAA;AA1BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAKA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtDA;AAEA;AACA;AACA;AAEA;AAGA;AAAA;AAaA;AALA;AACA;AACA;AACA;AANA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAQA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AAAA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAIA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AAWA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAAA;AACA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AAEA;AAMA;AAGA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AAAA;AAEA;AAGA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAvIA;AAAA;AADA;AASA;AACA;AACA;AACA;AApBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAIA;AAAA;AAEA;AAAA;AAIA;AAHA;AA2CA;AACA;AAAA;AAAA;AA9BA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA6BA;AAAA;AA1BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAKA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrDA;AACA;AACA;AACA;AAGA;AAAA;AAUA;AAJA;AACA;AACA;AANA;AAAA;AASA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AArDA;AAAA;AADA;AAOA;AACA;AACA;AAfA;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAPA;AAgBA;AAPA;AACA;AASA;AAAA;AACA;AACA;AAIA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAIA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAtFA;AA2FA;AAEA;AAEA;AAEA;AAGA;AAEA;AAEA;AAEA;AAAA;AACA;AA3GA;AA+GA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAvHA;AA0HA;AACA;AACA;AACA;AAAA;AACA;AA9HA;AAkIA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAJA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnDA;AACA;AAGA;AAEA;AAEA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAqBA;AAGA;;;;;;;;;;;;;;;;;;AC3CA;AAGA;AAAA;AAEA;AAAA;AAIA;AAHA;AAIA;AAAA;AAAA;AAEA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACZA;AAEA;AACA;AACA;AACA;AAKA;AAAA;AAWA;AALA;AACA;AACA;AACA;AANA;AAAA;AASA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAIA;AACA;AAIA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AA1SA;AA6SA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAEA;AAMA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAtWA;AAAA;AADA;AAOA;AACA;AACA;AACA;AApBA;;;;;;;;;;;;;;;;ACAA;AASA;;;;;;;;;;;;;;;;ACPA;AAAA;AAEA;AAEA;AACA;AACA;AAAA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACRA;AAEA;AACA;AAEA;AACA;AAKA;AAAA;AAqBA;AANA;AACA;AACA;AAEA;AAjBA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AAWA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AAAA;AACA;AASA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AAGA;AAvGA;AAwGA;AACA;AACA;AAGA;AAEA;AAAA;AAEA;AACA;AAEA;AAIA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAjIA;AAkIA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAjJA;AAoJA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAUA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AASA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AAIA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAQA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AAKA;AAEA;AAIA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAIA;AAAA;AACA;AAEA;AAEA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAKA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAtZA;AAAA;AADA;AAgBA;AACA;AACA;AACA;AA9BA;;;;;;;;;;;;;;;;;;ACAA;AAGA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACTA;AACA;AACA;AACA;AACA;AACA;AAIA;AAAA;AAaA;AALA;AACA;AACA;AACA;AANA;AAAA;AASA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AAvUA;AA0UA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAEA;AAMA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAhWA;AAmWA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAKA;AAAA;AAEA;AACA;AACA;AAGA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AA1bA;AAAA;AADA;AASA;AACA;AACA;AACA;AArBA;;;;;;;;;;;;;;;;ACAA;AAUA;;;;;;;;;;;;;;;;ACRA;AAAA;AAEA;AAEA;AACA;AAAA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAiBA;AAJA;AACA;AACA;AAbA;AACA;AACA;AAEA;AAEA;AAEA;AAAA;AAQA;AA9BA;AAsCA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAMA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AA9GA;AAiHA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAKA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAKA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AArRA;AA6RA;AAEA;AACA;AACA;AAEA;AAOA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAIA;AACA;AAAA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAIA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAOA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAIA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAKA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA;AAvdA;AAAA;AADA;AAcA;AACA;AACA;AA3BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAIA;AAAA;AAEA;AAAA;AAIA;AAHA;AAIA;AACA;AAAA;AAAA;AAKA;AAAA;AAHA;AACA;AACA;AAGA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpBA;AACA;AACA;AACA;AACA;AAKA;AAAA;AASA;AALA;AACA;AACA;AACA;AAAA;AAGA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAQA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAIA;AACA;AACA;AAAA;AAGA;AACA;AAKA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAtFA;AAyFA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AAIA;AACA;AACA;AAAA;AAGA;AAAA;AAEA;AApGA;AAAA;AADA;AAKA;AACA;AACA;AACA;AAhBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAEA;AACA;AACA;AACA;AAIA;AAAA;AAuBA;AAJA;AACA;AACA;AAnBA;AACA;AAEA;AACA;AAGA;AAEA;AAEA;AACA;AAEA;AAAA;AAQA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAOA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AApEA;AAqEA;AACA;AACA;AACA;AACA;AAEA;AAIA;AAAA;AAEA;AAAA;AAGA;AACA;AAEA;AAKA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAtIA;AAyIA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAIA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AAEA;AACA;AAGA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAIA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAGA;AAOA;AACA;AAKA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAiBA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AAEA;AAMA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AACA;AAGA;AACA;AAEA;AAEA;AACA;AAAA;AAGA;AAAA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AArdA;AAwdA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AAEA;AAteA;AAAA;AADA;AAoBA;AACA;AACA;AA9BA;;;;;;;;;;;;;;;;;;ACAA;AAGA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;AACA;AACA;AACA;AAGA;AAGA;AAAA;AAUA;AANA;AACA;AACA;AACA;AACA;AAPA;AACA;AAAA;AASA;AAGA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AAGA;AAEA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAIA;AACA;AAKA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AAEA;AAEA;AAEA;AAxGA;AA2GA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AA1IA;AAAA;AADA;AAKA;AACA;AACA;AACA;AACA;AAjBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AAGA;AAAA;AAQA;AAPA;AACA;AACA;AACA;AACA;AAIA;AAAA;AAEA;AAXA;AAAA;AADA;AAJA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAEA;AACA;AACA;AACA;AAIA;AAAA;AAsBA;AALA;AACA;AACA;AACA;AAnBA;AACA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AAAA;AASA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAIA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AAWA;AAEA;AAEA;AACA;AAAA;AAEA;AAGA;AACA;AAAA;AAMA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AA5IA;AA6IA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAxKA;AA2KA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAaA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAUA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AAKA;AAEA;AAIA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAEA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAEA;AAEA;AACA;AAAA;AAGA;AAAA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AAEA;AAxZA;AAAA;AADA;AAkBA;AACA;AACA;AACA;AA7BA;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAGA;AACA;AAtBA;AAAA;AAyBA;;;;;;;;;;;;;;;;;;;;;ACzBA;AACA;AACA;AAEA;AAEA;AAEA;AAAA;AAaA;AAJA;AALA;AAAA;AAWA;AAKA;AAEA;AAEA;AAEA;AAGA;AAEA;AAAA;AACA;AAGA;AAEA;AAAA;AAMA;AAGA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AAIA;AA5EA;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACRA;AAGA;AAAA;AAEA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAGA;AACA;;;;;;;;;;;;;;;;ACdA;AAEA;AACA;AACA;AACA;AACA;AACA;AAPA;AAAA;AAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;AAEA;AAEA;AAEA;AACA;AAOA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChBA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AANA;AAAA;AADA;AAHA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAGA;AACA;AACA;AAEA;AAAA;AAkBA;AADA;AANA;AAAA;AAQA;AAGA;AAEA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAIA;AAEA;AAEA;AAEA;AAEA;AAEA;AAAA;AACA;AAGA;AAEA;AAAA;AAMA;AAGA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAEA;AAIA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAKA;AA3PA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7BA;AACA;AACA;AAiBA;AAEA;AACA;AAwBA;AAEA;AAEA;AAAA;AAIA;AAHA;AAmkCA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAkTA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAuNA;AAAA;AAAA;AAvlDA;AAAA;AAnCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAcA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAsBA;AAAA;AAnBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAUA;AAAA;AANA;AACA;AACA;AACA;AACA;AACA;AAUA;AAAA;AANA;AACA;AACA;AACA;AACA;AACA;AAuBA;AAAA;AAnBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAoDA;AAAA;AAjDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAUA;AAAA;AAPA;AACA;AACA;AACA;AACA;AACA;AACA;AA8GA;AAAA;AA1GA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAgEA;AAAA;AA5DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAmDA;AAAA;AAhDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAuVA;AAAA;AApVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA8QA;AAAA;AA3QA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA0BA;AAAA;AApBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAiBA;AAAA;AAdA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA0BA;AAAA;AAvBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAgBA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAgDA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAkBA;AAAA;AAdA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAeA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA4CA;AAAA;AAxCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA2CA;AAAA;AAxCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAMA;AAAA;AAHA;AACA;AACA;AAiKA;AAAA;AA3JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAWA;AAAA;AARA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAuMA;AAAA;AA7KA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAgBA;AAAA;AAbA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAuBA;AAAA;AApBA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAKA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrrDA;AACA;AACA;AACA;AACA;AAKA;AAAA;AAWA;AAJA;AACA;AACA;AARA;AACA;AAEA;AAAA;AAQA;AAGA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AAEA;AAEA;AAEA;AAAA;AACA;AAGA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAIA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAEA;AAvIA;AAAA;AADA;AAQA;AACA;AACA;AAlBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAEA;AACA;AACA;AACA;AAGA;AAIA;AAAA;AAOA;AALA;AACA;AACA;AACA;AAAA;AAGA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAvDA;AAAA;AADA;AAGA;AACA;AACA;AACA;AAjBA;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AALA;AAAA;AAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACPA;AACA;AACA;AACA;AAqBA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA0CA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtFA;AACA;AACA;AAaA;AAEA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAAA;AA4CA;AANA;AACA;AAEA;AACA;AAzCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AAAA;AAAA;AAAA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AAEA;AAYA;AAAA;AACA;AAGA;AAGA;AAEA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AAIA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AAGA;AAAA;AAEA;AAAA;AACA;AAGA;AAEA;AAEA;AAAA;AAEA;AAGA;AAEA;AAAA;AAEA;AAEA;AAEA;AACA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAEA;AAAA;AACA;AAGA;AAGA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAKA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAKA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AACA;AAIA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAKA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAKA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAKA;AAKA;AAAA;AACA;AAGA;AAGA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AAAA;AAIA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAGA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAIA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAEA;AAGA;AAAA;AAEA;AAEA;AAEA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAIA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAhmBA;AAimBA;AAOA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAGA;AAEA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAEA;AAEA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAIA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAEA;AAAA;AACA;AAGA;AAOA;AACA;AACA;AAAA;AAGA;AAAA;AAGA;AACA;AAAA;AAGA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAIA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAKA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAEA;AAAA;AAEA;AA1/BA;AAAA;AADA;AAuCA;AACA;AACA;AAEA;AAlEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAWA;AAEA;AACA;AACA;AAEA;AAGA;AAAA;AAgBA;AANA;AACA;AAEA;AACA;AAbA;AACA;AAAA;AAeA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AACA;AACA;AAEA;AAAA;AAEA;AAEA;AAAA;AACA;AAWA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYA;AAGA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAIA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAQA;AAEA;AAKA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAEA;AAMA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAIA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAGA;AAAA;AAGA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AAAA;AAEA;AAAA;AAOA;AACA;AACA;AAEA;AAEA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAKA;AACA;AAIA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAIA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAKA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4CA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAIA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA8CA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AA3hBA;AAAA;AADA;AAWA;AACA;AACA;AAEA;AAlCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACUA;AAEA;AACA;AAEA;AAEA;AAEA;AAGA;AAAA;AAqCA;AANA;AACA;AACA;AAEA;AA/BA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AAEA;AAEA;AAUA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAIA;AAAA;AACA;AACA;AAEA;AACA;AAGA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAIA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AAEA;AAEA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAIA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AACA;AAOA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AAGA;AAEA;AAEA;AACA;AAAA;AAEA;AAGA;AAEA;AACA;AAAA;AAEA;AAGA;AAEA;AACA;AAAA;AAIA;AAEA;AACA;AAAA;AAIA;AACA;AACA;AAGA;AAIA;AAEA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAEA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAKA;AAKA;AAAA;AACA;AAGA;AACA;AAEA;AAEA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAMA;AACA;AAAA;AACA;AAEA;AA/fA;AAAA;AADA;AAgCA;AACA;AACA;AACA;AAxDA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAEA;AACA;AACA;AAEA;AAGA;AAAA;AAUA;AANA;AACA;AAEA;AACA;AAAA;AAGA;AAGA;AACA;AAAA;AACA;AAAA;AAGA;AAAA;AAIA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AA1EA;AAAA;AADA;AAKA;AACA;AACA;AAEA;AAjBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAEA;AACA;AACA;AAEA;AAGA;AAAA;AASA;AANA;AACA;AAEA;AACA;AAAA;AAGA;AAGA;AACA;AAAA;AACA;AAAA;AAGA;AAAA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWA;AAGA;AAEA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AA3EA;AAAA;AADA;AAIA;AACA;AACA;AAEA;AAhBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAEA;AAKA;AACA;AACA;AAGA;AAGA;AAUA;AANA;AACA;AACA;AAEA;AAAA;AAGA;AAGA;AACA;AAAA;AACA;AAAA;AAGA;AAAA;AAIA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AAEA;AAhEA;AAAA;AADA;AAQA;AACA;AACA;AACA;AAtBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AASA;AAAA;AA2IA;AANA;AACA;AACA;AAEA;AA7EA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAWA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAOA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAIA;AACA;AAAA;AAIA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AAIA;AACA;AAAA;AAEA;AAAA;AAEA;AAGA;AACA;AAAA;AAEA;AAIA;AAGA;AAAA;AACA;AAIA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAzXA;AA4XA;AAEA;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAAA;AAIA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AAEA;AAGA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAIA;AAAA;AACA;AAGA;AAAA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AAIA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AAIA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AAAA;AAIA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AAAA;AAIA;AAAA;AAEA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AAAA;AAIA;AAAA;AAEA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AAAA;AAIA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAlkBA;AAukBA;AACA;AAAA;AAEA;AAMA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAIA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AAEA;AAjnBA;AAAA;AADA;AAsIA;AACA;AACA;AACA;AAvJA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAEA;AACA;AAEA;AAGA;AAAA;AAYA;AANA;AACA;AACA;AAEA;AAAA;AAGA;AAGA;AAAA;AACA;AAGA;AAIA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAEA;AArEA;AAAA;AADA;AAOA;AACA;AACA;AACA;AAjBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACOA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAAA;AAmBA;AANA;AACA;AACA;AAEA;AAXA;AACA;AAaA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAKA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AAGA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AAAA;AACA;AAIA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AASA;AACA;AAEA;AAAA;AACA;AAhHA;AAmHA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AAMA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AAMA;AAKA;AAGA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AAUA;AAEA;AACA;AACA;AAAA;AAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoBA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAKA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAMA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AAGA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAEA;AACA;AApSA;AAqSA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AAAA;AAEA;AAAA;AAKA;AACA;AAEA;AAAA;AAEA;AAAA;AAOA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAGA;AAGA;AACA;AA5VA;AA6VA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AAlYA;AAqYA;AACA;AAMA;AAKA;AAAA;AAEA;AAMA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAcA;AAIA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWA;AAEA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWA;AAEA;AAEA;AAGA;AAAA;AAMA;AAvdA;AA0dA;AACA;AAEA;AAMA;AACA;AApeA;AAqeA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AAKA;AAEA;AAKA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AAOA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AAGA;AAEA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AAEA;AAIA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AAKA;AAAA;AAEA;AACA;AACA;AACA;AAIA;AAAA;AAEA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAKA;AAEA;AAKA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AAOA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AAGA;AAEA;AAAA;AAGA;AAKA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAGA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAGA;AAAA;AAEA;AAGA;AAAA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AAKA;AAAA;AAEA;AACA;AACA;AACA;AAIA;AAAA;AAEA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAEA;AAEA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAIA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AA75BA;AAg6BA;AAEA;AAKA;AAAA;AAEA;AAAA;AACA;AA16BA;AA66BA;AAAA;AACA;AAIA;AAEA;AAGA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAkBA;AACA;AAx9BA;AAy9BA;AAAA;AAIA;AACA;AACA;AAEA;AACA;AAGA;AAKA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAMA;AACA;AACA;AAIA;AAIA;AACA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AAKA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAKA;AAAA;AACA;AAGA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwBA;AAvmCA;AAAA;AADA;AAcA;AACA;AACA;AACA;AApCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAOA;AAEA;AAMA;AAEA;AACA;AACA;AAGA;AACA;AAKA;AAAA;AA5BA;AAoDA;AAPA;AACA;AACA;AACA;AAEA;AApBA;AACA;AAKA;AACA;AAgBA;AACA;AACA;AAGA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAGA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AArGA;AAwGA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AAMA;AAKA;AAGA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AAGA;AACA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAcA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAKA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAEA;AAAA;AACA;AAGA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAlYA;AAqYA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAIA;AAIA;AAAA;AAGA;AAGA;AAMA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAIA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAGA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAIA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AAGA;AAKA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAKA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAKA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAKA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAKA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAKA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAKA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAKA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAKA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAKA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAKA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAIA;AAAA;AACA;AACA;AACA;AAIA;AAGA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AAGA;AAAA;AACA;AAAA;AAIA;AAMA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAGA;AAQA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAEA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAEA;AAAA;AACA;AAv/BA;AA0/BA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAUA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AAMA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AAEA;AAEA;AAEA;AAKA;AAAA;AACA;AACA;AAGA;AAEA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AAKA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AA7nCA;AAgoCA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AAzoCA;AA4oCA;AAAA;AACA;AAIA;AAGA;AAIA;AAIA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AAEA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAIA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAIA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAIA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAIA;AACA;AAEA;AAAA;AACA;AAIA;AACA;AAAA;AACA;AAIA;AACA;AAEA;AACA;AAAA;AACA;AAIA;AACA;AAEA;AACA;AAAA;AACA;AAIA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AA3yCA;AA4yCA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AA9zCA;AAi0CA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AAt1CA;AAw1CA;AAAA;AAGA;AACA;AAEA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AA32CA;AA82CA;AACA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AAh4CA;AAm4CA;AACA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AAr5CA;AAw5CA;AACA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAv6CA;AA06CA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAMA;AAOA;AAEA;AAMA;AAEA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAIA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAIA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAIA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAIA;AAAA;AACA;AAEA;AAEA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAAA;AAIA;AAEA;AAAA;AAGA;AAAA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAGA;AAGA;AACA;AAKA;AAMA;AACA;AACA;AACA;AACA;AAIA;AAIA;AACA;AAEA;AACA;AAEA;AACA;AAIA;AAGA;AAEA;AAIA;AAEA;AACA;AAEA;AACA;AAIA;AAGA;AAEA;AAIA;AAEA;AACA;AAGA;AACA;AAAA;AAGA;AAAA;AAEA;AAAA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AAGA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AAGA;AACA;AAKA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAKA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AAEA;AAEA;AAAA;AACA;AAGA;AAGA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAMA;AAAA;AAAA;AAIA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAGA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAMA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAIA;AACA;AAEA;AACA;AAAA;AACA;AAIA;AACA;AAEA;AACA;AAAA;AACA;AAIA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAIA;AACA;AAEA;AACA;AAAA;AACA;AAIA;AACA;AAEA;AACA;AAAA;AACA;AAIA;AACA;AAEA;AACA;AAAA;AACA;AAIA;AACA;AAEA;AACA;AAAA;AACA;AAIA;AACA;AAEA;AACA;AAAA;AACA;AAIA;AACA;AAGA;AAAA;AAEA;AAzkEA;AAAA;AADA;AAkBA;AACA;AACA;AACA;AACA;AAjDA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAGA;AACA;AAEA;AAEA;AACA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AAlCA;AAAA;AADA;AAJA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAiBA;AAEA;AACA;AACA;AACA;AAGA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAJA;AAAA;AAQA;AAAA;AAiHA;AANA;AACA;AACA;AAEA;AAzGA;AAKA;AAAA;AAAA;AAAA;AAEA;AACA;AAiBA;AAkBA;AAEA;AAQA;AAQA;AAEA;AASA;AAEA;AAKA;AAAA;AAAA;AAAA;AAaA;AACA;AAKA;AAAA;AAAA;AAAA;AAkpBA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AAEA;AAAA;AAKA;AAxpBA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AA1MA;AA6MA;AACA;AAAA;AAEA;AAQA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAIA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AAAA;AACA;AAEA;AACA;AAEA;AAAA;AAGA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AAAA;AACA;AAEA;AACA;AAEA;AAAA;AAGA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AAAA;AACA;AAEA;AACA;AAEA;AAAA;AAGA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AAAA;AACA;AAEA;AACA;AAEA;AAAA;AAGA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AAAA;AACA;AAGA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAWA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AAEA;AAEA;AAEA;AACA;AAAA;AAGA;AAAA;AACA;AASA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAUA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAIA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAGA;AACA;AAAA;AACA;AAEA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAIA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAwBA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AAEA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAEA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAEA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAGA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AACA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAEA;AAGA;AAEA;AAGA;AAEA;AAGA;AAEA;AAGA;AAEA;AACA;AACA;AAGA;AAEA;AACA;AACA;AAGA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAKA;AAEA;AACA;AACA;AAGA;AAEA;AACA;AACA;AAGA;AAEA;AAEA;AACA;AAEA;AAEA;AAGA;AAEA;AAEA;AAEA;AAEA;AACA;AAEA;AACA;AAKA;AAKA;AAAA;AACA;AAAA;AAAA;AAAA;AAKA;AAAA;AACA;AAGA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAvtCA;AAAA;AADA;AA4GA;AACA;AACA;AACA;AAnJA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAYA;AAEA;AACA;AACA;AACA;AAKA;AAAA;AAgGA;AANA;AACA;AACA;AAEA;AA1FA;AAEA;AAEA;AAEA;AAGA;AAGA;AAEA;AACA;AAEA;AAGA;AAEA;AACA;AACA;AAkDA;AAGA;AAAA;AACA;AACA;AAEA;AAYA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AAGA;AAKA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AAKA;AAKA;AAGA;AAKA;AAEA;AAEA;AAKA;AAKA;AACA;AACA;AAGA;AAQA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAKA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAGA;AAEA;AAGA;AAEA;AAGA;AAEA;AAEA;AAEA;AAEA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAKA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAIA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAGA;AAAA;AAGA;AAIA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAMA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAMA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAMA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAxtBA;AA2tBA;AACA;AACA;AACA;AAEA;AAYA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAKA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AAGA;AAEA;AAEA;AAEA;AACA;AAGA;AAEA;AAEA;AAEA;AAGA;AAGA;AACA;AACA;AAEA;AAGA;AACA;AACA;AAGA;AAGA;AACA;AACA;AAGA;AAGA;AACA;AACA;AAGA;AAGA;AACA;AACA;AAGA;AAEA;AAEA;AACA;AAEA;AAGA;AAGA;AAEA;AAEA;AAEA;AAEA;AAIA;AAEA;AAEA;AAKA;AAKA;AAEA;AAEA;AAEA;AAAA;AACA;AAAA;AAIA;AAGA;AAAA;AACA;AAOA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAKA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AAIA;AAAA;AACA;AAEA;AAt/BA;AAAA;AADA;AA2FA;AACA;AACA;AACA;AAnHA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAYA;AAEA;AACA;AACA;AAEA;AAGA;AAAA;AAmBA;AANA;AACA;AACA;AAEA;AAAA;AAGA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AAEA;AACA;AAGA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAMA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AAyCA;AAKA;AAKA;AAKA;AAKA;AAMA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAOA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAOA;AAGA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AAMA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AA1XA;AA2XA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AAIA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAGA;AAEA;AAAA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAMA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAUA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAGA;AAEA;AAGA;AACA;AAAA;AAOA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AA/lBA;AAAA;AADA;AAcA;AACA;AACA;AACA;AArCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AALA;AAAA;AADA;AAHA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAUA;AAAA;AA0CA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAjCA;AAeA;AACA;AACA;AAIA;AAAA;AAeA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAEA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AAGA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAIA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AAGA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAKA;AAAA;AACA;AACA;AAEA;AAIA;AAGA;AAEA;AACA;AAEA;AAEA;AAEA;AAKA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAGA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAOA;AACA;AAAA;AACA;AAIA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAGA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAEA;AA/gBA;AAAA;AADA;AAgCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAxDA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAEA;AACA;AACA;AACA;AACA;AAQA;AAGA;AAAA;AAgBA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AApBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAaA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AAIA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAEA;AAvKA;AAAA;AADA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA9BA;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AAAA;AAcA;AADA;AARA;AACA;AACA;AACA;AAAA;AAOA;AAGA;AACA;AAEA;AAAA;AAIA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AAMA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AAGA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;;;;;;;;;;;;;;;;;;;ACpIA;AACA;AAGA;AAAA;AAEA;AAAA;AAIA;AAHA;AAKA;AAAA;AAGA;AAAA;AAEA;AAGA;AAAA;AACA;AAIA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAEA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/BA;AACA;AACA;AAIA;AAAA;AAIA;AADA;AAAA;AAEA;AAIA;AAAA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AAEA;AAlCA;AAAA;AADA;AAIA;AATA;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AAHA;AAAA;AAMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACNA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAIA;AAAA;AAAA;AAsBA;AAHA;AACA;AAjBA;AACA;AACA;AAQA;AAAA;AAAA;AAWA;AAEA;AAAA;AACA;AAOA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAGA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAGA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAOA;AACA;AAAA;AAEA;AACA;AAKA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAjPA;AAAA;AADA;AAmBA;AAEA;AAhCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AAIA;AACA;AAGA;AAAA;AAWA;AAJA;AACA;AACA;AAPA;AACA;AASA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AA5CA;AA+CA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AA3EA;AAiFA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AA3FA;AA6FA;AAIA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAtGA;AAAA;AADA;AAOA;AAEA;AACA;AAlBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AASA;AAEA;;;;;;;;;;;;;;;;;;;ACjBA;AACA;AACA;AAEA;AAAA;AAYA;AAXA;AACA;AACA;AAKA;AACA;AAMA;AACA;AAGA;AACA;AAGA;AACA;AAGA;AAGA;AACA;AACA;AAAA;AAUA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChHA;AAEA;AACA;AACA;AA2BA;AACA;AACA;AACA;AACA;AAJA;AAAA;AAcA;AAEA;AAFA;AAGA;AACA;AAOA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAGA;AAAA;AAAA;AAAA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AA3FA;AA6FA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAEA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAYA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAhLA;AAmLA;AACA;AAIA;AAEA;AACA;AAAA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AACA;AAAA;AAjNA;AAqNA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAIA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAvOA;AA2OA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AAEA;AA9MA;AAAA;AADA;AA5CA;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AAEA;AAAA;AAyBA;AAxBA;AAgBA;AAgCA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAnCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAmBA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAGA;AACA;AACA;AAAA;AAGA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAEA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AAEA;AAGA;;;;;;;;;;;;;;;;;;;;;;;ACpKA;AACA;AACA;AACA;AACA;AAEA;AAAA;AA6CA;AA5CA;AACA;AAUA;AAcA;AAMA;AAOA;AAEA;AACA;AAiJA;AACA;AAAA;AA9IA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AAEA;AAIA;AAEA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAOA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAIA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AAAA;AAAA;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAGA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AALA;AAAA;;;;;;;;;;;;;;;;;;;;;;ACpdA;AACA;AAEA;AACA;AACA;AACA;AAGA;AAAA;AAOA;AADA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAeA;AAEA;AAEA;AAIA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAIA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAGA;AAEA;AAEA;AAEA;AAEA;AAGA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7QA;AACA;AACA;AACA;AAGA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AA9BA;AAAA;AADA;AALA;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AAGA;AAAA;AAKA;AAHA;AAKA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;AC1GA;AACA;AACA;AACA;AAGA;AAAA;AAIA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAIA;AACA;AAAA;AACA;AAEA;AACA;AAEA;AAAA;AAGA;AAAA;AACA;AAAA;AAGA;AAGA;AAGA;AACA;AAAA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;AC7CA;AACA;AACA;AAEA;AAMA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAsCA;AAnCA;AAIA;AAiCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAIA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAEA;AAAA;AAGA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AAGA;AAEA;AAAA;AAGA;AAEA;AAAA;AAGA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAIA;AAhXA;AAmXA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AA1YA;AA8YA;AAIA;AAIA;AAIA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAKA;AAKA;AAAA;AAAA;AAAA;AAKA;AAwBA;AAGA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAEA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAEA;AAIA;AAAA;AACA;AAEA;AAEA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAEA;AAEA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;ACrnBA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqCA;AApCA;AAKA;AACA;AACA;AAeA;AAgBA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAKA;AAGA;AAEA;AAEA;AAIA;AAEA;AAEA;AAEA;AACA;AAAA;AAEA;AAEA;AAAA;AACA;AAGA;AAEA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AAEA;AAAA;AAIA;AAEA;AAEA;AAEA;AAGA;AAEA;AAEA;AAEA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAMA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAWA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAWA;AAAA;AACA;AAEA;;;;;;;;;;;;;;;;ACtZA;AACA;AACA;AAFA;AAAA;AAIA;;;;;;;;;;;;;;;;ACJA;AACA;AACA;AACA;AACA;AAJA;AAAA;AAMA;;;;;;;;;;;;;;;;;;;;;;;;ACNA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAiEA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAbA;AAgBA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAxEA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAkDA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AAGA;AACA;AAGA;AAEA;AAEA;AAEA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAhLA;AAmLA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7SA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAoCA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAbA;AAgBA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AAGA;AACA;AAGA;AAEA;AAEA;AAEA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAhJA;AAmJA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAjRA;AAAA;AADA;AAXA;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwBA;AAtBA;AAcA;AASA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAIA;AAGA;AAEA;AAEA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AAIA;AACA;AACA;AACA;AAEA;AAAA;AAGA;AAAA;AAGA;AACA;AACA;AAEA;AAAA;AAGA;AAAA;AAEA;AAEA;AACA;AAAA;AAGA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAIA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;;;;;;;;;;;;;;;;;;AC7RA;AAEA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAGA;AAAA;AACA;AAGA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;;;ACrCA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAGA;AAAA;AACA;AAGA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;AClCA;AACA;AACA;AACA;AAEA;AAAA;AAUA;AATA;AAEA;AAQA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAGA;AAEA;AACA;AAEA;AAEA;AACA;AAEA;AAAA;AAGA;AAAA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AAlDA;AAqDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AAEA;AAAA;AACA;AAAA;AAAA;AAGA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;ACzGA;AACA;AACA;AACA;AAEA;AAAA;AAUA;AATA;AAEA;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAGA;AAEA;AACA;AAEA;AAEA;AACA;AAEA;AAAA;AAGA;AAAA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AAEA;AAAA;AACA;AAAA;AAAA;AAEA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;ACxEA;AACA;AACA;AAGA;AAAA;AAYA;AAXA;AACA;AACA;AAKA;AACA;AAKA;AACA;AAEA;AACA;AAEA;AAEA;AAEA;AAEA;AAAA;AACA;AAGA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;AC5GA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAcA;AATA;AACA;AACA;AACA;AACA;AAEA;AACA;AAXA;AACA;AAcA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;AC9GA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAaA;AALA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAGA;AAEA;AAEA;AAEA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAEA;AAEA;AAEA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;ACzGA;AACA;AACA;AACA;AACA;AAAA;AAOA;AALA;AACA;AACA;AACA;AAAA;AAGA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;ACxCA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA+BA;AAfA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA5BA;AAgCA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AASA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AA1JA;AA6JA;AAEA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;AChLA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4BA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA7BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAkBA;AAGA;AACA;AACA;AACA;AACA;AAUA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAhHA;AAmHA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;ACrIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAuBA;AAfA;AACA;AACA;AACA;AACA;AACA;AAOA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAOA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAKA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAEA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAIA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAoBA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxOA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAmBA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA8EA;AAIA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;ACvKA;AACA;AACA;AACA;AAEA;AAAA;AAsCA;AArCA;AACA;AACA;AAoBA;AAAA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAIA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAIA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAEA;AACA;AAGA;AAEA;AAAA;AAGA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAEA;AAIA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AAEA;AACA;AACA;AAFA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzVA;AACA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;AC/DA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAGA;AAAA;AAuCA;AA7BA;AAAA;AAqBA;AAGA;AAAA;AACA;AACA;AAIA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAAA;AAKA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AASA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAAA;AAKA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AAAA;AAIA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAIA;AACA;AACA;AACA;AAAA;AAGA;AAIA;AAEA;AAAA;AACA;AAGA;AAEA;AAMA;AAMA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAMA;AAAA;AAIA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAAA;AAKA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;ACzeA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AAoBA;AALA;AACA;AACA;AACA;AAfA;AAmBA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AAEA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AAGA;AAEA;AAEA;AAEA;AAGA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAOA;AAGA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AAIA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AACA;AAEA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAIA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAGA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAOA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAIA;AAGA;AACA;AACA;AAAA;AAIA;AACA;AAMA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;;AChaA;AAEA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAOA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA;AAAA;AAAA;AAAA;AAMA;AAAA;AAAA;AAAA;AAAA;AAKA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;AChJA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAkBA;AALA;AACA;AACA;AACA;AAPA;AACA;AAUA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAIA;AAGA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AAIA;AACA;AACA;AAGA;AAAA;AAGA;AAEA;AAAA;AAIA;AAAA;AACA;AAAA;AAAA;AAAA;AAOA;AAGA;AAGA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAOA;AACA;AACA;AAKA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AAEA;AACA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;AC3QA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAJA;AAAA;AAOA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyCA;AANA;AACA;AACA;AAEA;AAtCA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAKA;AACA;AAKA;AAEA;AAiBA;AACA;AAAA;AAMA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AAIA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AAWA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AAAA;AAGA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AAIA;AAAA;AACA;AACA;AACA;AACA;AAKA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAoBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;AC7iBA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AAgBA;AAJA;AACA;AACA;AAVA;AAEA;AAAA;AAWA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAtDA;AAyDA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAEA;AAGA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAzIA;AA4IA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAEA;AACA;AAMA;AACA;AAAA;AAEA;AACA;AAGA;AAGA;AAAA;AAEA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;;AC9RA;AAIA;AAAA;AASA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;ACzBA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AAaA;AAHA;AACA;AARA;AAEA;AAAA;AASA;AAGA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAEA;AAnDA;AAsDA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AA3HA;AA8HA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;;ACpOA;AAIA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;ACjBA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBA;AANA;AACA;AAEA;AACA;AAAA;AAGA;AAvBA;AA8BA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAOA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAGA;AAKA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AACA;AAAA;AACA;AAEA;;;;;;;;;;;;;;;;;;;AC3JA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgCA;AAHA;AACA;AA1BA;AAUA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAWA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AAEA;AAEA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AAIA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAEA;AAEA;AAAA;AAAA;AAAA;AAMA;AAIA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AAIA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAzVA;AAAA;AAAA;AAAA;AAJA;;;;;;;;;;;;;;;;;ACAA;AAEA;AAAA;AAUA;AAJA;AACA;AACA;AAAA;AAGA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;;;;;;;;;;;;;;;;;;;ACzBA;AACA;AACA;AAEA;AAAA;AAJA;AAYA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC5CA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AAYA;AAHA;AACA;AATA;AAEA;AAAA;AAEA;AAAA;AAAA;AAQA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAlFA;AAqFA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAIA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AACA;AA7GA;AAgHA;AACA;AACA;AACA;AAAA;AAOA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AAMA;AACA;AACA;AAAA;AACA;AAKA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;ACtKA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AAyBA;AAJA;AAEA;AAtBA;AAMA;AASA;AAWA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AAAA;AAOA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AAGA;AAGA;AAAA;AACA;AAGA;AAAA;AAEA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAOA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAIA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAIA;AACA;AACA;AAAA;AAKA;AACA;AAMA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAIA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAGA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAOA;AAGA;AAGA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AAIA;AAGA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AACA;AAEA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAIA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAaA;AACA;AACA;AACA;AACA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AAMA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAIA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgCA;;;;;;;;;;;;;;;;;ACvjBA;AAEA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAOA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA;AAAA;AAAA;AAAA;AAMA;AAAA;AAAA;AAAA;AAAA;AAKA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;AClKA;AACA;AAEA;AACA;AAEA;AAAA;AAkBA;AAJA;AALA;AAWA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAGA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAOA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;;;;;;;;;;;;;;;;ACzLA;AACA;AACA;AACA;AAHA;AAAA;AAKA;;;;;;;;;;;;;;;;;;;ACLA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;ACxDA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAMA;AACA;AACA;AACA;AAAA;AAEA;AAMA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;;;;;;;;;;;;;;;;AC/DA;AACA;AACA;AACA;AACA;AAJA;AAAA;AAMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACNA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAqBA;AACA;AACA;AACA;AAgBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAIA;AAIA;AAEA;AACA;AAqHA;;;;;;;;;;;;;;;;;;AC1OA;AACA;AAGA;AAAA;AAEA;AAAA;AAEA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;AAEA;AAIA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;;;;;;;;;;;;;;;;;;;AC7CA;AACA;AACA;AAGA;AAAA;AAAA;AAKA;AAAA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAKA;AACA;AACA;AACA;AACA;AAEA;AAIA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAKA;AACA;AACA;AAAA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClDA;AAOA;AAKA;AAGA;AACA;AACA;AAOA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAYA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAvFA;AAuGA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AAGA;AAAA;AAEA;AAGA;AAAA;AAEA;AAGA;AAAA;AAEA;AAGA;AAAA;AAIA;AAGA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AA7KA;AAqLA;AAEA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AAAA;AAEA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA3MA;AAoNA;AAEA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AAAA;AAEA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7QA;AAEA;AACA;AAEA;AAEA;AAMA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAAA;AAAA;AAEA;AAIA;AAAA;AAAA;AAAA;AAWA;AAAA;AACA;AAIA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAKA;AAEA;AAAA;AACA;AAOA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsBA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWA;AAAA;AACA;AAGA;AACA;AAEA;AAAA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAMA;AAAA;AAEA;AACA;AAEA;AAAA;AACA;AAGA;AAEA;AACA;AAAA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AAGA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAAA;AACA;AAGA;AAEA;AAEA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAvRA;AA0RA;AACA;AAEA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAmBA;AAAA;AAGA;AACA;AACA;AAAA;AAmBA;AAAA;AAGA;AAAA;AACA;AAQA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAKA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AA3eA;AA8eA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AAGA;AAAA;AAEA;AAQA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAtiBA;AAyiBA;AACA;AACA;AAAA;AAEA;AAMA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAzjBA;AA6jBA;AAIA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AA1kBA;AA+kBA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAGA;AAEA;AAAA;AAEA;AAvjBA;AAAA;AADA;AAzCA;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AAHA;AAAA;AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACLA;AAEA;AAEA;AACA;AAGA;AAGA;AAAA;AAAA;AAeA;AAHA;AACA;AAVA;AACA;AAYA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AAEA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAIA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AAEA;AAEA;AAEA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAQA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AA/NA;AAAA;AADA;AAaA;AACA;AAxBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AAOA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAUA;AANA;AACA;AACA;AACA;AACA;AAPA;AACA;AAAA;AASA;AAGA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAGA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAIA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AAGA;AAAA;AAOA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAEA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAIA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AASA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAMA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAIA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AACA;AAGA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAMA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAIA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAGA;AAAA;AAEA;AA3fA;AAAA;AADA;AAKA;AACA;AACA;AACA;AACA;AA3BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AAEA;AAKA;AAAA;AAOA;AAHA;AACA;AAJA;AAAA;AAOA;AAGA;AACA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AAEA;AAEA;AAAA;AAIA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AA3IA;AAAA;AADA;AAKA;AACA;AAdA;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AAEA;AAEA;AAEA;AAAA;AAAA;AAwGA;AAHA;AACA;AArGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAcA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAAA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AASA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AAAA;AAKA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAEA;AAAA;AAIA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAIA;AACA;AAAA;AAIA;AACA;AAEA;AAEA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AACA;AAIA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAAA;AAIA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAAA;AAIA;AAEA;AACA;AACA;AAAA;AAEA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAIA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAIA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AAAA;AACA;AAAA;AAIA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAKA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AAOA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AAYA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAGA;AAEA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAYA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AACA;AAOA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AACA;AAOA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAIA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAOA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAIA;AAAA;AACA;AAGA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC3oBA;AACA;AAIA;AAAA;AAIA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAKA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAIA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAnDA;AAAA;AADA;AAKA;AATA;;;;;;;;;;;;;;;;;ACAA;AAGA;AAAA;AAeA;AAHA;AACA;AAIA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAGA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;ACpLA;AACA;AACA;AACA;AAIA;AAAA;AA+BA;AALA;AACA;AACA;AACA;AA5BA;AACA;AAUA;AACA;AACA;AAMA;AAYA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAEA;AAAA;AACA;AAnGA;AAsGA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AAEA;AAKA;AACA;AACA;AAEA;AAIA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AAIA;AAAA;AACA;AAGA;AACA;AAEA;AAEA;AACA;AACA;AAKA;AAEA;AAGA;AACA;AACA;AAGA;AAGA;AACA;AAAA;AAIA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAKA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AAEA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAKA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;;;ACzbA;AAKA;AAEA;AAAA;AA2BA;AALA;AACA;AACA;AACA;AAbA;AAOA;AAUA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AAEA;AAAA;AAEA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAIA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AAEA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAIA;AAGA;AACA;AAGA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAMA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;;ACxSA;AAEA;AAAA;AAUA;AADA;AAGA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxDA;AACA;AACA;AACA;AAGA;AAAA;AAQA;AAHA;AACA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAGA;AAGA;AAGA;AAGA;AAGA;AAGA;AAGA;AAAA;AACA;AAGA;AAGA;AAAA;AACA;AAAA;AAKA;AACA;AACA;AACA;AAGA;AACA;AACA;AAGA;AACA;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAGA;AACA;AAGA;AAAA;AACA;AAAA;AAKA;AACA;AACA;AACA;AAGA;AACA;AACA;AAGA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAEA;AAEA;AAGA;AACA;AAGA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAIA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAGA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAGA;AAGA;AAAA;AACA;AAAA;AAIA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AACA;AAGA;AAAA;AAIA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAIA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AA3bA;AA4bA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AACA;AAGA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AACA;AAGA;AACA;AACA;AAGA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AAGA;AAGA;AACA;AAGA;AAAA;AACA;AAAA;AAKA;AACA;AACA;AAAA;AAIA;AACA;AACA;AACA;AAGA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAIA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAIA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAIA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAGA;AAGA;AACA;AAAA;AACA;AAAA;AAKA;AAEA;AACA;AAAA;AAIA;AACA;AACA;AACA;AAGA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAGA;AACA;AAGA;AAGA;AAAA;AACA;AAAA;AAKA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAKA;AACA;AACA;AACA;AACA;AAEA;AAGA;AACA;AACA;AACA;AAAA;AAIA;AAEA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAWA;AAGA;AACA;AAGA;AACA;AAGA;AACA;AACA;AACA;AAKA;AAEA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAKA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAWA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAIA;AACA;AAAA;AAEA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAMA;AAGA;AAIA;AAAA;AACA;AAGA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC57BA;AACA;AACA;AACA;AAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBA;AAHA;AACA;AAXA;AA8bA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAtcA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAAA;AACA;AA3HA;AA8HA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAKA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAKA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AA1RA;AAgSA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAKA;AA1VA;AA2VA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAGA;AAEA;AAAA;AAGA;AAGA;AAIA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAMA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AAiCA;;;;;;;;;;;;;;;;;ACreA;AAEA;AAAA;AAQA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;;AC9CA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AASA;AACA;AACA;AACA;AACA;AAOA;AAAA;AACA;AAGA;AACA;AACA;AAuBA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AA3HA;AA6HA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;ACtJA;AACA;AACA;AAGA;AAAA;AALA;AAyFA;AA9EA;AAwDA;AAAA;AACA;AAuBA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AASA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAKA;AAAA;AAEA;AAEA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAYA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;ACxbA;AACA;AACA;AACA;AAHA;AAAA;AAMA;;;;;;;;;;;;;;;;;;ACNA;AACA;AAGA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAEA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;ACxDA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;AC5BA;AAAA;AAiBA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;;AC7CA;AAEA;AAAA;AAIA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACRA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAoBA;AAHA;AACA;AAjBA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAcA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAOA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAMA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AAzMA;AA+MA;AACA;AACA;AAAA;AAIA;AACA;AAAA;AAIA;AACA;AAAA;AAIA;AACA;AAAA;AAGA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;;;;;;;;;;;;;;;;AClQA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;ACRA;AACA;AACA;AAEA;AAAA;AAIA;AAAA;AACA;AAKA;AACA;AAAA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAEA;AAAA;AACA;AACA;AAEA;AAEA;AAAA;AAEA;AAAA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChEA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AAYA;AAiBA;AACA;AACA;AACA;AAKA;AAmDA;AACA;AAnGA;AAgJA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAMA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAaA;AA4BA;AAMA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AAKA;AACA;AACA;AAIA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAMA;AAEA;AACA;AAAA;AAQA;AACA;AACA;AACA;AAAA;AAEA;AAIA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAcA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAOA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAOA;AAEA;AACA;AAAA;AAEA;AAIA;AACA;AAAA;AAEA;AAAA;AAIA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAIA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAIA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AAIA;AACA;AAAA;AAEA;AACA;AAGA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAIA;AAIA;AACA;AAEA;AACA;AACA;AAAA;AAIA;AAGA;AAAA;AAEA;AACA;AAKA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AAAA;AAIA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AArjBA;AAwjBA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAIA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AASA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AAh4BA;AAAA;AADA;AANA;;;;;;;;;;;;;;;;ACAA;AAAA;AAcA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAAA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;AChEA;AACA;AACA;AAFA;AAAA;AAIA;;;;;;;;;;;;;;;;;ACJA;AAEA;AAAA;AAMA;AAHA;AAAA;AAIA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;AC3BA;AAAA;AAOA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAKA;AACA;AAAA;AACA;AAGA;AAOA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;AC1DA;AACA;AACA;AACA;AACA;AAJA;AAAA;AAMA;;;;;;;;;;;;;;;;;ACNA;AAEA;AAAA;AAuBA;AAtBA;AAuBA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;AC5IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA1BA;AAAA;AA4BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC5BA;AACA;AAQA;AAAA;AAWA;AACA;AAXA;AAIA;AAAA;AAAA;AACA;AACA;AACA;AAMA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYA;AACA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AAEA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAMA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAMA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAIA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAIA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAMA;AAAA;AAMA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAMA;AAAA;AAMA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AAMA;AACA;AAAA;AAEA;AAAA;AAEA;AAGA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAIA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AAAA;AACA;AAIA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAlcA;AAycA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAGA;AAEA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAKA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAIA;AAEA;AAIA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAIA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AAIA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AAIA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AAEA;AApjBA;AAAA;AADA;AAYA;AACA;AArBA;;;;;;;;;;;;;;;;;;ACAA;AACA;AAEA;AAAA;AAIA;AAKA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvBA;AASA;AAEA;AAKA;AACA;AAKA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAIA;AAAA;AACA;AACA;AAKA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAGA;AAGA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAEA;AAGA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAEA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAGA;AACA;AAAA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AAAA;AAOA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAeA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAGA;AAAA;AAGA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAIA;AAAA;AAAA;AACA;AACA;AAIA;AAAA;AAIA;AACA;AACA;AACA;AAKA;AAAA;AAAA;AAOA;AAAA;AAKA;AACA;AACA;AACA;AAIA;AAAA;AAIA;AACA;AAIA;AAAA;AAGA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAGA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAWA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAKA;AAAA;AAAA;AAAA;AAAA;AAMA;AAKA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAAA;AAMA;AAAA;AAGA;AAAA;AAGA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAOA;AAEA;AAAA;AASA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAIA;AACA;AACA;AACA;AAGA;AAGA;AAAA;AACA;AAAA;AACA;AACA;AAKA;AAGA;AAAA;AAAA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AAEA;AAWA;AAAA;AACA;AACA;AAGA;AAAA;AAGA;AAAA;AACA;AAGA;AAAA;AAAA;AAAA;AApBA;AACA;AACA;AACA;AAAA;AACA;AACA;AAgBA;AArdA;AAAA;AADA;AAtBA;;;;;;;;;;;;;;;;;ACAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;AChBA;AACA;AACA;AACA;AAHA;AAAA;AAMA;;;;;;;;;;;;;;;;ACNA;AACA;AACA;AACA;AACA;AAJA;AAAA;AAOA;;;;;;;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAjEA;AAAA;AAmEA;;;;;;;;;;;;;;;;ACnEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AAEA;AAEA;AAlBA;AAAA;AAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrBA;AACA;AACA;AAGA;AACA;AACA;AAIA;AAAA;AAOA;AAJA;AACA;AACA;AAJA;AAOA;AACA;AAAA;AACA;AAMA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAIA;AAEA;AAGA;AAEA;AAMA;AACA;AAEA;AAAA;AAEA;AAEA;AAAA;AAEA;AAAA;AACA;AAIA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AAGA;AAIA;AAKA;AAAA;AAIA;AAAA;AAEA;AAIA;AAAA;AACA;AAGA;AAKA;AACA;AAAA;AAGA;AAIA;AAAA;AACA;AAIA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAOA;AACA;AAAA;AAEA;AAIA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAEA;AA7NA;AAAA;AADA;AAIA;AACA;AACA;AAhBA;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAKA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAGA;AAEA;AAEA;AACA;AAGA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAzGA;AAAA;AA4GA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1GA;AAAA;AAeA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAzBA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAkBA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;AClFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AARA;AAAA;AAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;AACA;AACA;AACA;AACA;AAIA;AAEA;AACA;AAGA;AAAA;AAmBA;AAJA;AACA;AACA;AAhBA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAUA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAEA;AAEA;AAAA;AAGA;AAEA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AAMA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AAKA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAKA;AACA;AACA;AAEA;AACA;AAMA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAIA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAEA;AA9NA;AAAA;AADA;AAgBA;AACA;AACA;AA/BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAIA;AAGA;AAAA;AAMA;AAJA;AACA;AACA;AAGA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0BA;AArCA;AAAA;AADA;AAGA;AACA;AACA;AAXA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AAEA;AAIA;AAAA;AAIA;AADA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAKA;AAAA;AAEA;AAAA;AACA;AAKA;AAAA;AAEA;AA/CA;AAAA;AADA;AAIA;AAXA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAGA;AAAA;AA0IA;AAHA;AACA;AAvIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAAA;AAcA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAAA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAKA;AAAA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAYA;AAEA;AACA;AACA;AACA;AACA;AACA;AAmZA;AAAA;AA5YA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AAAA;AAKA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAEA;AAAA;AAIA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAIA;AACA;AAAA;AAIA;AACA;AAEA;AAEA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAMA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAIA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAIA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAAA;AAIA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAIA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AACA;AAOA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AAAA;AACA;AAOA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAniBA;AA0iBA;AAIA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAAA;AAEA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAIA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AACA;AAKA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AAKA;AACA;AAAA;AAEA;AAEA;AAAA;AAEA;AAAA;AACA;AAMA;AAntBA;AAotBA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAIA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AAEA;AAAA;AAEA;AAAA;AACA;AAKA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AArzBA;AAuzBA;AAAA;AACA;AAGA;AAAA;AA3zBA;AA6zBA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AAr0BA;AAu0BA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AAh2BA;AAk2BA;AAAA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AAEA;AAEA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AAz+BA;AA2+BA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AAAA;AAt/BA;AAu/BA;AAAA;AAAA;AAEA;AAz/BA;AAy/BA;AAAA;AACA;AAAA;AA1/BA;AA2/BA;AAAA;AAAA;AAEA;AA7/BA;AA6/BA;AAAA;AACA;AAAA;AA9/BA;AA+/BA;AAAA;AAAA;AAEA;AAAA;AAjgCA;AAkgCA;AAAA;AAAA;AAGA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAIA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAIA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AAAA;AAEA;AACA;AAGA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAIA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAIA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAWA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAIA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAIA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAKA;AAAA;AAhmDA;AAkmDA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAEA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAIA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AAGA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AAKA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AAxwDA;AA0wDA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AA7yDA;AA+yDA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AAl2DA;AAo2DA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AAAA;AACA;AAEA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AAAA;AA5+DA;AA8+DA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AAIA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AACA;AAMA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAOA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAYA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AAYA;AAAA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAOA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AAKA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AAv+EA;AAy+EA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AA5hFA;AA8hFA;AAMA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AAAA;AACA;AAEA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AASA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AAAA;AAjrFA;AAmrFA;AAKA;AAAA;AACA;AAGA;AAAA;AA5rFA;AA8rFA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AAKA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AA1wFA;AA4wFA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AAEA;AAGA;AAGA;AAAA;AACA;AAAA;AAKA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AA92FA;AAi3FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAIA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAKA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAl6FA;AAq6FA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAIA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAEA;AAAA;AACA;AAAA;AAKA;AAEA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAMA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AAAA;AAEA;AACA;AACA;AAOA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AApvGA;AAuvGA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAIA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAnyGA;AA6yGA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAGA;AACA;AACA;AAAA;AAIA;AACA;AAAA;AAKA;AACA;AAAA;AACA;AAKA;AACA;AAAA;AACA;AAIA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAAA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAKA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAMA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAEA;AAAA;AACA;AAAA;AAGA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAt6GA;AAAA;AAwHA;AAAA;AAxHA;AAAA;AAAA;AAAA;AAhBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AAGA;AAMA;AAAA;AAaA;AANA;AACA;AACA;AACA;AACA;AAPA;AAAA;AAYA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAGA;AAGA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AAIA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAKA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AACA;AAGA;AAGA;AACA;AAAA;AACA;AAEA;AAGA;AAAA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAGA;AAIA;AAAA;AAEA;AArLA;AAAA;AADA;AAQA;AACA;AACA;AACA;AACA;AAvBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAIA;AACA;AAGA;AAAA;AAmBA;AAJA;AACA;AACA;AAbA;AACA;AACA;AACA;AACA;AAYA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAnCA;AAAA;AACA;AAqCA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAGA;AAEA;AAGA;AACA;AAEA;AACA;AAIA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAxIA;AA2IA;AAGA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAIA;AAAA;AACA;AAAA;AApKA;AAwKA;AAAA;AACA;AAzKA;AA4KA;AAAA;AACA;AAGA;AAAA;AACA;AAjLA;AAqLA;AAAA;AACA;AAGA;AAAA;AACA;AA1LA;AA6LA;AAGA;AAEA;AAlMA;AAqMA;AAAA;AACA;AAtMA;AAyMA;AAEA;AACA;AA5MA;AA+MA;AAKA;AAAA;AACA;AAGA;AACA;AAIA;AAAA;AAEA;AAAA;AACA;AAhOA;AAkOA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAKA;AAAA;AACA;AAEA;AAEA;AACA;AAEA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAIA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAGA;AAEA;AACA;AAEA;AAAA;AAGA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AAGA;AA5SA;AA6SA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAAA;AAEA;AApUA;AAAA;AADA;AAgBA;AACA;AACA;AAjCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AAIA;AAAA;AAEA;AADA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAEA;AA1BA;AAAA;AADA;AAEA;AAPA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AAEA;AACA;AACA;AACA;AACA;AAKA;AAAA;AAKA;AAHA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAKA;AAGA;AACA;AAEA;AACA;AAAA;AAEA;AAEA;AAGA;AACA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAEA;AApEA;AAAA;AADA;AAGA;AACA;AAdA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACEA;AAEA;AAAA;AAqBA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAlCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAmBA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;ACpDA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AAEA;;;;;;;;;;;;;;;;ACtFA;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAZA;AAAA;AAcA;;;;;;;;;;;;;;;;;;;ACdA;AACA;AACA;AAIA;AAAA;AASA;AAHA;AACA;AAJA;AAQA;AACA;AAIA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AAIA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;ACpEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAjCA;AAAA;AAmCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AAmIA;AAlIA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AAMA;AAGA;AAAA;AACA;AACA;AAKA;AAAA;AACA;AAMA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAUA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAEA;AAAA;AAAA;AAIA;AAAA;AAAA;AAGA;AAAA;AACA;AAGA;AAAA;AAEA;AAGA;AAAA;AACA;AAKA;AAAA;AAAA;AAGA;AAAA;AACA;AAGA;AAAA;AAQA;AAAA;AAEA;AACA;AAEA;AAIA;AAEA;AAEA;AAEA;AAEA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAtGA;AAAA;AACA;AAGA;AAAA;AACA;AAoGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpOA;AACA;AAEA;AAEA;AACA;AA+DA;AAAA;AA9DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAcA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAcA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxGA;AAQA;AAEA;AAEA;AACA;AA2IA;AAAA;AA1IA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAaA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAaA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAaA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAcA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAaA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAeA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAcA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAcA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAaA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAaA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAoBA;AAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAqCA;AAAA;AAlCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAqCA;AAAA;AAlCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpXA;AAOA;AACA;AAGA;AAEA;AAIA;AAQA;AAAA;AAPA;AACA;AACA;AACA;AACA;AACA;AACA;AAsBA;AAAA;AAlBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA4BA;AAAA;AAzBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAeA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAcA;AAAA;AAVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvGA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AAuUA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AA9VA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA6JA;AAAA;AA1JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA6JA;AAAA;AA1JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAyCA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrXA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AAuUA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AA9VA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA6JA;AAAA;AA1JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA6JA;AAAA;AA1JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAyCA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC3WA;AAEA;AAEA;AAEA;AACA;AASA;AAAA;AARA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAqCA;AAAA;AAlCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAGA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxEA;AACA;AAEA;AAEA;AACA;AASA;AAAA;AARA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnBA;AAMA;AAEA;AAEA;AAIA;AAaA;AAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAsCA;AAAA;AAlCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAqCA;AAAA;AAlCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxGA;AAEA;AACA;AAEA;AACA;AAAA;AAqDA;AAAA;AAAA;AAFA;AAAA;AAlDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9DA;AAUA;AACA;AAMA;AAEA;AACA;AAAA;AAutBA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AArtBA;AAAA;AAtBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAsXA;AAAA;AAnXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAsKA;AAAA;AAnKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAqKA;AAAA;AAlKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAgNA;AAAA;AAtLA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAuCA;AAAA;AApCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAoBA;AAAA;AAjBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAYA;AAAA;AARA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC//BA;AAEA;AAEA;AAEA;AACA;AA+DA;AAAA;AA9DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzEA;AAGA;AAEA;AACA;AAYA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAcA;AAAA;AAXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClCA;AAIA;AAEA;AACA;AAKA;AAAA;AAJA;AACA;AACA;AACA;AAQA;AAAA;AALA;AACA;AACA;AACA;AACA;AAGA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACZA;AAEA;AACA;AAOA;AAAA;AACA;AACA;AAEA;AAYA;AAIA;AACA;AACA;AAEA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AAEA;AAQA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAKA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAGA;AACA;AAEA;AACA;AAGA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAMA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwDA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2GA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAMA;AAAA;AAAA;AA3oCA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAioCA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAYA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAMA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AA11CA;AA61CA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAOA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAviDA;AA0iDA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AAAA;AACA;AAKA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAIA;AAAA;AACA;AAGA;AAAA;AACA;AAGA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AAAA;AAEA;AAhmDA;AAAA;AADA;AAnBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAKA;AAEA;AAAA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAIA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAKA;AACA;AACA;AAAA;AAAA;AAAA;AAIA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AA5IA;AAAA;AADA;AAhCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAaA;AAZA;AACA;AAYA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAGA;AAAA;AACA;AACA;AApDA;AAuDA;AACA;AACA;AAAA;AACA;AACA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AAGA;AA1EA;AA4EA;AAAA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AAEA;AAIA;AAAA;AACA;AACA;AACA;AAGA;AAGA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AAGA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAKA;AAAA;AACA;AACA;AACA;AACA;AA2BA;AAAA;AAEA;AAAA;AAGA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAGA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAGA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AAAA;AACA;AACA;AA1SA;AA6SA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAhWA;AAmWA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AAGA;AAAA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AAEA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAIA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAEA;AAEA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAGA;AACA;AAAA;AAGA;AAAA;AAGA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AAEA;AAKA;AAIA;AAIA;AACA;AAAA;AAEA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvgBA;AACA;AACA;AAIA;AAGA;AAAA;AAaA;AAZA;AACA;AACA;AACA;AAIA;AAGA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAIA;AAEA;AAEA;AAEA;AAAA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AArEA;AAwEA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAIA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAKA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAUA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AAEA;AAAA;AAEA;AAAA;AAQA;AAAA;AACA;AACA;AAGA;AAGA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAGA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AAAA;AAYA;AAGA;AACA;AACA;AAAA;AAEA;AAAA;AAEA;AAjQA;AAAA;AAFA;AACA;AAcA;AAtBA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;AC9LA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACpDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACpFA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;AC7BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;AC3BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;ACzBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;ACRA;AACA;AACA;AACA;AACA;;;;;ACJA;AACA;AACA;AACA;AACA;;;;;ACJA;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;ACPA;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;AC3CA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;ACNA;AACA;AACA;AACA;AACA;;;;;ACJA;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;AC1EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;AErFA;AACA;AACA;AACA;AACA","sources":["webpack://game-client-lerna/./packages/core/src/egt/core/Core.ts","webpack://game-client-lerna/./packages/client/src/egt/index.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/AutoplayPopupComponent.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/AutoplayPopupFactory.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/index.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/default/configuration/AutoplayPopupComponentConfigurationDefault.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/default/controllers/AutoplayPopupControllerDefault.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/default/subjects/AutoplayPopupSubjectsDefault.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/default/views/AutoplayPopupViewDefault.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/extended/buttons/AutoplayButtonStatesExtended.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/extended/buttons/AutoplayButtonTexturesExtended.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/extended/buttons/AutoplaySartButtonExtended.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/extended/buttons/AutoplaySettingButtonExtended.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/extended/configuration/AutoplayPopupComponentConfigurationExtended.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/extended/controllers/AutoplayPopupControllerExtended.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/extended/views/AutoplayPopupViewExtended.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/max-bet/buttons/AutoplayKeyboardActionButtonMaxBet.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/max-bet/buttons/AutoplayKeyboardButtonMaxBet.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/max-bet/buttons/AutoplayPopupButtonStatesMaxBet.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/max-bet/buttons/AutoplayPopupButtonTexturesMaxBet.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/max-bet/buttons/AutoplayPopupSettingButtonMaxBet.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/max-bet/buttons/AutoplayPopupStartButtonMaxBet.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/max-bet/configuration/AutoplayPopupComponentConfigurationMaxBet.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/max-bet/controllers/AutoplayPopupControllerMaxBet.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/max-bet/views/AutoplayPopupShadowViewMaxBet.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/max-bet/views/AutoplayPopupViewMaxBet.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/max-bet/views/KeyboardMaxBet.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/numeric/buttons/AutoplayPopupButtonStatesNumeric.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/numeric/buttons/AutoplayPopupButtonTexturesNumeric.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/numeric/buttons/AutoplayPopupSettingButtonNumeric.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/numeric/buttons/AutoplayPopupStartButtonNumeric.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/numeric/configuration/AutoplayPopupComponentConfigurationNumeric.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/numeric/controllers/AutoplayPopupControllerNumeric.ts","webpack://game-client-lerna/./packages/components/slot/autoplay-popup/src/egt/modes/numeric/views/AutoplayPopupViewNumeric.ts","webpack://game-client-lerna/./packages/components/slot/background/src/egt/BackgroundComponent.ts","webpack://game-client-lerna/./packages/components/slot/background/src/egt/BackgroundFactory.ts","webpack://game-client-lerna/./packages/components/slot/background/src/egt/common/views/BackgroundViewCommon.ts","webpack://game-client-lerna/./packages/components/slot/background/src/egt/index.ts","webpack://game-client-lerna/./packages/components/slot/background/src/egt/modes/blurred/configuration/BackgroundComponentConfigurationBlurred.ts","webpack://game-client-lerna/./packages/components/slot/background/src/egt/modes/default/configuration/BackgroundComponentConfigurationDefault.ts","webpack://game-client-lerna/./packages/components/slot/bet-buttons/src/egt/BetButtonsComponent.ts","webpack://game-client-lerna/./packages/components/slot/bet-buttons/src/egt/BetButtonsModeFactory.ts","webpack://game-client-lerna/./packages/components/slot/bet-buttons/src/egt/index.ts","webpack://game-client-lerna/./packages/components/slot/bet-buttons/src/egt/modes/default/configuration/BetButtonsComponentConfigurationDefault.ts","webpack://game-client-lerna/./packages/components/slot/bet-buttons/src/egt/modes/default/controllers/BetButtonsControllerDefault.ts","webpack://game-client-lerna/./packages/components/slot/bet-buttons/src/egt/modes/default/views/BetButtonsViewDefault.ts","webpack://game-client-lerna/./packages/components/slot/bet-buttons/src/egt/modes/one-denom/configuration/BetButtonsComponentConfigurationOneDenom.ts","webpack://game-client-lerna/./packages/components/slot/bet-buttons/src/egt/modes/one-denom/controllers/BetButtonsControllerOneDenom.ts","webpack://game-client-lerna/./packages/components/slot/bet-buttons/src/egt/modes/one-denom/views/BetButtonsViewOneDenom.ts","webpack://game-client-lerna/./packages/components/slot/bet-buttons/src/egt/modes/turtle/configuration/BetButtonsComponentConfigurationTurtle.ts","webpack://game-client-lerna/./packages/components/slot/bet-buttons/src/egt/modes/turtle/controllers/BetButtonsControllerTurtle.ts","webpack://game-client-lerna/./packages/components/slot/bet-buttons/src/egt/modes/turtle/views/BetButtonsViewTurtle.ts","webpack://game-client-lerna/./packages/components/slot/bet-calculator/src/egt/BetCalculatorComponent.ts","webpack://game-client-lerna/./packages/components/slot/bet-calculator/src/egt/BetCalculatorFactory.ts","webpack://game-client-lerna/./packages/components/slot/bet-calculator/src/egt/common/buttons/BetSettingButtonCommon.ts","webpack://game-client-lerna/./packages/components/slot/bet-calculator/src/egt/index.ts","webpack://game-client-lerna/./packages/components/slot/bet-calculator/src/egt/modes/default/configuration/BetCalculatorComponentConfigurationDefault.ts","webpack://game-client-lerna/./packages/components/slot/bet-calculator/src/egt/modes/default/controllers/BetCalculatorControllerDefault.ts","webpack://game-client-lerna/./packages/components/slot/bet-calculator/src/egt/modes/default/views/BetCalculatorViewDefault.ts","webpack://game-client-lerna/./packages/components/slot/bet-calculator/src/egt/modes/turtle/configuration/BetCalculatorComponentConfigurationTurtle.ts","webpack://game-client-lerna/./packages/components/slot/bet-calculator/src/egt/modes/turtle/controllers/BetCalculatorControllerTurtle.ts","webpack://game-client-lerna/./packages/components/slot/bet-calculator/src/egt/modes/turtle/views/BetCalculatorViewTurtle.ts","webpack://game-client-lerna/./packages/components/slot/bg-animation/src/egt/BackgroundAnimationComponent.ts","webpack://game-client-lerna/./packages/components/slot/bg-animation/src/egt/BackgroundAnimationModeFactory.ts","webpack://game-client-lerna/./packages/components/slot/bg-animation/src/egt/index.ts","webpack://game-client-lerna/./packages/components/slot/bg-animation/src/egt/modes/default/configuration/BackgroundAnimationComponentConfigurationDefault.ts","webpack://game-client-lerna/./packages/components/slot/bg-animation/src/egt/modes/default/views/BackgroundAnimationViewDefault.ts","webpack://game-client-lerna/./packages/components/slot/bg-animation/src/egt/modes/desktopForLandscape/configuration/BackgroundAnimationComponentConfigurationDesktopForLandscape.ts","webpack://game-client-lerna/./packages/components/slot/buy-bonus/src/egt/BuyBonusComponent.ts","webpack://game-client-lerna/./packages/components/slot/buy-bonus/src/egt/BuyBonusModeFactory.ts","webpack://game-client-lerna/./packages/components/slot/buy-bonus/src/egt/common/double-chance/configuration/DoubleChanceComponentConfigurationCommon.ts","webpack://game-client-lerna/./packages/components/slot/buy-bonus/src/egt/common/double-chance/controllers/DoubleChanceControllerCommon.ts","webpack://game-client-lerna/./packages/components/slot/buy-bonus/src/egt/common/double-chance/views/DoubleChanceViewCommon.ts","webpack://game-client-lerna/./packages/components/slot/buy-bonus/src/egt/index.ts","webpack://game-client-lerna/./packages/components/slot/buy-bonus/src/egt/modes/default/configuration/BuyBonusComponentConfigurationDefault.ts","webpack://game-client-lerna/./packages/components/slot/buy-bonus/src/egt/modes/default/controllers/BuyBonusControllerDefault.ts","webpack://game-client-lerna/./packages/components/slot/buy-bonus/src/egt/modes/default/views/BuyBonusViewDefault.ts","webpack://game-client-lerna/./packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/configuration/BuyBonusComponentConfigurationExtendedMultipleBuyBonus.ts","webpack://game-client-lerna/./packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/controllers/BuyBonusControllerExtendedMultipleBuyBonus.ts","webpack://game-client-lerna/./packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/data/BannerData.ts","webpack://game-client-lerna/./packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/data/ExtendedMultipleBuyBonusContext.ts","webpack://game-client-lerna/./packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus.ts","webpack://game-client-lerna/./packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/ExtendedMultipleBuyBonusBanner.ts","webpack://game-client-lerna/./packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/ExtendedMultipleBuyBonusBetControl.ts","webpack://game-client-lerna/./packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/ExtendedMultipleBuyBonusInfoText.ts","webpack://game-client-lerna/./packages/components/slot/buy-bonus/src/egt/modes/multiple-buy-bonus/configuration/BuyBonusComponentConfigurationMultipleBuyBonus.ts","webpack://game-client-lerna/./packages/components/slot/buy-bonus/src/egt/modes/multiple-buy-bonus/controllers/BuyBonusControllerMultipleBuyBonus.ts","webpack://game-client-lerna/./packages/components/slot/buy-bonus/src/egt/modes/multiple-buy-bonus/views/BuyBonusViewMultipleBuyBonus.ts","webpack://game-client-lerna/./packages/components/slot/clock/src/egt/ClockComponent.ts","webpack://game-client-lerna/./packages/components/slot/clock/src/egt/ClockFactory.ts","webpack://game-client-lerna/./packages/components/slot/clock/src/egt/index.ts","webpack://game-client-lerna/./packages/components/slot/clock/src/egt/modes/default/configuration/ClockComponentConfigurationDefault.ts","webpack://game-client-lerna/./packages/components/slot/clock/src/egt/modes/default/views/ClockViewDefault.ts","webpack://game-client-lerna/./packages/components/slot/denomination-popup/src/egt/DenominationPopupComponent.ts","webpack://game-client-lerna/./packages/components/slot/denomination-popup/src/egt/DenominationPopupFactory.ts","webpack://game-client-lerna/./packages/components/slot/denomination-popup/src/egt/index.ts","webpack://game-client-lerna/./packages/components/slot/denomination-popup/src/egt/modes/default/configuration/DenominationPopupComponentConfigurationDefault.ts","webpack://game-client-lerna/./packages/components/slot/denomination-popup/src/egt/modes/default/controllers/DenominationPopupControllerDefault.ts","webpack://game-client-lerna/./packages/components/slot/denomination-popup/src/egt/modes/default/subjects/DenominationPopupSubjectsDefault.ts","webpack://game-client-lerna/./packages/components/slot/denomination-popup/src/egt/modes/default/views/DenominationPopupViewDefault.ts","webpack://game-client-lerna/./packages/components/slot/denomination-popup/src/egt/modes/extended/configuration/DenominationPopupComponentConfigurationExtended.ts","webpack://game-client-lerna/./packages/components/slot/denomination-popup/src/egt/modes/extended/controllers/DenominationPopupControllerExtended.ts","webpack://game-client-lerna/./packages/components/slot/denomination-popup/src/egt/modes/extended/views/DenominationPopupViewExtended.ts","webpack://game-client-lerna/./packages/components/slot/denomination-popup/src/egt/modes/max-bet/configuration/DenominationPopupComponentConfigurationMaxBet.ts","webpack://game-client-lerna/./packages/components/slot/denomination-popup/src/egt/modes/max-bet/controllers/DenominationPopupControllerMaxBet.ts","webpack://game-client-lerna/./packages/components/slot/denomination-popup/src/egt/modes/max-bet/views/DenominationPopupShadowViewMaxBet.ts","webpack://game-client-lerna/./packages/components/slot/denomination-popup/src/egt/modes/max-bet/views/DenominationPopupViewMaxBet.ts","webpack://game-client-lerna/./packages/components/slot/footer-background/src/egt/FooterBackgroundComponent.ts","webpack://game-client-lerna/./packages/components/slot/footer-background/src/egt/FooterBackgroundFactory.ts","webpack://game-client-lerna/./packages/components/slot/footer-background/src/egt/index.ts","webpack://game-client-lerna/./packages/components/slot/footer-background/src/egt/modes/blurred/configuration/FooterBackgroundComponentConfigurationBlurred.ts","webpack://game-client-lerna/./packages/components/slot/footer-background/src/egt/modes/blurred/views/FooterBGAnimationViewBlurred.ts","webpack://game-client-lerna/./packages/components/slot/footer-background/src/egt/modes/blurred/views/FooterBackgroundViewBlurred.ts","webpack://game-client-lerna/./packages/components/slot/footer-background/src/egt/modes/blurred/views/FooterDarknessViewBlurred.ts","webpack://game-client-lerna/./packages/components/slot/footer-background/src/egt/modes/default/configuration/FooterBackgroundComponentConfigurationDefault.ts","webpack://game-client-lerna/./packages/components/slot/footer-background/src/egt/modes/default/interfaces/InterfacesDefault.ts","webpack://game-client-lerna/./packages/components/slot/footer-background/src/egt/modes/default/views/FooterBackgroundViewDefault.ts","webpack://game-client-lerna/./packages/components/slot/footer-background/src/egt/modes/sided/configuration/FooterBackgroundComponentConfigurationSided.ts","webpack://game-client-lerna/./packages/components/slot/footer-background/src/egt/modes/sided/view/FooterBackgroundViewSided.ts","webpack://game-client-lerna/./packages/components/slot/home-button/src/egt/HomeButtonComponent.ts","webpack://game-client-lerna/./packages/components/slot/home-button/src/egt/HomeButtonFactory.ts","webpack://game-client-lerna/./packages/components/slot/home-button/src/egt/index.ts","webpack://game-client-lerna/./packages/components/slot/home-button/src/egt/modes/blurred/configuration/HomeButtonComponentConfigurationBlurred.ts","webpack://game-client-lerna/./packages/components/slot/home-button/src/egt/modes/default/configuration/HomeButtonComponentConfigurationDefault.ts","webpack://game-client-lerna/./packages/components/slot/home-button/src/egt/modes/default/controllers/HomeButtonControllerDefault.ts","webpack://game-client-lerna/./packages/components/slot/home-button/src/egt/modes/default/views/HomeButtonViewDefault.ts","webpack://game-client-lerna/./packages/components/slot/home-button/src/egt/modes/sided/configuration/HomeButtonComponentConfigurationSided.ts","webpack://game-client-lerna/./packages/components/slot/reels/src/egt/ReelsComponent.ts","webpack://game-client-lerna/./packages/components/slot/reels/src/egt/ReelsModeFactory.ts","webpack://game-client-lerna/./packages/components/slot/reels/src/egt/index.ts","webpack://game-client-lerna/./packages/components/slot/reels/src/egt/modes/default/configuration/ReelsComponentConfigurationDefault.ts","webpack://game-client-lerna/./packages/components/slot/reels/src/egt/modes/default/controllers/ReelsControllerDefault.ts","webpack://game-client-lerna/./packages/components/slot/reels/src/egt/modes/default/enums/ReelStateDefault.ts","webpack://game-client-lerna/./packages/components/slot/reels/src/egt/modes/default/views/ReelDefault.ts","webpack://game-client-lerna/./packages/components/slot/reels/src/egt/modes/default/views/ReelsViewDefault.ts","webpack://game-client-lerna/./packages/components/slot/reels/src/egt/modes/default/views/ReelsViewDesktopDefault.ts","webpack://game-client-lerna/./packages/components/slot/reels/src/egt/modes/desktopForLandscape/configuration/ReelsComponentConfigurationDesktopForLandscape.ts","webpack://game-client-lerna/./packages/components/slot/reels/src/egt/modes/desktopForLandscape/controllers/ReelsControllerDesktopForLandscape.ts","webpack://game-client-lerna/./packages/components/slot/reels/src/egt/modes/desktopForLandscape/enums/ReelStateDesktopForLandscape.ts","webpack://game-client-lerna/./packages/components/slot/reels/src/egt/modes/desktopForLandscape/views/ReelDesktopForLandscape.ts","webpack://game-client-lerna/./packages/components/slot/reels/src/egt/modes/desktopForLandscape/views/ReelsViewDesktopDesktopForLandscape.ts","webpack://game-client-lerna/./packages/components/slot/reels/src/egt/modes/desktopForLandscape/views/ReelsViewDesktopForLandscape.ts","webpack://game-client-lerna/./packages/components/slot/ui-main-panel/src/egt/UIMainPanelComponent.ts","webpack://game-client-lerna/./packages/components/slot/ui-main-panel/src/egt/UIMainPanelFactory.ts","webpack://game-client-lerna/./packages/components/slot/ui-main-panel/src/egt/index.ts","webpack://game-client-lerna/./packages/components/slot/ui-main-panel/src/egt/modes/blurred/configuration/UIMainPanelComponentConfigurationBlurred.ts","webpack://game-client-lerna/./packages/components/slot/ui-main-panel/src/egt/modes/blurred/views/UIMainPanelViewBlurred.ts","webpack://game-client-lerna/./packages/components/slot/ui-main-panel/src/egt/modes/default/configuration/UIMainPanelComponentConfigurationDefault.ts","webpack://game-client-lerna/./packages/components/slot/ui-main-panel/src/egt/modes/default/controllers/UIMainPanelControllerDefault.ts","webpack://game-client-lerna/./packages/components/slot/ui-main-panel/src/egt/modes/default/controllers/UIMainPanelControllerDesktopDefault.ts","webpack://game-client-lerna/./packages/components/slot/ui-main-panel/src/egt/modes/default/views/UIMainPanelViewDefault.ts","webpack://game-client-lerna/./packages/components/slot/ui-main-panel/src/egt/modes/sided/configuration/UIMainPanelComponentConfigurationSided.ts","webpack://game-client-lerna/./packages/components/slot/ui-view/src/egt/UIViewComponent.ts","webpack://game-client-lerna/./packages/components/slot/ui-view/src/egt/UIViewFactory.ts","webpack://game-client-lerna/./packages/components/slot/ui-view/src/egt/index.ts","webpack://game-client-lerna/./packages/components/slot/ui-view/src/egt/modes/default/configuration/UIViewComponentConfigurationDefault.ts","webpack://game-client-lerna/./packages/components/slot/ui-view/src/egt/modes/default/controllers/UIViewAutoPlayControllerDefault.ts","webpack://game-client-lerna/./packages/components/slot/ui-view/src/egt/modes/default/controllers/UIViewManualControllerDefault.ts","webpack://game-client-lerna/./packages/components/slot/ui-view/src/egt/modes/default/views/UIViewDefault.ts","webpack://game-client-lerna/./packages/components/slot/ui-view/src/egt/modes/turtle/configuration/UIViewComponentConfigurationTurtle.ts","webpack://game-client-lerna/./packages/components/slot/ui-view/src/egt/modes/turtle/controllers/UIViewAutoPlayControllerTurtle.ts","webpack://game-client-lerna/./packages/components/slot/ui-view/src/egt/modes/turtle/controllers/UIViewManualControllerTurtle.ts","webpack://game-client-lerna/./packages/components/slot/ui-view/src/egt/modes/turtle/views/CascadeUIViewTurtle.ts","webpack://game-client-lerna/./packages/components/slot/ui-view/src/egt/modes/turtle/views/UIViewTurtle.ts","webpack://game-client-lerna/./packages/core/features/custom-react/src/egt/feature-flags/featureFlagGroups.ts","webpack://game-client-lerna/./packages/core/features/custom-react/src/egt/feature-flags/resolveFlagDescription.ts","webpack://game-client-lerna/./packages/core/features/custom-react/src/egt/feature-flags/resolveFlagState.ts","webpack://game-client-lerna/./packages/core/features/custom-result/src/egt/custom-result/CustomResultFeature.ts","webpack://game-client-lerna/./packages/core/features/custom-result/src/egt/custom-result/controller/CustomResultController.ts","webpack://game-client-lerna/./packages/core/features/custom-result/src/egt/custom-result/view/CustomResultContentView.ts","webpack://game-client-lerna/./packages/core/features/custom-result/src/egt/custom-result/view/CustomResultView.ts","webpack://game-client-lerna/./packages/core/features/custom-result/src/egt/index.ts","webpack://game-client-lerna/./packages/core/features/dev-tools/src/egt/dev-tools/BaseHooks.ts","webpack://game-client-lerna/./packages/core/features/dev-tools/src/egt/dev-tools/DeveloperTools.ts","webpack://game-client-lerna/./packages/core/features/dev-tools/src/egt/dev-tools/GLHook.ts","webpack://game-client-lerna/./packages/core/features/dev-tools/src/egt/dev-tools/MediaInfoViewer.ts","webpack://game-client-lerna/./packages/core/features/dev-tools/src/egt/dev-tools/PIXIHooks.ts","webpack://game-client-lerna/./packages/core/features/dev-tools/src/egt/dev-tools/TestConsoleViewer.ts","webpack://game-client-lerna/./packages/core/features/dev-tools/src/egt/dev-tools/TextureHook.ts","webpack://game-client-lerna/./packages/core/features/dev-tools/src/egt/dev-tools/leak-radar/CreationProbe.ts","webpack://game-client-lerna/./packages/core/features/dev-tools/src/egt/dev-tools/leak-radar/GsapProbe.ts","webpack://game-client-lerna/./packages/core/features/dev-tools/src/egt/dev-tools/leak-radar/LeakRadar.ts","webpack://game-client-lerna/./packages/core/features/dev-tools/src/egt/dev-tools/leak-radar/LeakRadarPanel.ts","webpack://game-client-lerna/./packages/core/features/dev-tools/src/egt/dev-tools/leak-radar/OrphanTracker.ts","webpack://game-client-lerna/./packages/core/features/dev-tools/src/egt/dev-tools/leak-radar/SceneCensus.ts","webpack://game-client-lerna/./packages/core/features/dev-tools/src/egt/dev-tools/leak-radar/stackUtil.ts","webpack://game-client-lerna/./packages/core/src/egt/core/AnalyticsDispatcher.ts","webpack://game-client-lerna/./packages/core/src/egt/core/AssetsCollection.ts","webpack://game-client-lerna/./packages/core/src/egt/core/AssetsLoader.ts","webpack://game-client-lerna/./packages/core/src/egt/core/BaseComponent.ts","webpack://game-client-lerna/./packages/core/src/egt/core/BaseComponentConfiguration.ts","webpack://game-client-lerna/./packages/core/src/egt/core/BaseController.ts","webpack://game-client-lerna/./packages/core/src/egt/core/BaseFeature.ts","webpack://game-client-lerna/./packages/core/src/egt/core/BaseGame.ts","webpack://game-client-lerna/./packages/core/src/egt/core/BaseModeFactory.ts","webpack://game-client-lerna/./packages/core/src/egt/core/BaseStore.ts","webpack://game-client-lerna/./packages/core/src/egt/core/BaseTemplate.ts","webpack://game-client-lerna/./packages/core/src/egt/core/CommunicationManager.ts","webpack://game-client-lerna/./packages/core/src/egt/core/ConditionObject.ts","webpack://game-client-lerna/./packages/core/src/egt/core/Configuration.ts","webpack://game-client-lerna/./packages/core/src/egt/core/CustomAppService.ts","webpack://game-client-lerna/./packages/core/src/egt/core/DynamicPositionObject.ts","webpack://game-client-lerna/./packages/core/src/egt/core/Environment.ts","webpack://game-client-lerna/./packages/core/src/egt/core/ErrorManager.tsx","webpack://game-client-lerna/./packages/core/src/egt/core/FontsLoader.ts","webpack://game-client-lerna/./packages/core/src/egt/core/HtmlStage.ts","webpack://game-client-lerna/./packages/core/src/egt/core/I18n.ts","webpack://game-client-lerna/./packages/core/src/egt/core/IFrameEventListener.ts","webpack://game-client-lerna/./packages/core/src/egt/core/LobbyStore.ts","webpack://game-client-lerna/./packages/core/src/egt/core/LocalStorageManager.ts","webpack://game-client-lerna/./packages/core/src/egt/core/PositionObject.ts","webpack://game-client-lerna/./packages/core/src/egt/core/PostMessageDispatcher.ts","webpack://game-client-lerna/./packages/core/src/egt/core/RequestManager.ts","webpack://game-client-lerna/./packages/core/src/egt/core/SoundManager.ts","webpack://game-client-lerna/./packages/core/src/egt/core/SpineAnimations.ts","webpack://game-client-lerna/./packages/core/src/egt/core/SpineVideoPlayer.ts","webpack://game-client-lerna/./packages/core/src/egt/core/Stage.ts","webpack://game-client-lerna/./packages/core/src/egt/core/ToneSoundManager.ts","webpack://game-client-lerna/./packages/core/src/egt/core/VideoPlayer.ts","webpack://game-client-lerna/./packages/core/src/egt/core/components/Maintenance.tsx","webpack://game-client-lerna/./packages/core/src/egt/core/components/Modal.tsx","webpack://game-client-lerna/./packages/core/src/egt/core/data/BalanceRequest.ts","webpack://game-client-lerna/./packages/core/src/egt/core/data/BalanceResponse.ts","webpack://game-client-lerna/./packages/core/src/egt/core/data/DefenceCodeRequest.ts","webpack://game-client-lerna/./packages/core/src/egt/core/data/FeatureFlagsData.ts","webpack://game-client-lerna/./packages/core/src/egt/core/data/GameTypes.ts","webpack://game-client-lerna/./packages/core/src/egt/core/data/JackpotLevelStats.ts","webpack://game-client-lerna/./packages/core/src/egt/core/data/JackpotStatsResponse.ts","webpack://game-client-lerna/./packages/core/src/egt/core/data/JoinRequest.ts","webpack://game-client-lerna/./packages/core/src/egt/core/data/LoadGameRequest.ts","webpack://game-client-lerna/./packages/core/src/egt/core/data/Money.ts","webpack://game-client-lerna/./packages/core/src/egt/core/data/MoneyFormatter.ts","webpack://game-client-lerna/./packages/core/src/egt/core/data/Orientation.ts","webpack://game-client-lerna/./packages/core/src/egt/core/data/SettingsRequest.ts","webpack://game-client-lerna/./packages/core/src/egt/core/data/StartingRequest.ts","webpack://game-client-lerna/./packages/core/src/egt/core/data/StatsIntervalTracker.ts","webpack://game-client-lerna/./packages/core/src/egt/core/data/SymbolCredits.ts","webpack://game-client-lerna/./packages/core/src/egt/core/data/UnloadGameRequest.ts","webpack://game-client-lerna/./packages/core/src/egt/core/decorators/Decorators.ts","webpack://game-client-lerna/./packages/core/src/egt/core/enums/AssetPriority.ts","webpack://game-client-lerna/./packages/core/src/egt/core/enums/BaseComponents.ts","webpack://game-client-lerna/./packages/core/src/egt/core/enums/BaseFeatures.ts","webpack://game-client-lerna/./packages/core/src/egt/core/enums/ErrorTypes.ts","webpack://game-client-lerna/./packages/core/src/egt/core/enums/FeatureFlagGroups.ts","webpack://game-client-lerna/./packages/core/src/egt/core/enums/FeatureFlags.ts","webpack://game-client-lerna/./packages/core/src/egt/core/enums/Language.ts","webpack://game-client-lerna/./packages/core/src/egt/core/enums/LifeCycle.ts","webpack://game-client-lerna/./packages/core/src/egt/core/enums/LobbyOpenType.ts","webpack://game-client-lerna/./packages/core/src/egt/core/enums/LobbyStyle.ts","webpack://game-client-lerna/./packages/core/src/egt/core/enums/LoggerGroups.ts","webpack://game-client-lerna/./packages/core/src/egt/core/enums/RestrictionType.ts","webpack://game-client-lerna/./packages/core/src/egt/core/enums/VideoTypes.ts","webpack://game-client-lerna/./packages/core/src/egt/core/metrics/MetricsDebugPanel.ts","webpack://game-client-lerna/./packages/core/src/egt/core/metrics/SessionMetricsCollector.ts","webpack://game-client-lerna/./packages/core/src/egt/core/replayer/ReplayerSocket.ts","webpack://game-client-lerna/./packages/core/src/egt/core/replayer/types/ReplayerTypes.ts","webpack://game-client-lerna/./packages/core/src/egt/core/sentry/sentry-utils.ts","webpack://game-client-lerna/./packages/core/src/egt/core/services/FeatureFlagsStore.ts","webpack://game-client-lerna/./packages/core/src/egt/core/services/FlagsHostConfig.ts","webpack://game-client-lerna/./packages/core/src/egt/core/utils/AdvancedLog.ts","webpack://game-client-lerna/./packages/core/src/egt/core/utils/CommonUtils.ts","webpack://game-client-lerna/./packages/core/src/egt/core/utils/DomHelpers.ts","webpack://game-client-lerna/./packages/core/src/egt/core/utils/GameComponentsLogger.ts","webpack://game-client-lerna/./packages/core/src/egt/core/utils/Log.ts","webpack://game-client-lerna/./packages/core/src/egt/core/utils/OverrideRedundancyReporter.ts","webpack://game-client-lerna/./packages/core/src/egt/core/utils/RedundantOverrideInspector.ts","webpack://game-client-lerna/./packages/core/src/egt/core/utils/SpineUseAnimatorSlotPosition.ts","webpack://game-client-lerna/./packages/core/src/egt/core/utils/TextMetrics.ts","webpack://game-client-lerna/./packages/core/src/egt/core/utils/Timers.ts","webpack://game-client-lerna/./packages/core/src/egt/core/utils/align/Align.ts","webpack://game-client-lerna/./packages/core/src/egt/core/utils/align/AlignBottomCenter.ts","webpack://game-client-lerna/./packages/core/src/egt/core/utils/align/AlignBottomLeft.ts","webpack://game-client-lerna/./packages/core/src/egt/core/utils/align/AlignBottomRight.ts","webpack://game-client-lerna/./packages/core/src/egt/core/utils/align/AlignMiddle.ts","webpack://game-client-lerna/./packages/core/src/egt/core/utils/align/AlignMiddleLeft.ts","webpack://game-client-lerna/./packages/core/src/egt/core/utils/align/AlignMiddleRight.ts","webpack://game-client-lerna/./packages/core/src/egt/core/utils/align/AlignStrategy.ts","webpack://game-client-lerna/./packages/core/src/egt/core/utils/align/AlignTopCenter.ts","webpack://game-client-lerna/./packages/core/src/egt/core/utils/align/AlignTopLeft.ts","webpack://game-client-lerna/./packages/core/src/egt/core/utils/align/AlignTopRight.ts","webpack://game-client-lerna/./packages/core/src/egt/core/utils/scale/Scale.ts","webpack://game-client-lerna/./packages/core/src/egt/core/utils/scale/ScaleFullSize.ts","webpack://game-client-lerna/./packages/core/src/egt/core/utils/scale/ScaleKeepAspectRatio.ts","webpack://game-client-lerna/./packages/core/src/egt/core/utils/scale/ScaleNone.ts","webpack://game-client-lerna/./packages/core/src/egt/core/utils/scale/ScaleStrategy.ts","webpack://game-client-lerna/./packages/core/src/egt/core/utils/scale/ScaleUntil.ts","webpack://game-client-lerna/./packages/core/src/egt/core/views/LoadingView.ts","webpack://game-client-lerna/./packages/features/slot/free-spins/src/egt/FreeSpinFactory.ts","webpack://game-client-lerna/./packages/features/slot/free-spins/src/egt/FreeSpinFeature.ts","webpack://game-client-lerna/./packages/features/slot/free-spins/src/egt/index.ts","webpack://game-client-lerna/./packages/features/slot/free-spins/src/egt/modes/blurred/configuration/FreeSpinFeatureConfigurationBlurred.ts","webpack://game-client-lerna/./packages/features/slot/free-spins/src/egt/modes/default/configuration/FreeSpinFeatureConfigurationDefault.ts","webpack://game-client-lerna/./packages/features/slot/free-spins/src/egt/modes/default/controllers/FreeSpinControllerDefault.ts","webpack://game-client-lerna/./packages/features/slot/free-spins/src/egt/modes/default/enums/FreeSpinType.ts","webpack://game-client-lerna/./packages/features/slot/free-spins/src/egt/modes/default/stores/FreeSpinStore.ts","webpack://game-client-lerna/./packages/features/slot/free-spins/src/egt/modes/default/views/FreeSpinMessageBarView.ts","webpack://game-client-lerna/./packages/features/slot/free-spins/src/egt/modes/default/views/FreeSpinViewDefault.ts","webpack://game-client-lerna/./packages/features/slot/gamble/src/egt/GambleFeature.ts","webpack://game-client-lerna/./packages/features/slot/gamble/src/egt/GambleModeFactory.ts","webpack://game-client-lerna/./packages/features/slot/gamble/src/egt/index.ts","webpack://game-client-lerna/./packages/features/slot/gamble/src/egt/modes/default/configuration/GambleFeatureConfigurationDefault.ts","webpack://game-client-lerna/./packages/features/slot/gamble/src/egt/modes/default/controllers/GambleControllerDefault.ts","webpack://game-client-lerna/./packages/features/slot/gamble/src/egt/modes/default/data/GambleRequest.ts","webpack://game-client-lerna/./packages/features/slot/gamble/src/egt/modes/default/data/GambleResponse.ts","webpack://game-client-lerna/./packages/features/slot/gamble/src/egt/modes/default/enums/GambleConsts.ts","webpack://game-client-lerna/./packages/features/slot/gamble/src/egt/modes/default/enums/GambleState.ts","webpack://game-client-lerna/./packages/features/slot/gamble/src/egt/modes/default/stores/GambleStoreDefault.ts","webpack://game-client-lerna/./packages/features/slot/gamble/src/egt/modes/default/views/GambleViewDefault.ts","webpack://game-client-lerna/./packages/features/slot/gamble/src/egt/modes/turtle/configuration/GambleFeatureConfigurationTurtle.ts","webpack://game-client-lerna/./packages/features/slot/lines/src/egt/LinesFeature.ts","webpack://game-client-lerna/./packages/features/slot/lines/src/egt/LinesModeFactory.ts","webpack://game-client-lerna/./packages/features/slot/lines/src/egt/index.ts","webpack://game-client-lerna/./packages/features/slot/lines/src/egt/modes/default/configuration/LinesFeatureConfigurationDefault.ts","webpack://game-client-lerna/./packages/features/slot/lines/src/egt/modes/default/controllers/LinesControllerDefault.ts","webpack://game-client-lerna/./packages/features/slot/lines/src/egt/modes/default/enums/LineTypesDefault.ts","webpack://game-client-lerna/./packages/features/slot/lines/src/egt/modes/default/store/LinesStoreDefault.ts","webpack://game-client-lerna/./packages/features/slot/lines/src/egt/modes/default/views/SpineLinesViewDefault.ts","webpack://game-client-lerna/./packages/features/slot/lines/src/egt/modes/onlyFrames/configuration/LinesFeatureConfigurationOnlyFrames.ts","webpack://game-client-lerna/./packages/features/slot/lines/src/egt/modes/onlyFrames/views/LinesViewOnlyFrames.ts","webpack://game-client-lerna/./packages/features/slot/lines/src/egt/modes/spineLinesSquares/configuration/LinesFeatureConfigurationSpineLinesSquares.ts","webpack://game-client-lerna/./packages/features/slot/lines/src/egt/modes/spineLinesSquares/views/LinesViewSpineLinesSquares.ts","webpack://game-client-lerna/./packages/features/slot/lines/src/egt/modes/spineOldLines/configuration/LinesFeatureConfigurationSpineOldLines.ts","webpack://game-client-lerna/./packages/features/slot/lines/src/egt/modes/spineOldLines/views/LinesViewSpineOldLines.ts","webpack://game-client-lerna/./packages/features/slot/lines/src/egt/modes/spineSquares/configuration/LinesFeatureConfigurationSpineSquares.ts","webpack://game-client-lerna/./packages/features/slot/lines/src/egt/modes/spineSquares/views/LinesViewSpineSquares.ts","webpack://game-client-lerna/./packages/features/slot/lines/src/egt/modes/spineWaysToPay/configuration/LinesFeatureConfigurationSpineWaysToPay.ts","webpack://game-client-lerna/./packages/features/slot/lines/src/egt/modes/spineWaysToPay/views/LinesViewSpineWaysToPay.ts","webpack://game-client-lerna/./packages/features/slot/videos/src/egt/VideosFeature.ts","webpack://game-client-lerna/./packages/features/slot/videos/src/egt/VideosModeFactory.ts","webpack://game-client-lerna/./packages/features/slot/videos/src/egt/index.ts","webpack://game-client-lerna/./packages/features/slot/videos/src/egt/modes/cascade-ways/configuration/VideosFeatureConfigurationCascadeWays.ts","webpack://game-client-lerna/./packages/features/slot/videos/src/egt/modes/cascade-ways/controllers/VideosControllerCascadeWays.ts","webpack://game-client-lerna/./packages/features/slot/videos/src/egt/modes/cascade-ways/data/EntryWays.ts","webpack://game-client-lerna/./packages/features/slot/videos/src/egt/modes/cascade-ways/data/VideosContextCascadeWays.ts","webpack://game-client-lerna/./packages/features/slot/videos/src/egt/modes/cascade-ways/views/VideosViewCascadeWays.ts","webpack://game-client-lerna/./packages/features/slot/videos/src/egt/modes/cascade/configuration/VideosFeatureConfigurationCascade.ts","webpack://game-client-lerna/./packages/features/slot/videos/src/egt/modes/cascade/controllers/VideosControllerCascade.ts","webpack://game-client-lerna/./packages/features/slot/videos/src/egt/modes/cascade/data/EntryCascade.ts","webpack://game-client-lerna/./packages/features/slot/videos/src/egt/modes/cascade/data/VideosContextCascade.ts","webpack://game-client-lerna/./packages/features/slot/videos/src/egt/modes/cascade/views/VideosViewCascade.ts","webpack://game-client-lerna/./packages/features/slot/videos/src/egt/modes/default/configuration/VideosFeatureConfigurationDefault.ts","webpack://game-client-lerna/./packages/features/slot/videos/src/egt/modes/default/controllers/VideosControllerDefault.ts","webpack://game-client-lerna/./packages/features/slot/videos/src/egt/modes/default/views/VideosViewDefault.ts","webpack://game-client-lerna/./packages/features/slot/videos/src/egt/modes/spine/configuration/VideosFeatureConfigurationSpine.ts","webpack://game-client-lerna/./packages/features/slot/videos/src/egt/modes/spine/controllers/VideosControllerSpine.ts","webpack://game-client-lerna/./packages/features/slot/videos/src/egt/modes/spine/store/VideoStoreSpine.ts","webpack://game-client-lerna/./packages/features/slot/videos/src/egt/modes/spine/views/VideosViewSpine.ts","webpack://game-client-lerna/./packages/scratch/src/egt/scratch/components/feature/ScratchFeatures.ts","webpack://game-client-lerna/./packages/slot-components/reels-overlay/src/egt/ReelsOverlayComponent.ts","webpack://game-client-lerna/./packages/slot-components/reels-overlay/src/egt/configuration/ReelsOverlayComponentConfiguration.ts","webpack://game-client-lerna/./packages/slot-components/reels-overlay/src/egt/enums/ReelsOverlayZOrders.ts","webpack://game-client-lerna/./packages/slot-components/reels-overlay/src/egt/index.ts","webpack://game-client-lerna/./packages/slot-components/reels-overlay/src/egt/views/ReelsOverlayView.ts","webpack://game-client-lerna/./packages/slot-components/settings-popup/src/egt/SettingsPopupComponent.ts","webpack://game-client-lerna/./packages/slot-components/settings-popup/src/egt/configuration/SettingsPopupComponentConfiguration.ts","webpack://game-client-lerna/./packages/slot-components/settings-popup/src/egt/controllers/SettingsPopupController.ts","webpack://game-client-lerna/./packages/slot-components/settings-popup/src/egt/controllers/SettingsPopupControllerDesktop.ts","webpack://game-client-lerna/./packages/slot-components/settings-popup/src/egt/enums/SettingsTab.ts","webpack://game-client-lerna/./packages/slot-components/settings-popup/src/egt/index.ts","webpack://game-client-lerna/./packages/slot-components/settings-popup/src/egt/settings-views/bet/BetSettingsView.ts","webpack://game-client-lerna/./packages/slot-components/settings-popup/src/egt/settings-views/bet/BetSettingsViewDesktop.ts","webpack://game-client-lerna/./packages/slot-components/settings-popup/src/egt/settings-views/bet/OneDenomBetSettingsView.ts","webpack://game-client-lerna/./packages/slot-components/settings-popup/src/egt/settings-views/bet/WaysPayBetSettingsView.ts","webpack://game-client-lerna/./packages/slot-components/settings-popup/src/egt/settings-views/bet/WaysPayBetSettingsViewDesktop.ts","webpack://game-client-lerna/./packages/slot-components/settings-popup/src/egt/settings-views/bet/WaysPayOneDenomBetSettingsView.ts","webpack://game-client-lerna/./packages/slot-components/settings-popup/src/egt/settings-views/general/GeneralSettingsView.ts","webpack://game-client-lerna/./packages/slot-components/settings-popup/src/egt/settings-views/general/GeneralSettingsViewDesktop.ts","webpack://game-client-lerna/./packages/slot-components/settings-popup/src/egt/settings-views/help/HelpView.ts","webpack://game-client-lerna/./packages/slot-components/settings-popup/src/egt/settings-views/paytableHTML/PaytableHTMLView.ts","webpack://game-client-lerna/./packages/slot-components/settings-popup/src/egt/settings-views/paytableHTML/PaytableScript.ts","webpack://game-client-lerna/./packages/slot-components/settings-popup/src/egt/settings-views/spin/SpinSettingsNumericInputView.ts","webpack://game-client-lerna/./packages/slot-components/settings-popup/src/egt/settings-views/spin/SpinSettingsView.ts","webpack://game-client-lerna/./packages/slot-components/settings-popup/src/egt/settings-views/spin/SpinSettingsViewDesktop.ts","webpack://game-client-lerna/./packages/slot-components/settings-popup/src/egt/subjects/SettingsPopupSubjects.ts","webpack://game-client-lerna/./packages/slot-components/settings-popup/src/egt/views/SettingsPopup.ts","webpack://game-client-lerna/./packages/slot-components/settings-popup/src/egt/views/SettingsPopupDesktop.ts","webpack://game-client-lerna/./packages/slot-features/character-animations/src/egt/character-animations/CharacterAnimationsFeature.ts","webpack://game-client-lerna/./packages/slot-features/character-animations/src/egt/character-animations/configurations/CharacterAnimationFeatureConfiguration.ts","webpack://game-client-lerna/./packages/slot-features/character-animations/src/egt/character-animations/controllers/CharacterAnimationsController.ts","webpack://game-client-lerna/./packages/slot-features/character-animations/src/egt/character-animations/enums/AnimationTypes.ts","webpack://game-client-lerna/./packages/slot-features/character-animations/src/egt/character-animations/views/CharacterAnimationsView.ts","webpack://game-client-lerna/./packages/slot-features/character-animations/src/egt/character-animations/views/ClusterCascadeCharacterAnimationsView.ts","webpack://game-client-lerna/./packages/slot-features/character-animations/src/egt/index.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/Icon.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/JackpotCounterBase.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/Slider.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/SteppedSlider.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/TitledWindow.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/UIBlocker.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/ViewContainer.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/ViewVisibilityContainer.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/buttons/BetButton.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/buttons/Button.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/buttons/ButtonShapes.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/buttons/ButtonStates.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/buttons/DenominationButton.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/buttons/DenominationButtonDesktop.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/buttons/DenominationOptionButton.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/buttons/FakeBetButton.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/buttons/HighCashFakeBetButton.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/buttons/KeyboardActionButtonNumeric.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/buttons/KeyboardButtonNumeric.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/buttons/ToggleButton.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/buttons/ValueButton.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/buttons/WaysPayWinlinesButton.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/buttons/WaysPayWinlinesButtonDesktop.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/buttons/WinlinesButton.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/buttons/WinlinesButtonDesktop.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/groups/MoneyContainerGroup.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/index.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/input-field/InputField.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/interfaces/Interfaces.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/numeric-keyboard/KeyboardNumeric.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/texts/AnimatedMoneyText.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/texts/AnimatedMoneyTextConfigV2.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/texts/AnimatedMoneyTextV2.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/texts/BangUpAnimatedCurrencyText.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/texts/BangUpBitMapCurrencyText.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/texts/BangUpBitMapCurrencyTextDynamicPivot.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/texts/BangUpBitMapText.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/texts/BangUpBitMapTextDynamicPivot.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/texts/BangUpCurrencyText.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/texts/BangUpText.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/texts/BangUpTextBounds.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/texts/BluredText.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/texts/JackpotBangUpBitMapText.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/texts/MoneyText.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/texts/MoneyTextConfig.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/texts/Text.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/texts/TextAlign.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/texts/TextConfig.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/texts/TextFitting.ts","webpack://game-client-lerna/./packages/slot-features/ui-lib/src/egt/ui/texts/VerticalTextAlign.ts","webpack://game-client-lerna/./packages/slot/src/egt/index.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/PriorityPositionObject.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/PriorityTextStyle.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/SlotFeatureFlagsStore.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/SlotGame.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/SlotGameLayouts.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/custom-result/CustomInfinityPlayController.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/custom-result/CustomResultSlotController.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/custom-result/CustomResultSlotView.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/custom-result/CustomResultStore.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/custom-result/ScenarioViewer.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/custom-result/views/CustomResultBotContentView.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/custom-result/views/CustomResultCustomContentView.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/custom-result/views/CustomResultScenarioContentView.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/custom-result/views/CustomResultSettingsContentView.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/custom-result/views/CustomResultSoundContentView.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/custom-result/views/CustomResultVideoContentView.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/data/BaseResponse.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/data/BetRequest.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/data/BetResponse.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/data/BonusTypes.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/data/ChainSubject.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/data/CollectRequest.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/data/CollectResponse.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/data/CustomBehaviorSubject.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/data/DomainStore.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/data/FreeSpinRestoreRequest.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/data/HistorySubject.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/data/InitialSettings.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/data/JackpotWin.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/data/MessBarTypes.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/data/PausableSubject.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/data/PriorityList.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/data/PriorityTypes.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/data/RestoreResponse.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/data/ServerState.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/data/SpinAnalyzer.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/data/StateSubject.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/data/Subjects.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/enums/AnalyticsState.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/enums/CentralWinActions.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/enums/RootElementsAnimationTypes.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/enums/SlotComponents.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/enums/ZOrders.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/feature/FeatureController.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/feature/Features.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/lines/Line.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/lines/LineMode.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/lines/LinesView.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/lines/LinesViewDesktop.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/restore/RestoreController.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/root/CustomResultStore.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/root/RootController.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/root/RootStore.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/root/RootView.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/stop-video/StopVideoView.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/symbols/NonProportionalSymbolBase.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/symbols/SymbolBase.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/ui/BangupActionConsts.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/ui/SpinSpeedIndicator.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/ui/UIState.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/components/ui/UIStore.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/configurations/single-progressive/SingleProgressiveAutoplayPopupComponentConfigurationDefault.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/configurations/single-progressive/SingleProgressiveAutoplayPopupComponentConfigurationExtended.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/configurations/single-progressive/SingleProgressiveAutoplayPopupComponentConfigurationNumeric.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/configurations/single-progressive/SingleProgressiveBetButtonsComponentConfigurationDefault.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/configurations/single-progressive/SingleProgressiveBetButtonsComponentConfigurationOneDenom.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/configurations/single-progressive/SingleProgressiveBetCalculatorComponentConfigurationDefault.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/configurations/single-progressive/SingleProgressiveClockComponentConfigurationDefault.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/configurations/single-progressive/SingleProgressiveDenominationPopupComponentConfigurationExtended.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/configurations/single-progressive/SingleProgressiveMessageBarComponentConfiguration.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/configurations/single-progressive/SingleProgressiveSettingsPopupComponentConfiguration.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/configurations/single-progressive/SingleProgressiveTitleComponentConfiguration.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/configurations/single-progressive/SingleProgressiveUIMainPanelComponentConfigurationDefault.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/override-feature-configurations/single-progressive/SingleProgressiveGambleFeatureConfigurationFactoryDefault.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/slot-configuration/SlotConfiguration.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/templates/SingleProgressiveTemplate.ts","webpack://game-client-lerna/./packages/slot/src/egt/slots/templates/SlotTemplate.ts","webpack://game-client-lerna/./packages/core/src/egt/core/Communication.ts","webpack://game-client-lerna/./packages/core/src/egt/core/components/Maintenance.less","webpack://game-client-lerna/./packages/core/src/egt/core/components/Modal.less","webpack://game-client-lerna/./packages/core/features/dev-tools/dev_assets/json-viewer.js","webpack://game-client-lerna/./packages/core/src/egt/core/replayer/translations/ sync ^\\.\\/.*\\.json$","webpack://game-client-lerna/./packages/core/src/egt/core/ sync ^.*\\.json$","webpack://game-client-lerna/ignored|/var/lib/jenkins/workspace/game-client_pre-release@2/game-client-lerna-version-change/node_modules/object-inspect|./util.inspect","webpack://game-client-lerna/webpack/bootstrap","webpack://game-client-lerna/webpack/runtime/chunk loaded","webpack://game-client-lerna/webpack/runtime/compat get default export","webpack://game-client-lerna/webpack/runtime/create fake namespace object","webpack://game-client-lerna/webpack/runtime/define property getters","webpack://game-client-lerna/webpack/runtime/ensure chunk","webpack://game-client-lerna/webpack/runtime/get javascript chunk filename","webpack://game-client-lerna/webpack/runtime/get mini-css chunk filename","webpack://game-client-lerna/webpack/runtime/getFullHash","webpack://game-client-lerna/webpack/runtime/global","webpack://game-client-lerna/webpack/runtime/hasOwnProperty shorthand","webpack://game-client-lerna/webpack/runtime/load script","webpack://game-client-lerna/webpack/runtime/make namespace object","webpack://game-client-lerna/webpack/runtime/node module decorator","webpack://game-client-lerna/webpack/runtime/publicPath","webpack://game-client-lerna/webpack/runtime/css loading","webpack://game-client-lerna/webpack/runtime/jsonp chunk loading","webpack://game-client-lerna/webpack/before-startup","webpack://game-client-lerna/webpack/startup","webpack://game-client-lerna/webpack/after-startup"],"sourcesContent":["// Generated on 2026-10-08T14:06:26.581Z\nvar __async = (__this, __arguments, generator) => {\n  return new Promise((resolve, reject) => {\n    var fulfilled = (value) => {\n      try {\n        step(generator.next(value));\n      } catch (e) {\n        reject(e);\n      }\n    };\n    var rejected = (value) => {\n      try {\n        step(generator.throw(value));\n      } catch (e) {\n        reject(e);\n      }\n    };\n    var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);\n    step((generator = generator.apply(__this, __arguments)).next());\n  });\n};\nimport * as ES6Promise from \"es6-promise\";\nimport NoSleep from \"nosleep.js\";\nimport * as PIXI from \"pixi.js\";\nimport { utils } from \"pixi.js\";\nimport { Logger } from \"unicorn.console-logger\";\nimport JackpotLevelStats from \"./data/JackpotLevelStats\";\nimport JackpotStatsResponse from \"./data/JackpotStatsResponse\";\nimport StatsIntervalTracker from \"./data/StatsIntervalTracker\";\nimport \"reflect-metadata\";\nimport { BehaviorSubject, Subject, fromEvent } from \"rxjs\";\nimport { filter, take } from \"rxjs/operators\";\nimport SockJS from \"sockjs-client\";\nimport { Lifecycle, container } from \"tsyringe\";\nimport Features from \"../../../../slot/src/egt/slots/components/feature/Features\";\nimport ScratchFeatures from \"../../../../scratch/src/egt/scratch/components/feature/ScratchFeatures\";\nimport AnalyticsDispatcher from \"./AnalyticsDispatcher\";\nimport AssetsLoader from \"./AssetsLoader\";\nimport BaseComponent from \"./BaseComponent\";\nimport BaseComponentConfiguration from \"./BaseComponentConfiguration\";\nimport BaseController from \"./BaseController\";\nimport BaseFeature from \"./BaseFeature\";\nimport BaseGame from \"./BaseGame\";\nimport BaseModesConfigurations from \"./BaseModeFactory\";\nimport { BaseStore, logSubjectsValues } from \"./BaseStore\";\nimport BaseTemplate from \"./BaseTemplate\";\nimport Communication from \"./Communication\";\nimport CommunicationManager from \"./CommunicationManager\";\nimport ConditionObject from \"./ConditionObject\";\nimport Configuration from \"./Configuration\";\nimport CustomAppService from \"./CustomAppService\";\nimport DynamicPositionObject from \"./DynamicPositionObject\";\nimport Environment from \"./Environment\";\nimport ErrorManager from \"./ErrorManager\";\nimport FontsLoader from \"./FontsLoader\";\nimport HtmlStage from \"./HtmlStage\";\nimport I18n from \"./I18n\";\nimport { IBaseConfiguration } from \"./IBaseConfiguration\";\nimport IFrameEventListener from \"./IFrameEventListener\";\nimport LobbyStore from \"./LobbyStore\";\nimport LocalStorageManager from \"./LocalStorageManager\";\nimport PositionObject from \"./PositionObject\";\nimport PostMessageDispatcher from \"./PostMessageDispatcher\";\nimport RequestManager from \"./RequestManager\";\nimport SoundManager from \"./SoundManager\";\nimport SpineAnimations from \"./SpineAnimations\";\nimport SpineVideoPlayer from \"./SpineVideoPlayer\";\nimport Stage from \"./Stage\";\nimport VideoPlayer from \"./VideoPlayer\";\nimport BalanceRequest from \"./data/BalanceRequest\";\nimport BalanceResponse from \"./data/BalanceResponse\";\nimport { BusMessage } from \"./data/BusMessage\";\nimport DefenceCodeRequest from \"./data/DefenceCodeRequest\";\nimport Money from \"./data/Money\";\nimport MoneyFormatter from \"./data/MoneyFormatter\";\nimport Orientation from \"./data/Orientation\";\nimport SettingsRequest from \"./data/SettingsRequest\";\nimport StartingRequest from \"./data/StartingRequest\";\nimport SymbolCredits from \"./data/SymbolCredits\";\nimport UnloadGameRequest from \"./data/UnloadGameRequest\";\nimport {\n  AddPriority,\n  DebugPriorities,\n  DefaultAssets,\n  DefaultValue,\n  ModifyAssets,\n  ModifyValue,\n  OverrideDefaultProperties,\n  RemoveAssets,\n  ScaleByGlobalReelsTimeScale\n} from \"./decorators/Decorators\";\nimport AssetPriority from \"./enums/AssetPriority\";\nimport BaseFeatures from \"./enums/BaseFeatures\";\nimport ErrorTypes from \"./enums/ErrorTypes\";\nimport Language from \"./enums/Language\";\nimport LifeCycle from \"./enums/LifeCycle\";\nimport LobbyOpenType from \"./enums/LobbyOpenType\";\nimport LobbyStyle from \"./enums/LobbyStyle\";\nimport { LoggerGroups } from \"./enums/LoggerGroups\";\nimport RestrictionType, { RESTRICTION_TYPE_BY_FEATURE_FLAG } from \"./enums/RestrictionType\";\nimport VideoTypes from \"./enums/VideoTypes\";\nimport { IAsset } from \"./interfaces/IAsset\";\nimport { IAssetsLoader } from \"./interfaces/IAssetsLoader\";\nimport { IConfiguration } from \"./interfaces/IConfiguration\";\nimport { IConnectable } from \"./interfaces/IConnectable\";\nimport { IContentLoadData } from \"./interfaces/IContentLoadData\";\nimport { IDeveloperTools } from \"./interfaces/IDeveloperTools\";\nimport { IDisplayData } from \"./interfaces/IDisplayData\";\nimport { IDynamicPosition, IModifiedDynamicPosition } from \"./interfaces/IDynamicPosition\";\nimport IElementVisabilty from \"./interfaces/IElementVisabilty\";\nimport { IEnvironment } from \"./interfaces/IEnvironment\";\nimport { IErrorData } from \"./interfaces/IErrorData\";\nimport { ILifeCycle } from \"./interfaces/ILifeCycle\";\nimport { ILinesConfiguration } from \"./interfaces/ILinesConfiguration\";\nimport { ILoadAsset } from \"./interfaces/ILoadAsset\";\nimport { ILoadingIndicator } from \"./interfaces/ILoadingIndicator\";\nimport { IMediaInfoData } from \"./interfaces/IMediaInfoData\";\nimport { IOrientation } from \"./interfaces/IOrientation\";\nimport { IFeatureAssetsArray, IPosition, IPositionPoint } from \"./interfaces/IPosition\";\nimport { IRequest } from \"./interfaces/IRequest\";\nimport { IRestriction } from \"./interfaces/IRestriction\";\nimport { IScratchTemplateConstructorProps } from \"./interfaces/IScratchTemplateConstructorProps\";\nimport { ISlotTemplateConstructorProps } from \"./interfaces/ISlotTemplateConstructorProps\";\nimport { ISoundAsset } from \"./interfaces/ISoundAsset\";\nimport { ISoundManager } from \"./interfaces/ISoundManager\";\nimport { ISpineVideoConfig, ISpineVideoPlayer } from \"./interfaces/ISpineVideoPlayer\";\nimport { IStageOptions } from \"./interfaces/IStageOptions\";\nimport { ITemplate } from \"./interfaces/ITemplate\";\nimport { ITranslator } from \"./interfaces/ITranslator\";\nimport { IVideoPlayer } from \"./interfaces/IVideoPlayer\";\nimport { IVideoPositionPoint } from \"./interfaces/IVideoPositionPoint\";\nimport SessionMetricsCollector, { UserActionType } from \"./metrics/SessionMetricsCollector\";\nimport ReplayerSocket from \"./replayer/ReplayerSocket\";\nimport { ReplayerCommandType, ReplayerRoundType } from \"./replayer/types/ReplayerTypes\";\nimport { initSentry, startInitializationTransaction } from \"./sentry/sentry-utils\";\nimport { initAdvancedLog } from \"./utils/AdvancedLog\";\nimport { computeSpineDelta, getDocumentCookie } from \"./utils/CommonUtils\";\nimport DomHelpers from \"./utils/DomHelpers\";\nimport { NOT_MIGRATE_TEXT, logGameComponents } from \"./utils/GameComponentsLogger\";\nimport Log from \"./utils/Log\";\nimport { overrideTextMetrics } from \"./utils/TextMetrics\";\nimport Timers from \"./utils/Timers\";\nimport Align from \"./utils/align/Align\";\nimport Scale from \"./utils/scale/Scale\";\nimport ScaleUntil from \"./utils/scale/ScaleUntil\";\nimport LoadingView from \"./views/LoadingView\";\nimport AssetsCollection from \"./AssetsCollection\";\nimport ToneSoundManager from \"./ToneSoundManager\";\nimport LocalFeatureFlags from \"./data/FeatureFlagsData\";\nimport GameTypes from \"./data/GameTypes\";\nimport FeatureFlagGroups from \"./enums/FeatureFlagGroups\";\nimport { FeatureFlags } from \"./enums/FeatureFlags\";\nimport { IFeatureFlag, IFeatureFlags } from \"./interfaces/IFeatureFlags\";\nimport \"./metrics/MetricsDebugPanel\";\nimport FeatureFlagsStore from \"./services/FeatureFlagsStore\";\nimport { setFlagsHostConfigProvider } from \"./services/FlagsHostConfig\";\nimport SpineUseAnimatorSlotPosition from \"./utils/SpineUseAnimatorSlotPosition\";\nES6Promise.polyfill();\noverrideTextMetrics();\nclass Core {\n  constructor() {\n    this.multiPlayerGame = [\"XRideMP\"];\n    // BlitzPlays mode\n    this.BLITZ_PLAY_OPEN = new BehaviorSubject(false);\n    this.BLITZ_PLAY_MODE = new BehaviorSubject(false);\n    this.BLITZ_PLAY_ON_SERVER_RESPONSE = new Subject();\n    // used for replayer\n    /** when we need to send click / tap event to replayer in order to continue replay */\n    this.WAIT_USER_ACTION = new Subject();\n    /** when replayer must send notification to controllers/views in order to change state of its component */\n    this.REPLAYER_ACTION = new Subject();\n    this.isReplayer = new URLSearchParams(window.location.search).get(\"replayKey\") ? true : false;\n    this.EXIT_APPLICATION = new Subject();\n    this.ON_SERVER_MESSAGE = new Subject();\n    this.ON_GAME_LOADED = new Subject();\n    this.ON_GAME_UNLOADED = new Subject();\n    this.ON_GAME_PAUSED = new BehaviorSubject(\"NONE\");\n    this.ON_RENDERER_PAUSED = new BehaviorSubject(false);\n    this.LEFT_HAND_MODE = new BehaviorSubject(false);\n    this.UPDATE_PRIORITIES_FOR_COMPONENTS = new Subject();\n    this.ON_CONNECTION_OPENED = new Subject();\n    this.ON_CONNECTION_RESTORED = new Subject();\n    this.IS_DOWNLOAD_BUTTON_ACTIVE = new BehaviorSubject(false);\n    this.SHOW_ERROR = new Subject();\n    this.HIDE_ERROR = new Subject();\n    this.ON_SERVER_RESPONSE = new Subject();\n    this.ON_SOCKET_MESSAGE = new Subject();\n    // dispatched before ON_SERVER_RESPONSE / on_game_message\n    this.SEND_MESSAGE_TO_SERVER = new Subject();\n    this.STAGE_RESIZE_START = new Subject();\n    this.STAGE_RESIZE_END = new Subject();\n    this.FULL_SCREEN_ACTIVATED = new BehaviorSubject(false);\n    this.MEDIA_INFO_UPDATED = new Subject();\n    this.PERFORMANCE_METRICS = new Subject();\n    this.ASSET_ERROR = new Subject();\n    this.ATTACH_SUBSCRIPTIONS = new Subject();\n    this.LOADING_ASSETS = new BehaviorSubject(false);\n    this.DISABLE_KEYBOARD_EVENTS = new BehaviorSubject(false);\n    this.CONTENT_LOADED = new Subject();\n    this.TOUCH_CANCEL = new Subject();\n    this.ORIENTATION = new BehaviorSubject(\n      new Orientation({\n        orientation: \"Landscape\",\n        width: 0,\n        height: 0\n      })\n    );\n    this.UI_BLOCKER = new BehaviorSubject(false);\n    this.BATTERY_SAVE_MODE = new BehaviorSubject(false);\n    this.PLAYER_BALANCE = new BehaviorSubject(\n      new BalanceResponse({ balance: { balance: 0, denomination: 1, units: 100, currency: \"EGT\" } })\n    );\n    this.allow_money_mode_change = false;\n    this.MONEY_MODE_IN_CREDITS = new BehaviorSubject(false);\n    this.SELECTED_DENOMINATION = new BehaviorSubject(1);\n    // public readonly MAX_WIN_LIMIT_HIT: BehaviorSubject<boolean> = new BehaviorSubject(false);\n    // NO-Sleep\n    // public readonly NO_SLEEP_ACTIVE: BehaviorSubject<boolean> = new BehaviorSubject(false);\n    // NO-Sleep\n    this.environment = new Environment();\n    this.configuration = new Configuration();\n    this.lobbyStore = new LobbyStore();\n    /**\n     * Global feature-flags store. Single source of truth — read via `Core.flags.isActive(...)`.\n     *\n     * Typed as the concrete base store, which every per-game subclass (`SlotFeatureFlagsStore`,\n     * `ScratchFeatureFlagsStore`, `MultiplayerFeatureFlagsStore`) extends — so assigning one of\n     * those here is ordinary subtype assignment and needs no cast. `readonly` is dropped to allow\n     * that single assignment at load (see `onCreateFeatureFlags`), and again in `destroyGame`, which\n     * puts a fresh base store back so the lobby never reads the previous game's flags.\n     * Constructed eagerly so the read API works before any game load.\n     */\n    this.flags = new FeatureFlagsStore();\n    // public maxWinLimitHit: boolean = false;\n    /** store result of settings command */\n    this.settings = void 0;\n    /** store result of joinGame command for multiplier games */\n    this.settingsMP = void 0;\n    this.fonts = new FontsLoader();\n    /** used to echange data between game and portal as groupid or denomination */\n    this.gamePortalExchangeObject = {};\n    this.devTools = null;\n    this.customAppService = new CustomAppService();\n    this.gameDependencyContainer = container.createChildContainer();\n    this.noSleep = new NoSleep();\n    this.container = container.createChildContainer();\n    this.initialized = false;\n    this.errorManager = new ErrorManager();\n    this.onBeforeStartLoadingResourcesEmitted = false;\n    this.registeredVideoPlayers = [];\n    setFlagsHostConfigProvider(() => {\n      var _a, _b, _c;\n      return {\n        gameKey: (_b = (_a = this.configuration) == null ? void 0 : _a.gameKey) != null ? _b : \"\",\n        devTools: !!((_c = this.configuration) == null ? void 0 : _c.devTools)\n      };\n    });\n    this.container.registerInstance(\"IConfiguration\", this.configuration);\n    this.container.registerInstance(\"IEnvironment\", this.environment);\n    this.container.registerInstance(\"ErrorManager\", this.errorManager);\n    this.container.registerInstance(\"LobbyStore\", this.lobbyStore);\n    this.SHOW_ERROR.subscribe(this.errorManager.show);\n    this.HIDE_ERROR.subscribe(this.errorManager.hide);\n    this.ON_GAME_LOADED.subscribe((response) => this.onGameLoaded(response));\n    this.ON_GAME_UNLOADED.subscribe(() => this.onGameUnloaded());\n    this.ON_CONNECTION_OPENED.subscribe(() => this.onConnectionOpened());\n    window.addEventListener(\"touchstart\", this.onTouchEvent.bind(this), false);\n    window.addEventListener(\"touchend\", this.onTouchEvent.bind(this), false);\n    window.addEventListener(\"pagehide\", () => {\n      AnalyticsDispatcher.forceFlushSessionMetrics();\n      if (this.configuration.devTools) {\n        this._connection.close(1e3, \"Normal Closure\");\n      }\n    });\n    window.addEventListener(\"message\", this.processEvent.bind(this), false);\n    fromEvent(window, \"resize\").pipe(filter(() => !this.stage || !this.stage.stageInititalized || !this.stage.shouldResize)).subscribe(() => {\n      this.STAGE_RESIZE_END.next();\n    });\n    window.addEventListener(\"touchcancel\", () => {\n      this.TOUCH_CANCEL.next(true);\n    });\n    window.PIXI = PIXI;\n    this.multiTouchProtector = document.getElementById(\"multitouchprotect\");\n    const canvas = document.getElementById(\"app-canvas\");\n    canvas.addEventListener(\"webglcontextlost\", (e) => {\n      e.preventDefault();\n      AnalyticsDispatcher.sendErrorEvent(ErrorTypes.JS_ERROR, \"Lost context\", \"WEBGL Context Lost\");\n      window.location.reload();\n    });\n    window.onerror = (message, _source, _line, _col, error) => {\n      let errStack = [];\n      let errDescription = message;\n      if (typeof error === \"object\" && (error == null ? void 0 : error.stack)) {\n        if (error == null ? void 0 : error.stack) {\n          errStack = String(error == null ? void 0 : error.stack).split(\" at \");\n        }\n        if (typeof error === \"string\") {\n          errStack = String(error).split(\" at \");\n        }\n        errDescription = errStack[0] + \" at \" + (errStack.length > 1) ? errStack[1] : \"\";\n      }\n      Logger.logServiceMessage(\n        [`General Exception:`, { message, source: _source, line: _line, col: _col, error }],\n        _source || \"window.onerror()\",\n        \"important\"\n      );\n      AnalyticsDispatcher.sendErrorEvent(ErrorTypes.JS_ERROR, \"unknown\", errDescription);\n      return false;\n    };\n  }\n  get game() {\n    return this._game;\n  }\n  // gameType is not set for all type of games should be refactored\n  get gameType() {\n    return this._game.gameType;\n  }\n  hasFeature(feature, mode) {\n    return this._game.hasFeature(feature, mode);\n  }\n  hasComponent(component, mode) {\n    return this._game.hasComponent(component, mode);\n  }\n  get gameLayout() {\n    return this._game.gameLayout;\n  }\n  set gameLayout(value) {\n    this._game.gameLayout = value;\n  }\n  get display() {\n    this.checkInitialization();\n    return this.stage.getMediaInfo().display;\n  }\n  get translator() {\n    this.checkInitialization();\n    return this._translator;\n  }\n  get sounds() {\n    this.checkInitialization();\n    return this.soundManager;\n  }\n  get spineAnimations() {\n    this.checkInitialization();\n    return this._spineAnimations;\n  }\n  get connection() {\n    this.checkInitialization();\n    return this._connection;\n  }\n  get assets() {\n    this.checkInitialization();\n    return this.assetsLoader;\n  }\n  get localStorage() {\n    this.checkInitialization();\n    return this.localStorrageManager;\n  }\n  get customResourcesHost() {\n    if (window.hasOwnProperty(\"ssi\") && window.ssi.hasOwnProperty(\"CustomResourcesHost\")) {\n      return true;\n    }\n    return false;\n  }\n  get hash() {\n    let hashStr = \"hash=\";\n    hashStr += String(__webpack_hash__);\n    return hashStr;\n  }\n  get isDesktopMode() {\n    return this.configuration.mode === \"desktop\" ? true : false;\n  }\n  processEvent(ev) {\n    IFrameEventListener.processEvent(ev);\n  }\n  emit(key, value, featuresOnly = false) {\n    if (this._game) {\n      if (this._game[key] && !featuresOnly) {\n        this._game[key](value);\n      }\n      this._game.components.forEach((component) => {\n        if (component[key]) {\n          component[key](value);\n        }\n      });\n      this._game.features.forEach((feature) => {\n        if (feature[key]) {\n          feature[key](value);\n        }\n      });\n    }\n  }\n  getGameComponents() {\n    return this._game.components;\n  }\n  getGameFeatures() {\n    return this._game.features;\n  }\n  getSupportedLayouts() {\n    return this._game.supportedLayouts;\n  }\n  createVideoPlayer() {\n    this.checkInitialization();\n    const vp = this.container.resolve(\"IVideoPlayer\");\n    this.registeredVideoPlayers.push(vp);\n    return vp;\n  }\n  destroyVideoPlayer(vp) {\n    this.checkInitialization();\n    const index = this.registeredVideoPlayers.indexOf(vp);\n    if (index > -1) {\n      this.registeredVideoPlayers.splice(index, 1);\n    }\n    vp == null ? void 0 : vp.destroy();\n  }\n  createSpineVideoPlayer() {\n    this.checkInitialization();\n    const vp = this.container.resolve(\"ISpineVideoPlayer\");\n    this.registeredVideoPlayers.push(vp);\n    return vp;\n  }\n  sendMessage(request) {\n    this.checkInitialization();\n    return this.communication.sendMessage(request);\n  }\n  closeGame() {\n    this.DISABLE_KEYBOARD_EVENTS.next(true);\n    if (this.configuration.gameKey && this.configuration.gameKey !== \"\" && !this.configuration.openSection) {\n      this.sendMessage(new UnloadGameRequest());\n    } else {\n      this.ON_GAME_UNLOADED.next();\n    }\n    if (this.noSleep.isEnabled) {\n      try {\n        this.noSleep.disable();\n      } catch (error) {\n        Log.warn(\"NoSleep disable failed:\", error);\n      }\n    }\n  }\n  openGame(gameKey) {\n    var _a;\n    if (!this.isReplayer && (!gameKey || gameKey === \"\" || ((_a = this.configuration) == null ? void 0 : _a.openSection))) {\n      this.closeGame();\n      return;\n    }\n    window[\"sesionMetricCollector\"] = SessionMetricsCollector.getInstance();\n    this.DISABLE_KEYBOARD_EVENTS.next(false);\n    this.sendMessage(new StartingRequest(this.environment, gameKey));\n  }\n  init(localServer) {\n    if (this.configuration.devTools) {\n      initAdvancedLog(window.location.search);\n    }\n    if (!this.isReplayer && window.hasOwnProperty(\"ssi\")) {\n      if (\n        // @ts-ignore\n        window.ssi.hasOwnProperty(\"egtd_maintenance\") && // @ts-ignore\n        window.ssi[\"egtd_maintenance\"] === true && !getDocumentCookie(\"skip_egtd_maintenance\")\n      ) {\n        const errorData = {};\n        errorData.errorName = \"maintenance_all\";\n        errorData.code = \"\";\n        errorData.modal = true;\n        errorData.type = ErrorTypes.MAINTENANCE;\n        this.initialized = true;\n        this.setConfigurationFromURL();\n        container.register(\"ITranslator\", { useClass: I18n }, { lifecycle: Lifecycle.Singleton });\n        this._translator = this.container.resolve(\"ITranslator\");\n        this.SHOW_ERROR.next(errorData);\n        return;\n      }\n      if (window.ssi.hasOwnProperty(\"sentryEnvironment\")) {\n        initSentry(window.location.search, this.configuration.version).then((client) => {\n          if (client) {\n            this._sentryClient = client;\n            startInitializationTransaction(this._sentryClient);\n          }\n        });\n      }\n    }\n    const compatibilty = this.environment.isBrowserFeaturesCompatible();\n    if (compatibilty !== true) {\n      const errorData = {};\n      errorData.errorName = \"browserError\";\n      errorData.code = \"\" + compatibilty;\n      errorData.modal = true;\n      errorData.type = ErrorTypes.BROWSER_NOT_SUPPORTED_ERROR;\n      if (!this.initialized) {\n        this.initialized = true;\n        this.setConfigurationFromURL();\n        container.register(\"ITranslator\", { useClass: I18n }, { lifecycle: Lifecycle.Singleton });\n        this._translator = this.container.resolve(\"ITranslator\");\n      }\n      this.SHOW_ERROR.next(errorData);\n      return;\n    }\n    if (!this.initialized) {\n      this.initialized = true;\n      this.localServer = localServer;\n      this.setConfigurationFromURL();\n      Logger.logServiceMessage([\"init() configuration:\", this.configuration], \"Core\");\n      if (this.devTools) {\n        logSubjectsValues(this, [this.PERFORMANCE_METRICS]);\n        logSubjectsValues(this.lobbyStore);\n        this.devTools.init();\n      }\n      if (!this.isReplayer) {\n        this.lobbyStore.loadLobbyScript();\n      }\n      this.registerDependencies();\n      this.resolveDependencies();\n      this.lobbyStore.init();\n      this.soundManager.ON_SOUND_MUTED.next(this.configuration.mute);\n      this.soundManager.ON_BACKGROUND_SOUNDS_MUTED.next(this.configuration.bgMusicMute);\n    }\n  }\n  openConnection() {\n    if (this.isReplayer) {\n      this.replayerSocket = new ReplayerSocket();\n      this._connection = this.replayerSocket;\n    } else {\n      const a = this.getURL();\n      this._connection = this.localServer || new SockJS(a, this.configuration.protocol, { sessionId: 17, timeout: 1e4 });\n    }\n    return this._connection;\n  }\n  initStage(options) {\n    options.view = this.getCanvas();\n    const url = new URL(window.location.href);\n    options = this.setStageOptions(url, options);\n    this.stage.initStage(options);\n    this.stage.stage.addChild(this.loadingView);\n    this.loadingView.initLoading();\n    this.setOrientation();\n  }\n  destroyGame() {\n    var _a, _b;\n    this.flags.reset();\n    this.flags = new FeatureFlagsStore();\n    this.soundManager.stopAll([\"homeSound\", \"selectGameSound\"]);\n    this.translator.moduleAssets = [];\n    if (!(this.stage instanceof HtmlStage)) {\n      (_a = this.stage.stage) == null ? void 0 : _a.removeChild(this.loadingView);\n    }\n    this.emit(LifeCycle.ON_DESTROY, \"\", true);\n    (_b = this._game) == null ? void 0 : _b.destroy();\n    this.assets.reset();\n    this.fonts.reset();\n    this.translator.reset();\n    this.translator.loadErrorAsset();\n    if (this.registeredVideoPlayers.length > 0) {\n      this.registeredVideoPlayers.forEach((vp) => {\n        vp.stop();\n        vp = null;\n      });\n      this.registeredVideoPlayers = [];\n    }\n    if (this.sounds.isPlaying(\"homeSound\")) {\n      const _time = this.sounds.getSoundDuration(\"mainSounds\", \"homeSound\") - (this.sounds.getSoundCurrentTime(\"homeSound\") || 0);\n      if (_time > 0) {\n        setTimeout(() => {\n          this.sounds.reset();\n        }, _time + 100);\n      } else {\n        this.sounds.reset();\n      }\n    } else {\n      this.sounds.reset();\n    }\n    Timers.clearIntervalAll();\n    Timers.clearTimeoutAll();\n    utils.clearTextureCache();\n    utils.destroyTextureCache();\n    this.stage.clear();\n    this._spineAnimations.destroy();\n    this.gameDependencyContainer.clearInstances();\n    this.gameDependencyContainer.reset();\n    this._game = null;\n    this.LEFT_HAND_MODE.next(false);\n  }\n  get sentryClient() {\n    return this._sentryClient;\n  }\n  onTouchEvent(event) {\n    if (this.configuration.gameKey !== \"\") {\n      if (event.touches.length > 0) {\n        this.multiTouchProtector.style.pointerEvents = \"auto\";\n      } else {\n        this.multiTouchProtector.style.pointerEvents = \"none\";\n      }\n    }\n  }\n  // called when unload confirmation is received\n  onGameUnloaded() {\n    this.emit(LifeCycle.ON_BEFORE_DESTROY);\n    AnalyticsDispatcher.forceFlushSessionMetrics();\n    this.destroyGame();\n    this.spineAnimations.destroy();\n    if (!this.configuration.gameKey || this.configuration.openSection) {\n      this.sendMessage(new SettingsRequest());\n    }\n  }\n  onGameLoaded(response) {\n    return __async(this, null, function* () {\n      var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;\n      if (response.error && response.event === \"loadGame\") {\n        this.closeGame();\n        return;\n      }\n      if (!this.importGame) {\n        throw new Error(\"Import game not implemented!\");\n      }\n      this.destroyGame();\n      if (!this.configuration.hasPortal && response.gameKey === void 0) {\n        this.EXIT_APPLICATION.next();\n        return;\n      }\n      let moneyInCredits = false;\n      switch ((_b = (_a = response.settings) == null ? void 0 : _a.jurisdiction) == null ? void 0 : _b.metric) {\n        case \"both\":\n          this.allow_money_mode_change = true;\n          moneyInCredits = ((_d = (_c = response.settings) == null ? void 0 : _c.jurisdiction) == null ? void 0 : _d.defaultMetric) === \"credits\" ? true : false;\n          break;\n        case \"currency\":\n          moneyInCredits = false;\n          break;\n        case \"credits\":\n          moneyInCredits = true;\n          break;\n      }\n      this.MONEY_MODE_IN_CREDITS.next(moneyInCredits);\n      if (response.event === \"joinGame\") {\n        this.lobbyStore.setLobbyOptions((_f = (_e = response.data) == null ? void 0 : _e.settings) == null ? void 0 : _f.lobbyHome, (_g = response.data) == null ? void 0 : _g.settings);\n      } else {\n        this.lobbyStore.setLobbyOptions(\n          (_i = (_h = response.settings) == null ? void 0 : _h.jurisdiction) == null ? void 0 : _i.lobbyHome,\n          (_j = response.settings) == null ? void 0 : _j.jurisdiction\n        );\n      }\n      this.lobbyStore.setCurrentGame(response.gameKey);\n      const indicator = this.container.resolve(\"ILoadingIndicator\");\n      indicator.start();\n      PostMessageDispatcher.gameLoadStarted();\n      PostMessageDispatcher.gameLoadProgress(0);\n      this.importGame(response.gameKey).then((source) => __async(this, null, function* () {\n        var _a2, _b2, _c2, _d2, _e2, _f2, _g2, _h2, _i2, _j2, _k, _l, _m, _n, _o, _p, _q;\n        if (this.configuration.gameKey !== \"\") {\n          if (!this.configuration.multiplayer) {\n            this.environment.addMobileFullscreen();\n          }\n          if (!this.isReplayer) {\n            AnalyticsDispatcher.sendOpenGameEvent();\n          }\n        } else {\n          this.environment.removeMobileFullscreen();\n        }\n        PostMessageDispatcher.gameOpened();\n        this._game = new source.default(this.stage.gameContainer, this.gameDependencyContainer);\n        this._game.onCreateFeatureFlags(response);\n        this._game.onCreateGameTemplate(response);\n        let features = (_a2 = response.settings) == null ? void 0 : _a2.feature;\n        if ((features == null ? void 0 : features.indexOf(\"BUY_BONUS\")) > -1 && (features == null ? void 0 : features.indexOf(\"GIFT_SPINS\")) === -1) {\n          features.push(\"GIFT_SPINS\");\n        }\n        if (((_c2 = (_b2 = response.settings) == null ? void 0 : _b2.clientSettings) == null ? void 0 : _c2.branding) && ((_e2 = (_d2 = response.settings) == null ? void 0 : _d2.clientSettings) == null ? void 0 : _e2.branding) !== \"christmas\" && !this._game.gameTemplate.getTemplateGameFeatures().find((f) => f[0] === Features.BRANDING)) {\n          features.push(\"BRANDING\");\n        }\n        if (((_g2 = (_f2 = response.settings) == null ? void 0 : _f2.jurisdiction) == null ? void 0 : _g2.seasonalBranding) && ((_i2 = (_h2 = response.settings) == null ? void 0 : _h2.jurisdiction) == null ? void 0 : _i2.seasonalBranding) === \"Christmas\") {\n          features.push(\"BL_CHRISTMAS\");\n        }\n        const enabledBlitzPlay = (_k = (_j2 = response.settings) == null ? void 0 : _j2.clientSettings) == null ? void 0 : _k.enableBlitzPlay;\n        if (enabledBlitzPlay) {\n          features.push(\"BLITZ_PLAY\");\n        }\n        if ((_l = response.settings) == null ? void 0 : _l.limit) {\n          features.push(\"MAX_WIN_LIMIT\");\n        }\n        if (this.isReplayer) {\n          if (this._game.gameTemplate.getTemplateExternalFeatures().find((item) => item[0] === Features.REPLAYER)) {\n            features = features.filter((item) => item !== Features.TOURNAMENTS);\n            features.push(\"REPLAYER\");\n          } else {\n            const errorData = {};\n            errorData.code = \"4819\";\n            errorData.modal = true;\n            errorData.type = ErrorTypes.GAME_LOCK_ERROR;\n            this.SHOW_ERROR.next(errorData);\n          }\n        }\n        features = this._game.gameTemplate.updateExternalServerList(features);\n        this._game.gameTemplate.addExternalFeatures(features);\n        this._game.externalFeaturesAdded();\n        const featuresList = this.getFeaturesList(features);\n        let brandingFeature = featuresList.find((b) => b[0] === Features.BRANDING);\n        if (brandingFeature) {\n          const indexFeature = featuresList.indexOf(brandingFeature);\n          brandingFeature = [...brandingFeature, (_n = (_m = response.settings) == null ? void 0 : _m.clientSettings) == null ? void 0 : _n.branding];\n          featuresList.splice(indexFeature, 1, brandingFeature);\n        }\n        this._game.onBeforeInit();\n        const prizePopFeature = featuresList.find((b) => b[0] === Features.PRIZE_POPS);\n        const isCampaignInRestore = (_q = (_p = (_o = this._game) == null ? void 0 : _o.featuresPriority) == null ? void 0 : _p.RESTORE) == null ? void 0 : _q.includes(Features.CAMPAIGN_MANAGER);\n        if (prizePopFeature && !isCampaignInRestore) {\n          this._game.featuresPriority.RESTORE.push(Features.CAMPAIGN_MANAGER);\n        }\n        const removedFeatures = this.getRemovedFeaturesList(features);\n        if (removedFeatures.includes(Features.PRIZE_POPS)) {\n          removedFeatures.push(Features.CAMPAIGN_MANAGER);\n        }\n        if (removedFeatures.includes(ScratchFeatures.SCRATCH_PRIZE_POPS)) {\n          removedFeatures.push(ScratchFeatures.SCRATCH_CAMPAIGN_MANAGER);\n        }\n        this.filterPriorities(removedFeatures);\n        yield this.importFeatures(featuresList);\n        const gameComponents = this._game.getGameComponents(response);\n        if (this.configuration.mode === \"kiosk\") {\n          gameComponents.push([\"VLT\"]);\n        }\n        yield this.importComponents(gameComponents);\n        this.emit(LifeCycle.ON_GAME_SETTINGS, response);\n        this.emit(LifeCycle.ON_REGISTER_DEPENDENCIES, this.gameDependencyContainer);\n        if (this.isDesktopMode) {\n          this.emit(LifeCycle.ON_REGISTER_DESKTOP_DEPENDENCIES, this.gameDependencyContainer);\n        } else {\n          this.emit(LifeCycle.ON_REGISTER_MOBILE_DEPENDENCIES, this.gameDependencyContainer);\n        }\n        this.emit(LifeCycle.ON_BEFORE_RESOLVE_DEPENDENCIES, this.gameDependencyContainer);\n        this.UPDATE_PRIORITIES_FOR_COMPONENTS.next();\n        this.emit(LifeCycle.ON_GAME_CONFIGURATION_CREATED);\n        this.emit(LifeCycle.ON_AFTER_GAME_CONFIGURATION_CREATED);\n        this.emit(LifeCycle.ON_PREPARE_RESOURCES, this.stage.gameContainer);\n        const duration = Math.max(\n          this.sounds.getSoundDuration(\"mainSounds\", \"homeSound\"),\n          this.sounds.getSoundDuration(\"portalSounds\", \"selectGameSound\")\n        );\n        Timers.setTimeout(() => {\n          this.sounds.reset();\n          this.onBeforeStartLoadingResourcesEmitted = false;\n          this.fonts.FONTS_LOADED.pipe(take(1)).subscribe(this.loadAssets.bind(this));\n          this.fonts.load();\n        }, duration);\n      }));\n    });\n  }\n  onConnectionOpened() {\n    this.openGame(this.configuration.gameKey);\n  }\n  setOrientation() {\n    this.ORIENTATION.next(\n      new Orientation({\n        orientation: this.display.stage.orientation.charAt(0).toUpperCase() + this.display.stage.orientation.slice(1),\n        width: this.display.stage.width,\n        height: this.display.stage.height\n      })\n    );\n  }\n  checkInitialization() {\n    if (!this.initialized) {\n      throw new Error(\"Core not initialized!\");\n    }\n  }\n  getAudioEngine() {\n    const useToneParam = !!this.configuration.useTone;\n    const audioEngine = useToneParam ? ToneSoundManager : SoundManager;\n    return audioEngine;\n  }\n  get audioEngineType() {\n    const audioEngine = this.getAudioEngine();\n    const audioEngineType = audioEngine === ToneSoundManager ? \"Tone\" : \"Howler\";\n    return audioEngineType;\n  }\n  registerDependencies() {\n    //! lemmy\n    const audioEngine = this.getAudioEngine();\n    Log.colorfulLog(`AUDIO ENGINE: ${this.configuration.useTone ? \"ToneJS\" : \"Howler\"}`, \"#black#lightgreen\");\n    this._connection = this.openConnection();\n    this.container.registerInstance(\"IConnectable\", this._connection);\n    this.container.register(\"ICommunication\", { useClass: Communication }, { lifecycle: Lifecycle.Singleton });\n    if (this.configuration.multiplayer) {\n      this.container.register(\"IStage\", { useClass: HtmlStage }, { lifecycle: Lifecycle.Singleton });\n    } else {\n      this.container.register(\"IStage\", { useClass: Stage }, { lifecycle: Lifecycle.Singleton });\n    }\n    this.container.register(\n      \"CommunicationManager\",\n      { useClass: CommunicationManager },\n      { lifecycle: Lifecycle.Singleton }\n    );\n    this.container.register(\"RequestManager\", { useClass: RequestManager }, { lifecycle: Lifecycle.Singleton });\n    this.container.register(\"ISoundManager\", { useClass: audioEngine }, { lifecycle: Lifecycle.Singleton });\n    this.container.register(\"ISpineAnimations\", { useClass: SpineAnimations }, { lifecycle: Lifecycle.Singleton });\n    this.container.register(\"IVideoPlayer\", { useClass: VideoPlayer });\n    this.container.register(\"ISpineVideoPlayer\", { useClass: SpineVideoPlayer });\n    this.container.register(\"AssetsLoader\", { useClass: AssetsLoader }, { lifecycle: Lifecycle.Singleton });\n    this.container.register(\"ITranslator\", { useClass: I18n }, { lifecycle: Lifecycle.Singleton });\n    this.container.register(\n      \"LocalStorrageManager\",\n      { useClass: LocalStorageManager },\n      { lifecycle: Lifecycle.Singleton }\n    );\n    this.container.register(\"LoadingView\", { useClass: LoadingView }, { lifecycle: Lifecycle.Singleton });\n    this.container.registerInstance(\"ILoadingIndicator\", window.egt.LoadingIndicator);\n  }\n  resolveDependencies() {\n    this._translator = this.container.resolve(\"ITranslator\");\n    this.soundManager = this.container.resolve(\"ISoundManager\");\n    this._spineAnimations = this.container.resolve(\"ISpineAnimations\");\n    this.communication = this.container.resolve(\"CommunicationManager\");\n    this.requestManager = this.container.resolve(\"RequestManager\");\n    this.localStorrageManager = this.container.resolve(\"LocalStorrageManager\");\n    this.assetsLoader = this.container.resolve(\"AssetsLoader\");\n    this.stage = this.container.resolve(\"IStage\");\n    this.loadingView = this.container.resolve(\"LoadingView\");\n  }\n  /**\n   * closeUrl ends up in `location.href` (lobby exit, replayer), so only http(s) is accepted.\n   * `javascript:`, `data:` etc. are dropped to prevent DOM XSS. Relative URLs resolve to http(s) and pass.\n   */\n  sanitizeCloseUrl(raw) {\n    try {\n      const decoded = decodeURI(raw);\n      const { protocol } = new URL(decoded, window.location.href);\n      if (protocol === \"https:\" || protocol === \"http:\") {\n        return decoded;\n      }\n    } catch (e) {\n    }\n    Log.warn(\"Ignoring invalid closeUrl:\", raw);\n    return void 0;\n  }\n  setConfigurationFromURL() {\n    const url = new URL(window.location.href);\n    this.setConfigurationMode(url);\n    this.setConfigurationProperties(url);\n    this.configuration.multiplayer = this.multiPlayerGame.indexOf(this.configuration.gameKey) > -1;\n    this.readWindowSsiConfiguration();\n    this.setHostOverrideFromUrl(url);\n    this.addRecourceRootDir();\n  }\n  getURL() {\n    const cleanPlayerName = this.configuration.playerName;\n    const queryParams = `?sessionToken=${encodeURIComponent(this.configuration.sessionToken)}&casinoId=${encodeURIComponent(this.configuration.casinoId)}&playerId=${encodeURIComponent(this.configuration.playerId)}&tempToken=${encodeURIComponent(this.configuration.tempToken || \"\")}${cleanPlayerName ? \"&playerName=\" + encodeURIComponent(cleanPlayerName) : \"\"}&gameKey=${encodeURIComponent(this.configuration.gameKey)}&currencyCode=${encodeURIComponent(this.configuration.currencyCode)}&demo=${this.configuration.demo}&channel=${encodeURIComponent(this.environment.getDeviceType())}&version=${encodeURIComponent(this.configuration.version)}&browser=${encodeURIComponent(this.environment.getBrowserString())}`;\n    if (this.configuration.multiplayer) {\n      return `${this.configuration.protocol}://${this.configuration.multiplayerHost}${queryParams}`;\n    } else {\n      return `${this.configuration.protocol}://${this.configuration.host}${queryParams}`;\n    }\n  }\n  readWindowSsiConfiguration() {\n    this.configuration.host = this.getWindowSsiProperty(\"host\", \"demoHost\");\n    this.configuration.multiplayerHost = this.getWindowSsiProperty(\"multiplayerHost\", \"demoMultiplayerHost\");\n    this.configuration.lobbyHost = this.getWindowSsiProperty(\"lobbyHost\");\n    this.configuration.apiIntegrationHost = this.getWindowSsiProperty(\"apiIntegrationHost\");\n    this.configuration.historyHost = this.getWindowSsiProperty(\"historyHost\");\n    this.configuration.tournamentHost = this.getWindowSsiProperty(\"tournamentHost\");\n    this.configuration.prizePopServiceHost = this.getWindowSsiProperty(\"prizePopServiceHost\");\n    this.configuration.protocol = this.getWindowSsiProperty(\"protocol\");\n    this.configuration.lobbyRedirectHost = this.getWindowSsiProperty(\"lobbyRedirectHost\");\n    this.configuration.tournamentAPICallTimeout = Number(this.getWindowSsiProperty(\"tournamentAPICallTimeout\"));\n    this.configuration.replayHost = this.getWindowSsiProperty(\"replayHost\");\n    this.configuration.hideFullScreenButton = this.getWindowSsiProperty(\n      \"hideFullScreenButton\"\n    );\n    this.checkForAllowLobbyBlocking();\n  }\n  /**\n   * This checks if there is allowLobbyBlocking and only then takes in account blockLobby parameter\n   * if allowLobbyBlocking is not defined in window.ssi or its false the blockLobby will be forced\n   */\n  checkForAllowLobbyBlocking() {\n    if (window.hasOwnProperty(\"ssi\") && window[\"ssi\"].hasOwnProperty(\"allowLobbyBlocking\")) {\n      if (!window[\"ssi\"].allowLobbyBlocking) {\n        this.configuration.blockLobby = false;\n      }\n    } else {\n      this.configuration.blockLobby = false;\n    }\n  }\n  setStageOptions(url, options) {\n    if (this.configuration.mode === \"desktop\" && !url.searchParams.has(\"align\")) {\n      options.changeOrientation = false;\n      options.align = Align.TOP_CENTER;\n    } else if (url.searchParams.get(\"align\") !== null) {\n      options.align = decodeURI(String(url.searchParams.get(\"align\")));\n    }\n    return options;\n  }\n  getCanvas() {\n    const canvas = DomHelpers.getElementOrCreateNew(\n      \"app-canvas\",\n      \"canvas\",\n      document.getElementById(\"app-root\")\n    );\n    return canvas;\n  }\n  setConfigurationProperties(url) {\n    const paramsMap = {\n      sessionToken: \"string\",\n      playerId: \"string\",\n      playerName: \"string\",\n      casinoId: \"string\",\n      gameKey: \"string\",\n      demo: \"boolean\",\n      language: \"string\",\n      currencyCode: \"string\",\n      devTools: \"boolean\",\n      redundantOverrideReport: \"boolean\",\n      denomination: \"number\",\n      align: \"string\",\n      lobbyOpenType: \"string\",\n      comeFromLobby: \"number\",\n      mute: \"boolean\",\n      bgMusicMute: \"boolean\",\n      useNewReactLobby: \"boolean\",\n      hideHandCursor: \"boolean\",\n      blockLobby: \"boolean\",\n      replaceAssets: \"boolean\",\n      replaceSoundAssets: \"boolean\",\n      replaceImageAssets: \"boolean\",\n      noSounds: \"boolean\",\n      openSection: \"string\",\n      useTone: \"boolean\",\n      layoutType: \"string\"\n    };\n    for (const [key, type] of Object.entries(paramsMap)) {\n      const value = url.searchParams.get(key);\n      if (value !== null) {\n        this.configuration[key] = type === \"boolean\" ? value === \"true\" : type === \"number\" ? Number(value) : String(value);\n      }\n    }\n    if (url.searchParams.get(\"lobbyOpenType\") !== null) {\n      this.configuration.lobbyOpenType = url.searchParams.get(\"lobbyOpenType\") === \"ingame\" ? \"ingame\" : \"fullscreen\";\n    }\n    if (url.searchParams.get(\"closeUrl\") !== null) {\n      const closeUrl = this.sanitizeCloseUrl(String(url.searchParams.get(\"closeUrl\")));\n      if (closeUrl !== void 0) {\n        this.configuration.closeUrl = closeUrl;\n      }\n    }\n    this.configuration.language = this.configuration.language.toLowerCase();\n    this.configuration.currencyCode = this.configuration.currencyCode.toUpperCase();\n  }\n  getWindowSsiProperty(property, demoProperty) {\n    if (window.hasOwnProperty(\"ssi\")) {\n      if (this.configuration.demo && demoProperty && window.ssi.hasOwnProperty(demoProperty)) {\n        return window.ssi[demoProperty];\n      } else if (window.ssi.hasOwnProperty(property)) {\n        return window.ssi[property];\n      }\n    }\n    return this.configuration[property];\n  }\n  setConfigurationMode(url) {\n    var _a;\n    this.configuration.mode = ((_a = url.searchParams.get(\"mode\")) == null ? void 0 : _a.toLowerCase()) || this.environment.getDeviceType();\n  }\n  setHostOverrideFromUrl(url) {\n    if (this.configuration.allowHostOverrideFromUrl) {\n      const hostOverrideProperties = [\n        \"host\",\n        \"protocol\",\n        \"historyHost\",\n        \"multiplayerHost\",\n        \"tournamentHost\",\n        \"prizePopServiceHost\",\n        \"lobbyHost\",\n        \"apiIntegrationHost\",\n        \"lobbyRedirectHost\",\n        \"replayHost\"\n      ];\n      hostOverrideProperties.forEach((property) => {\n        const value = url.searchParams.get(property);\n        if (value !== null) {\n          this.configuration[property] = String(value);\n        }\n      });\n    }\n  }\n  addRecourceRootDir() {\n    if (this.customResourcesHost) {\n      if (\"serviceWorker\" in navigator) {\n        navigator.serviceWorker.getRegistrations().then((registrations) => {\n          registrations.forEach((registration) => {\n            registration.unregister().then((unregistered) => {\n              Log.debug(\n                `Service Worker ${unregistered ? \"unregistered\" : \"still registered\"}`,\n                this.constructor.name\n              );\n            });\n          });\n        });\n      }\n    }\n    if (window.hasOwnProperty(\"ssi\") && window.ssi.hasOwnProperty(\"demoResourcesUrl\") && this.configuration.demo) {\n      this.configuration.resourcesRootDir = window.ssi.demoResourcesUrl;\n    }\n    if (window.hasOwnProperty(\"ssi\") && window.ssi.hasOwnProperty(\"resourcesUrl\") && !this.configuration.demo) {\n      this.configuration.resourcesRootDir = window.ssi.resourcesUrl;\n    }\n  }\n  /**\n   * `replaceAssets` swaps everything, `replaceSoundAssets` only the sounds and\n   * `replaceImageAssets` everything except them. Null means no replacement run.\n   */\n  getAssetsReplaceMode() {\n    const { replaceAssets, replaceSoundAssets, replaceImageAssets } = this.configuration;\n    if (replaceAssets || replaceSoundAssets && replaceImageAssets) {\n      return \"all\";\n    }\n    if (replaceSoundAssets) {\n      return \"sound\";\n    }\n    if (replaceImageAssets) {\n      return \"image\";\n    }\n    return null;\n  }\n  loadAssets() {\n    Log.debug(\"START LOADING ASSETS\", this.constructor.name);\n    if (!this.onBeforeStartLoadingResourcesEmitted) {\n      this.onBeforeStartLoadingResourcesEmitted = true;\n      this.emit(LifeCycle.ON_BEFORE_START_LOADING_RESOURCES, this.assets.getAssetsQueue());\n    }\n    const replaceMode = this.getAssetsReplaceMode();\n    if (this.customResourcesHost && replaceMode) {\n      this.configuration.replaceAssets = false;\n      this.configuration.replaceSoundAssets = false;\n      this.configuration.replaceImageAssets = false;\n      this.assets.replaceAssets(replaceMode).then(() => {\n        this.loadAssets();\n      });\n      return;\n    }\n    if (this.configuration.resourcesRootDir !== \"\") {\n      this.assets.getAssetsQueue().forEach((el) => {\n        if (Array.isArray(el.url)) {\n          el.url = el.url.map((url) => this.replaceUrl(url));\n        } else {\n          el.url = this.replaceUrl(el.url);\n        }\n      });\n    }\n    this.assets.load();\n  }\n  replaceUrl(url) {\n    if (url.includes(this.configuration.resourcesRootDir)) {\n      return url;\n    } else {\n      return this.configuration.resourcesRootDir + url;\n    }\n  }\n  /**\n   * Imports features source code and initialize the loaded feature with\n   * arguments that are passed from game.\n   * @param featuresList\n   */\n  importFeatures(featuresList) {\n    return __async(this, null, function* () {\n      const featureImportPromises = featuresList.map((featureArr) => __async(this, null, function* () {\n        const Feature = yield this.importFeature(featureArr[0]);\n        const FeatureClass = Feature.default;\n        let shouldAddToFeaturesArray = true;\n        if (Object.getOwnPropertyNames(FeatureClass).includes(\"checkAvailability\")) {\n          try {\n            shouldAddToFeaturesArray = yield FeatureClass.checkAvailability();\n          } catch (_err) {\n            shouldAddToFeaturesArray = false;\n          }\n        }\n        return shouldAddToFeaturesArray ? {\n          FeatureClass,\n          args: featureArr.slice(1)\n        } : null;\n      }));\n      const features = yield Promise.all(featureImportPromises);\n      features.filter((feature) => feature !== null).forEach((feature) => {\n        this._game.features = this._game.features.concat(new feature.FeatureClass(...feature.args));\n      });\n      return Promise.resolve();\n    });\n  }\n  importComponents(componentsList) {\n    return __async(this, null, function* () {\n      const componentImportPromises = componentsList.map((componentArr) => __async(this, null, function* () {\n        const Component = yield this.importComponent(componentArr[0]);\n        return {\n          ComponentClass: Component.default,\n          args: componentArr.slice(1)\n        };\n      }));\n      const components = yield Promise.all(componentImportPromises);\n      components.filter((component) => component !== null).forEach((component) => {\n        this._game.components = this._game.components.concat(new component.ComponentClass(...component.args));\n      });\n      return Promise.resolve();\n    });\n  }\n  /**\n   * Remove features that are in removedFeaturesList from priority list\n   * @param removedFeaturesList\n   */\n  filterPriorities(removedFeaturesList) {\n    Object.keys(this._game.featuresPriority).forEach((key) => {\n      this._game.featuresPriority[key] = this._game.featuresPriority[key].filter(\n        (featName) => !removedFeaturesList.includes(featName)\n      );\n    });\n  }\n  /**\n   * This gets features that are defined in game extrenal features\n   * array but are not included in features array passed form server.\n   *\n   * @param features - array of features that must be included in game.\n   */\n  getRemovedFeaturesList(features) {\n    return this._game.getExternalFeatures().filter((feat) => !features.includes(feat[0])).reduce((accumulator, value) => accumulator.concat(value[0]), []);\n  }\n  /**\n   * This filters external features depending on server config\n   * and supported external features list from game.\n   * After filtering is applied the function combines external features and\n   * game features and returns the concatenaed list of features that needs to be\n   * initialized.\n   *\n   * @param features - array of features that must be included in game.\n   */\n  getFeaturesList(features) {\n    return this._game.getExternalFeatures().filter((feat) => features.includes(feat[0])).concat(this._game.getGameFeatures());\n  }\n  // private onSleepChange(val: boolean): void {\n  //     if (val && !this.noSleep.isEnabled) {\n  //         this.noSleep.enable();\n  //     } else if (!val) {\n  //         this.noSleep.disable();\n  //     }\n  // }\n}\nexport {\n  AddPriority,\n  Align,\n  AnalyticsDispatcher,\n  AssetPriority,\n  AssetsCollection,\n  BalanceRequest,\n  BalanceResponse,\n  BaseComponent,\n  BaseComponentConfiguration,\n  BaseController,\n  BaseFeature,\n  BaseFeatures,\n  BaseGame,\n  BaseModesConfigurations,\n  BaseStore,\n  BaseTemplate,\n  BusMessage,\n  ConditionObject,\n  DebugPriorities,\n  DefaultAssets,\n  DefaultValue,\n  DefenceCodeRequest,\n  DomHelpers,\n  DynamicPositionObject,\n  ErrorManager,\n  ErrorTypes,\n  FeatureFlagGroups,\n  FeatureFlags,\n  FeatureFlagsStore,\n  GameTypes,\n  IAsset,\n  IAssetsLoader,\n  IBaseConfiguration,\n  IConfiguration,\n  IConnectable,\n  IContentLoadData,\n  IDeveloperTools,\n  IDisplayData,\n  IDynamicPosition,\n  IElementVisabilty,\n  IEnvironment,\n  IErrorData,\n  IFeatureAssetsArray,\n  IFeatureFlag,\n  IFeatureFlags,\n  ILifeCycle,\n  ILinesConfiguration,\n  ILoadAsset,\n  ILoadingIndicator,\n  IMediaInfoData,\n  IModifiedDynamicPosition,\n  IOrientation,\n  IPosition,\n  IPositionPoint,\n  IRequest,\n  IRestriction,\n  IScratchTemplateConstructorProps,\n  ISlotTemplateConstructorProps,\n  ISoundAsset,\n  ISoundManager,\n  ISpineVideoConfig,\n  ISpineVideoPlayer,\n  IStageOptions,\n  ITemplate,\n  ITranslator,\n  IVideoPlayer,\n  IVideoPositionPoint,\n  JackpotLevelStats,\n  JackpotStatsResponse,\n  Language,\n  LifeCycle,\n  LoadingView,\n  LobbyOpenType,\n  LobbyStyle,\n  LocalFeatureFlags,\n  Log,\n  LoggerGroups,\n  ModifyAssets,\n  ModifyValue,\n  Money,\n  MoneyFormatter,\n  NOT_MIGRATE_TEXT,\n  OverrideDefaultProperties,\n  PositionObject,\n  PostMessageDispatcher,\n  RESTRICTION_TYPE_BY_FEATURE_FLAG,\n  RemoveAssets,\n  ReplayerCommandType,\n  ReplayerRoundType,\n  RequestManager,\n  RestrictionType,\n  Scale,\n  ScaleByGlobalReelsTimeScale,\n  ScaleUntil,\n  SessionMetricsCollector,\n  SpineUseAnimatorSlotPosition,\n  SpineVideoPlayer,\n  StatsIntervalTracker,\n  SymbolCredits,\n  Timers,\n  UserActionType,\n  VideoTypes,\n  computeSpineDelta,\n  logGameComponents,\n  logSubjectsValues\n};\nexport default window.__SL_CORE = new Core();\n","// import { BaseFeatures } from '@egt/core';\n// import { Features } from '@egt/slot';\n\nimport * as ES6Promise from 'es6-promise';\n\nimport 'reflect-metadata';\n\nimport Core from '@egt/core';\n\nES6Promise.polyfill();\n\n\n\nlet portal: Promise<any>;\nportal = import(\n/* webpackChunkName: \"games/portal\" */\n'@egt/portal');\n/* ===== portal end placeholder ===== */\n\n/* tslint:disable:trailing-comma */\nCore.importGame = (gameKey: string): Promise<any> => {\n    /* ===== This code block was automatically generated by prebuild.js ===== */\n    /* ===== Start of code block ===== */\n            if ('FHEBLBNSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLBNSlot\" */\n                    '@egt/fheblbnslot'\n                );\n            }\n            if ('BFHEBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BFHEBLSlot\" */\n                    '@egt/bfheblslot'\n                );\n            }\n            if ('TBHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TBHSlot\" */\n                    '@egt/tbhslot'\n                );\n            }\n            if ('FRDHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRDHSlot\" */\n                    '@egt/frdhslot'\n                );\n            }\n            if ('RSSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/RSSlot\" */\n                    '@egt/rsslot'\n                );\n            }\n            if ('EDSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/EDSlot\" */\n                    '@egt/edslot'\n                );\n            }\n            if ('LHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/LHSlot\" */\n                    '@egt/lhslot'\n                );\n            }\n            if ('EPSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/EPSlot\" */\n                    '@egt/epslot'\n                );\n            }\n            if ('ABSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/ABSlot\" */\n                    '@egt/abslot'\n                );\n            }\n            if ('FSHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSHSlot\" */\n                    '@egt/fshslot'\n                );\n            }\n            if ('TSHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TSHSlot\" */\n                    '@egt/tshslot'\n                );\n            }\n            if ('TSHPLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TSHPLSlot\" */\n                    '@egt/tshplslot'\n                );\n            }\n            if ('FHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHSlot\" */\n                    '@egt/fhslot'\n                );\n            }\n            if ('FSHPLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSHPLSlot\" */\n                    '@egt/fshplslot'\n                );\n            }\n            if ('BHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BHSlot\" */\n                    '@egt/bhslot'\n                );\n            }\n            if ('BHPLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BHPLSlot\" */\n                    '@egt/bhplslot'\n                );\n            }\n            if ('FMCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FMCSlot\" */\n                    '@egt/fmcslot'\n                );\n            }\n            if ('SCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SCSlot\" */\n                    '@egt/scslot'\n                );\n            }\n            if ('SCPLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SCPLSlot\" */\n                    '@egt/scplslot'\n                );\n            }\n            if ('SCDSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SCDSlot\" */\n                    '@egt/scdslot'\n                );\n            }\n            if ('FSCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSCSlot\" */\n                    '@egt/fscslot'\n                );\n            }\n            if ('FBHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHSlot\" */\n                    '@egt/fbhslot'\n                );\n            }\n            if ('FBHIBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHIBSlot\" */\n                    '@egt/fbhibslot'\n                );\n            }\n            if ('VNABSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/VNABSlot\" */\n                    '@egt/vnabslot'\n                );\n            }\n            if ('VNSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/VNSlot\" */\n                    '@egt/vnslot'\n                );\n            }\n            if ('VNBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/VNBLSlot\" */\n                    '@egt/vnblslot'\n                );\n            }\n            if ('SACBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SACBLSlot\" */\n                    '@egt/sacblslot'\n                );\n            }\n            if ('FHEIAGSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEIAGSlot\" */\n                    '@egt/fheiagslot'\n                );\n            }\n            if ('FHESlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHESlot\" */\n                    '@egt/fheslot'\n                );\n            }\n            if ('RORSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/RORSlot\" */\n                    '@egt/rorslot'\n                );\n            }\n            if ('RORPLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/RORPLSlot\" */\n                    '@egt/rorplslot'\n                );\n            }\n            if ('BHBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BHBLSlot\" */\n                    '@egt/bhblslot'\n                );\n            }\n            if ('FDCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FDCSlot\" */\n                    '@egt/fdcslot'\n                );\n            }\n            if ('TNDCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TNDCSlot\" */\n                    '@egt/tndcslot'\n                );\n            }\n            if ('FDHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FDHSlot\" */\n                    '@egt/fdhslot'\n                );\n            }\n            if ('TNDHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TNDHSlot\" */\n                    '@egt/tndhslot'\n                );\n            }\n            if ('TSHBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TSHBLSlot\" */\n                    '@egt/tshblslot'\n                );\n            }\n            if ('FSHBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSHBLSlot\" */\n                    '@egt/fshblslot'\n                );\n            }\n            if ('FSHBLVKRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSHBLVKRSlot\" */\n                    '@egt/fshblvkrslot'\n                );\n            }\n            if ('FSCBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSCBLSlot\" */\n                    '@egt/fscblslot'\n                );\n            }\n            if ('FSCBLSSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSCBLSSlot\" */\n                    '@egt/fscblsslot'\n                );\n            }\n            if ('FSCBLMSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSCBLMSlot\" */\n                    '@egt/fscblmslot'\n                );\n            }\n            if ('SCASlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SCASlot\" */\n                    '@egt/scaslot'\n                );\n            }\n            if ('SCSBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SCSBSlot\" */\n                    '@egt/scsbslot'\n                );\n            }\n            if ('SCWSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SCWSlot\" */\n                    '@egt/scwslot'\n                );\n            }\n            if ('FHBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHBLSlot\" */\n                    '@egt/fhblslot'\n                );\n            }\n            if ('FHEBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLSlot\" */\n                    '@egt/fheblslot'\n                );\n            }\n            if ('BPFHEBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BPFHEBLSlot\" */\n                    '@egt/bpfheblslot'\n                );\n            }\n            if ('FHEBLALBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLALBSlot\" */\n                    '@egt/fheblalbslot'\n                );\n            }\n            if ('FHEBLAMSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLAMSlot\" */\n                    '@egt/fheblamslot'\n                );\n            }\n            if ('FHEBLMCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLMCSlot\" */\n                    '@egt/fheblmcslot'\n                );\n            }\n            if ('FHEBLSSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLSSlot\" */\n                    '@egt/fheblsslot'\n                );\n            }\n            if ('FHEBLGBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLGBSlot\" */\n                    '@egt/fheblgbslot'\n                );\n            }\n            if ('FHEBLGRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLGRSlot\" */\n                    '@egt/fheblgrslot'\n                );\n            }\n            if ('FHEBLKSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLKSlot\" */\n                    '@egt/fheblkslot'\n                );\n            }\n            if ('SCBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SCBLSlot\" */\n                    '@egt/scblslot'\n                );\n            }\n            if ('FDHBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FDHBLSlot\" */\n                    '@egt/fdhblslot'\n                );\n            }\n            if ('FBHBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLSlot\" */\n                    '@egt/fbhblslot'\n                );\n            }\n            if ('FBHBLVRBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLVRBSlot\" */\n                    '@egt/fbhblvrbslot'\n                );\n            }\n            if ('FBHBLABSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLABSlot\" */\n                    '@egt/fbhblabslot'\n                );\n            }\n            if ('FBHBLLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLLSlot\" */\n                    '@egt/fbhbllslot'\n                );\n            }\n            if ('FBHBLBBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLBBSlot\" */\n                    '@egt/fbhblbbslot'\n                );\n            }\n            if ('DRHCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/DRHCSlot\" */\n                    '@egt/drhcslot'\n                );\n            }\n            if ('PCHCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/PCHCSlot\" */\n                    '@egt/pchcslot'\n                );\n            }\n            if ('LTHCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/LTHCSlot\" */\n                    '@egt/lthcslot'\n                );\n            }\n            if ('MSHCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/MSHCSlot\" */\n                    '@egt/mshcslot'\n                );\n            }\n            if ('FCHJSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FCHJSlot\" */\n                    '@egt/fchjslot'\n                );\n            }\n            if ('VGSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/VGSlot\" */\n                    '@egt/vgslot'\n                );\n            }\n            if ('THSFSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/THSFSlot\" */\n                    '@egt/thsfslot'\n                );\n            }\n            if ('TBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TBSlot\" */\n                    '@egt/tbslot'\n                );\n            }\n            if ('OLHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OLHSlot\" */\n                    '@egt/olhslot'\n                );\n            }\n            if ('TCWSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TCWSlot\" */\n                    '@egt/tcwslot'\n                );\n            }\n            if ('TWGSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TWGSlot\" */\n                    '@egt/twgslot'\n                );\n            }\n            if ('TDHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TDHSlot\" */\n                    '@egt/tdhslot'\n                );\n            }\n            if ('TBHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TBHRSlot\" */\n                    '@egt/tbhrslot'\n                );\n            }\n            if ('FBHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHRSlot\" */\n                    '@egt/fbhrslot'\n                );\n            }\n            if ('MDSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/MDSlot\" */\n                    '@egt/mdslot'\n                );\n            }\n            if ('OSHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OSHSlot\" */\n                    '@egt/oshslot'\n                );\n            }\n            if ('BORSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BORSlot\" */\n                    '@egt/borslot'\n                );\n            }\n            if ('OBHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OBHSlot\" */\n                    '@egt/obhslot'\n                );\n            }\n            if ('FLKSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FLKSlot\" */\n                    '@egt/flkslot'\n                );\n            }\n            if ('STSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/STSlot\" */\n                    '@egt/stslot'\n                );\n            }\n            if ('STHWSASlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/STHWSASlot\" */\n                    '@egt/sthwsaslot'\n                );\n            }\n            if ('FHBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHBSlot\" */\n                    '@egt/fhbslot'\n                );\n            }\n            if ('ZWSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/ZWSlot\" */\n                    '@egt/zwslot'\n                );\n            }\n            if ('BCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BCSlot\" */\n                    '@egt/bcslot'\n                );\n            }\n            if ('BCBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BCBSlot\" */\n                    '@egt/bcbslot'\n                );\n            }\n            if ('TCHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TCHSlot\" */\n                    '@egt/tchslot'\n                );\n            }\n            if ('TCHGRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TCHGRSlot\" */\n                    '@egt/tchgrslot'\n                );\n            }\n            if ('TWCHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TWCHSlot\" */\n                    '@egt/twchslot'\n                );\n            }\n            if ('TCHJSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TCHJSlot\" */\n                    '@egt/tchjslot'\n                );\n            }\n            if ('TSDSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TSDSlot\" */\n                    '@egt/tsdslot'\n                );\n            }\n            if ('TSDTWSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TSDTWSlot\" */\n                    '@egt/tsdtwslot'\n                );\n            }\n            if ('TSDTBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TSDTBSlot\" */\n                    '@egt/tsdtbslot'\n                );\n            }\n            if ('TSPCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TSPCSlot\" */\n                    '@egt/tspcslot'\n                );\n            }\n            if ('FBHSSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHSSlot\" */\n                    '@egt/fbhsslot'\n                );\n            }\n            if ('VGSASlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/VGSASlot\" */\n                    '@egt/vgsaslot'\n                );\n            }\n            if ('VGPLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/VGPLSlot\" */\n                    '@egt/vgplslot'\n                );\n            }\n            if ('TSHSASlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TSHSASlot\" */\n                    '@egt/tshsaslot'\n                );\n            }\n            if ('FSHSASlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSHSASlot\" */\n                    '@egt/fshsaslot'\n                );\n            }\n            if ('FSHGBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSHGBSlot\" */\n                    '@egt/fshgbslot'\n                );\n            }\n            if ('BHSASlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BHSASlot\" */\n                    '@egt/bhsaslot'\n                );\n            }\n            if ('BESlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BESlot\" */\n                    '@egt/beslot'\n                );\n            }\n            if ('RORSASlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/RORSASlot\" */\n                    '@egt/rorsaslot'\n                );\n            }\n            if ('UHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/UHSlot\" */\n                    '@egt/uhslot'\n                );\n            }\n            if ('UFSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/UFSlot\" */\n                    '@egt/ufslot'\n                );\n            }\n            if ('OSFSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OSFSlot\" */\n                    '@egt/osfslot'\n                );\n            }\n            if ('OHSRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OHSRSlot\" */\n                    '@egt/ohsrslot'\n                );\n            }\n            if ('OHSHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OHSHRSlot\" */\n                    '@egt/ohshrslot'\n                );\n            }\n            if ('OHSRSSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OHSRSSlot\" */\n                    '@egt/ohsrsslot'\n                );\n            }\n            if ('SRSHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SRSHRSlot\" */\n                    '@egt/srshrslot'\n                );\n            }\n            if ('FCHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FCHSlot\" */\n                    '@egt/fchslot'\n                );\n            }\n            if ('FRSHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRSHRSlot\" */\n                    '@egt/frshrslot'\n                );\n            }\n            if ('OHCHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OHCHSlot\" */\n                    '@egt/ohchslot'\n                );\n            }\n            if ('XRideMP' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/XRideMP\" */\n                    '@egt/xridemp'\n                );\n            }\n            if ('TBCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TBCSlot\" */\n                    '@egt/tbcslot'\n                );\n            }\n            if ('SJSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SJSlot\" */\n                    '@egt/sjslot'\n                );\n            }\n            if ('OBCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OBCSlot\" */\n                    '@egt/obcslot'\n                );\n            }\n            if ('FBCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBCSlot\" */\n                    '@egt/fbcslot'\n                );\n            }\n            if ('FSFSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSFSlot\" */\n                    '@egt/fsfslot'\n                );\n            }\n            if ('FRSRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRSRSlot\" */\n                    '@egt/frsrslot'\n                );\n            }\n            if ('FSFBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSFBLSlot\" */\n                    '@egt/fsfblslot'\n                );\n            }\n            if ('TSFSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TSFSlot\" */\n                    '@egt/tsfslot'\n                );\n            }\n            if ('TSFBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TSFBLSlot\" */\n                    '@egt/tsfblslot'\n                );\n            }\n            if ('OSHSSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OSHSSlot\" */\n                    '@egt/oshsslot'\n                );\n            }\n            if ('FBCSSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBCSSlot\" */\n                    '@egt/fbcsslot'\n                );\n            }\n            if ('HFSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/HFSlot\" */\n                    '@egt/hfslot'\n                );\n            }\n            if ('PVHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/PVHRSlot\" */\n                    '@egt/pvhrslot'\n                );\n            }\n            if ('BCHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BCHRSlot\" */\n                    '@egt/bchrslot'\n                );\n            }\n            if ('FBRHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBRHRSlot\" */\n                    '@egt/fbrhrslot'\n                );\n            }\n            if ('TCHHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TCHHRSlot\" */\n                    '@egt/tchhrslot'\n                );\n            }\n            if ('TSDHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TSDHRSlot\" */\n                    '@egt/tsdhrslot'\n                );\n            }\n            if ('TNSHRHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TNSHRHRSlot\" */\n                    '@egt/tnshrhrslot'\n                );\n            }\n            if ('SRSSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SRSSlot\" */\n                    '@egt/srsslot'\n                );\n            }\n            if ('TNSHHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TNSHHRSlot\" */\n                    '@egt/tnshhrslot'\n                );\n            }\n            if ('BORHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BORHRSlot\" */\n                    '@egt/borhrslot'\n                );\n            }\n            if ('BOSHHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BOSHHRSlot\" */\n                    '@egt/boshhrslot'\n                );\n            }\n            if ('FCHJHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FCHJHRSlot\" */\n                    '@egt/fchjhrslot'\n                );\n            }\n            if ('PVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/PVSlot\" */\n                    '@egt/pvslot'\n                );\n            }\n            if ('GVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/GVSlot\" */\n                    '@egt/gvslot'\n                );\n            }\n            if ('OVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OVSlot\" */\n                    '@egt/ovslot'\n                );\n            }\n            if ('GVHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/GVHRSlot\" */\n                    '@egt/gvhrslot'\n                );\n            }\n            if ('TVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TVSlot\" */\n                    '@egt/tvslot'\n                );\n            }\n            if ('MFICTSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/MFICTSlot\" */\n                    '@egt/mfictslot'\n                );\n            }\n            if ('OTPVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OTPVSlot\" */\n                    '@egt/otpvslot'\n                );\n            }\n            if ('OTPVHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OTPVHRSlot\" */\n                    '@egt/otpvhrslot'\n                );\n            }\n            if ('TVHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TVHRSlot\" */\n                    '@egt/tvhrslot'\n                );\n            }\n            if ('HFCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/HFCSlot\" */\n                    '@egt/hfcslot'\n                );\n            }\n            if ('SBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SBSlot\" */\n                    '@egt/sbslot'\n                );\n            }\n            if ('TSSSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TSSSlot\" */\n                    '@egt/tssslot'\n                );\n            }\n            if ('KTSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/KTSlot\" */\n                    '@egt/ktslot'\n                );\n            }\n            if ('THBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/THBSlot\" */\n                    '@egt/thbslot'\n                );\n            }\n            if ('TADSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TADSlot\" */\n                    '@egt/tadslot'\n                );\n            }\n            if ('DRHCVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/DRHCVSlot\" */\n                    '@egt/drhcvslot'\n                );\n            }\n            if ('PCHCVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/PCHCVSlot\" */\n                    '@egt/pchcvslot'\n                );\n            }\n            if ('LTHCVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/LTHCVSlot\" */\n                    '@egt/lthcvslot'\n                );\n            }\n            if ('PROSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/PROSlot\" */\n                    '@egt/proslot'\n                );\n            }\n            if ('SDSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SDSlot\" */\n                    '@egt/sdslot'\n                );\n            }\n            if ('STOTSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/STOTSlot\" */\n                    '@egt/stotslot'\n                );\n            }\n            if ('BHESlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BHESlot\" */\n                    '@egt/bheslot'\n                );\n            }\n            if ('DWSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/DWSlot\" */\n                    '@egt/dwslot'\n                );\n            }\n            if ('FXSJSSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FXSJSSlot\" */\n                    '@egt/fxsjsslot'\n                );\n            }\n            if ('ZWBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/ZWBLSlot\" */\n                    '@egt/zwblslot'\n                );\n            }\n            if ('ZWXBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/ZWXBLSlot\" */\n                    '@egt/zwxblslot'\n                );\n            }\n            if ('ZWXBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/ZWXBLVSlot\" */\n                    '@egt/zwxblvslot'\n                );\n            }\n            if ('TFWSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TFWSlot\" */\n                    '@egt/tfwslot'\n                );\n            }\n            if ('VHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/VHSlot\" */\n                    '@egt/vhslot'\n                );\n            }\n            if ('VHHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/VHHRSlot\" */\n                    '@egt/vhhrslot'\n                );\n            }\n            if ('SUCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SUCSlot\" */\n                    '@egt/sucslot'\n                );\n            }\n            if ('FZWBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FZWBLSlot\" */\n                    '@egt/fzwblslot'\n                );\n            }\n            if ('FLKBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FLKBLSlot\" */\n                    '@egt/flkblslot'\n                );\n            }\n            if ('FLKBLPSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FLKBLPSlot\" */\n                    '@egt/flkblpslot'\n                );\n            }\n            if ('FLKBLGBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FLKBLGBSlot\" */\n                    '@egt/flkblgbslot'\n                );\n            }\n            if ('SMCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SMCSlot\" */\n                    '@egt/smcslot'\n                );\n            }\n            if ('FBHBLPBVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLPBVSlot\" */\n                    '@egt/fbhblpbvslot'\n                );\n            }\n            if ('FBHBLCRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLCRSlot\" */\n                    '@egt/fbhblcrslot'\n                );\n            }\n            if ('FBHBLBNSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLBNSlot\" */\n                    '@egt/fbhblbnslot'\n                );\n            }\n            if ('FBHBLCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLCSlot\" */\n                    '@egt/fbhblcslot'\n                );\n            }\n            if ('FBHBLGOBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLGOBSlot\" */\n                    '@egt/fbhblgobslot'\n                );\n            }\n            if ('FBHBLPBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLPBLSlot\" */\n                    '@egt/fbhblpblslot'\n                );\n            }\n            if ('FBHBLMRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLMRSlot\" */\n                    '@egt/fbhblmrslot'\n                );\n            }\n            if ('FBHBLBGSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLBGSlot\" */\n                    '@egt/fbhblbgslot'\n                );\n            }\n            if ('FBHBLVGOBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLVGOBSlot\" */\n                    '@egt/fbhblvgobslot'\n                );\n            }\n            if ('FBHBLSRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLSRSlot\" */\n                    '@egt/fbhblsrslot'\n                );\n            }\n            if ('FBHBLALBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLALBSlot\" */\n                    '@egt/fbhblalbslot'\n                );\n            }\n            if ('FBHBLPUSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLPUSlot\" */\n                    '@egt/fbhblpuslot'\n                );\n            }\n            if ('FBHBLCRCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLCRCSlot\" */\n                    '@egt/fbhblcrcslot'\n                );\n            }\n            if ('FBHBLSSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLSSlot\" */\n                    '@egt/fbhblsslot'\n                );\n            }\n            if ('BOSHBLSBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BOSHBLSBSlot\" */\n                    '@egt/boshblsbslot'\n                );\n            }\n            if ('FBHBLSRBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLSRBSlot\" */\n                    '@egt/fbhblsrbslot'\n                );\n            }\n            if ('FBHBLOSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLOSlot\" */\n                    '@egt/fbhbloslot'\n                );\n            }\n            if ('FBHBOSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBOSlot\" */\n                    '@egt/fbhboslot'\n                );\n            }\n            if ('FBHOSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHOSlot\" */\n                    '@egt/fbhoslot'\n                );\n            }\n            if ('FBHBLVBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLVBSlot\" */\n                    '@egt/fbhblvbslot'\n                );\n            }\n            if ('FRLKEBLLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRLKEBLLSlot\" */\n                    '@egt/frlkebllslot'\n                );\n            }\n            if ('FRLKEBLVJSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRLKEBLVJSlot\" */\n                    '@egt/frlkeblvjslot'\n                );\n            }\n            if ('TDCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TDCSlot\" */\n                    '@egt/tdcslot'\n                );\n            }\n            if ('FVSFSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FVSFSlot\" */\n                    '@egt/fvsfslot'\n                );\n            }\n            if ('FVSRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FVSRSlot\" */\n                    '@egt/fvsrslot'\n                );\n            }\n            if ('TNSFSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TNSFSlot\" */\n                    '@egt/tnsfslot'\n                );\n            }\n            if ('CRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/CRSlot\" */\n                    '@egt/crslot'\n                );\n            }\n            if ('BORJWSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BORJWSlot\" */\n                    '@egt/borjwslot'\n                );\n            }\n            if ('SWSSSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SWSSSlot\" */\n                    '@egt/swssslot'\n                );\n            }\n            if ('SWSSHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SWSSHRSlot\" */\n                    '@egt/swsshrslot'\n                );\n            }\n            if ('TNBCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TNBCSlot\" */\n                    '@egt/tnbcslot'\n                );\n            }\n            if ('FVCHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FVCHSlot\" */\n                    '@egt/fvchslot'\n                );\n            }\n            if ('FVSHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FVSHRSlot\" */\n                    '@egt/fvshrslot'\n                );\n            }\n            if ('FVBPSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FVBPSlot\" */\n                    '@egt/fvbpslot'\n                );\n            }\n            if ('FVBPSSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FVBPSSlot\" */\n                    '@egt/fvbpsslot'\n                );\n            }\n            if ('FVCHTSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FVCHTSlot\" */\n                    '@egt/fvchtslot'\n                );\n            }\n            if ('FVCHTFBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FVCHTFBSlot\" */\n                    '@egt/fvchtfbslot'\n                );\n            }\n            if ('JWSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/JWSlot\" */\n                    '@egt/jwslot'\n                );\n            }\n            if ('FXSFSSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FXSFSSlot\" */\n                    '@egt/fxsfsslot'\n                );\n            }\n            if ('FSAWSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSAWSlot\" */\n                    '@egt/fsawslot'\n                );\n            }\n            if ('ARSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/ARSlot\" */\n                    '@egt/arslot'\n                );\n            }\n            if ('TWLHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TWLHSlot\" */\n                    '@egt/twlhslot'\n                );\n            }\n            if ('TNLHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TNLHSlot\" */\n                    '@egt/tnlhslot'\n                );\n            }\n            if ('OHLHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OHLHSlot\" */\n                    '@egt/ohlhslot'\n                );\n            }\n            if ('OHCHTSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OHCHTSlot\" */\n                    '@egt/ohchtslot'\n                );\n            }\n            if ('FRLHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRLHSlot\" */\n                    '@egt/frlhslot'\n                );\n            }\n            if ('FRCHTSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRCHTSlot\" */\n                    '@egt/frchtslot'\n                );\n            }\n            if ('FTBRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FTBRSlot\" */\n                    '@egt/ftbrslot'\n                );\n            }\n            if ('BOSHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BOSHSlot\" */\n                    '@egt/boshslot'\n                );\n            }\n            if ('BGSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BGSlot\" */\n                    '@egt/bgslot'\n                );\n            }\n            if ('FRBPSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRBPSlot\" */\n                    '@egt/frbpslot'\n                );\n            }\n            if ('BGWBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BGWBSlot\" */\n                    '@egt/bgwbslot'\n                );\n            }\n            if ('BGIBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BGIBSlot\" */\n                    '@egt/bgibslot'\n                );\n            }\n            if ('BGJSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BGJSlot\" */\n                    '@egt/bgjslot'\n                );\n            }\n            if ('WGSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/WGSlot\" */\n                    '@egt/wgslot'\n                );\n            }\n            if ('BGPSSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BGPSSlot\" */\n                    '@egt/bgpsslot'\n                );\n            }\n            if ('BGTCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BGTCSlot\" */\n                    '@egt/bgtcslot'\n                );\n            }\n            if ('BGBCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BGBCSlot\" */\n                    '@egt/bgbcslot'\n                );\n            }\n            if ('BGCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BGCSlot\" */\n                    '@egt/bgcslot'\n                );\n            }\n            if ('BGHBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BGHBSlot\" */\n                    '@egt/bghbslot'\n                );\n            }\n            if ('BGSBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BGSBSlot\" */\n                    '@egt/bgsbslot'\n                );\n            }\n            if ('BGABSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BGABSlot\" */\n                    '@egt/bgabslot'\n                );\n            }\n            if ('BGLBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BGLBSlot\" */\n                    '@egt/bglbslot'\n                );\n            }\n            if ('OHDHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OHDHSlot\" */\n                    '@egt/ohdhslot'\n                );\n            }\n            if ('FRDCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRDCSlot\" */\n                    '@egt/frdcslot'\n                );\n            }\n            if ('GAGKLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/GAGKLSlot\" */\n                    '@egt/gagklslot'\n                );\n            }\n            if ('GAGKLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/GAGKLVSlot\" */\n                    '@egt/gagklvslot'\n                );\n            }\n            if ('GAGKLBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/GAGKLBSlot\" */\n                    '@egt/gagklbslot'\n                );\n            }\n            if ('FRSPSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRSPSlot\" */\n                    '@egt/frspslot'\n                );\n            }\n            if ('OHDCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OHDCSlot\" */\n                    '@egt/ohdcslot'\n                );\n            }\n            if ('OHSPSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OHSPSlot\" */\n                    '@egt/ohspslot'\n                );\n            }\n            if ('FVCLHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FVCLHSlot\" */\n                    '@egt/fvclhslot'\n                );\n            }\n            if ('FVSPSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FVSPSlot\" */\n                    '@egt/fvspslot'\n                );\n            }\n            if ('BOSHJWSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BOSHJWSlot\" */\n                    '@egt/boshjwslot'\n                );\n            }\n            if ('SCWMSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SCWMSlot\" */\n                    '@egt/scwmslot'\n                );\n            }\n            if ('SCCHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SCCHSlot\" */\n                    '@egt/scchslot'\n                );\n            }\n            if ('SCCHCSSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SCCHCSSlot\" */\n                    '@egt/scchcsslot'\n                );\n            }\n            if ('SCCHBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SCCHBSlot\" */\n                    '@egt/scchbslot'\n                );\n            }\n            if ('SCCHBTSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SCCHBTSlot\" */\n                    '@egt/scchbtslot'\n                );\n            }\n            if ('SCCHZSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SCCHZSlot\" */\n                    '@egt/scchzslot'\n                );\n            }\n            if ('SCCHSBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SCCHSBSlot\" */\n                    '@egt/scchsbslot'\n                );\n            }\n            if ('SCCHPSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SCCHPSlot\" */\n                    '@egt/scchpslot'\n                );\n            }\n            if ('SCCHPDSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SCCHPDSlot\" */\n                    '@egt/scchpdslot'\n                );\n            }\n            if ('SCCHHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SCCHHSlot\" */\n                    '@egt/scchhslot'\n                );\n            }\n            if ('TWBHCHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TWBHCHSlot\" */\n                    '@egt/twbhchslot'\n                );\n            }\n            if (!gameKey || 'Portal' === gameKey || 'Tournaments' === gameKey) {\n                return portal;\n            }\n            if ('BHIScratch' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BHIScratch\" */\n                    '@egt/bhiscratch'\n                );\n            }\n            if ('OHSHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OHSHSlot\" */\n                    '@egt/ohshslot'\n                );\n            }\n            if ('FRSHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRSHSlot\" */\n                    '@egt/frshslot'\n                );\n            }\n            if ('FYHBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FYHBSlot\" */\n                    '@egt/fyhbslot'\n                );\n            }\n            if ('EWCHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/EWCHSlot\" */\n                    '@egt/ewchslot'\n                );\n            }\n            if ('TNCLHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TNCLHSlot\" */\n                    '@egt/tnclhslot'\n                );\n            }\n            if ('TNBPSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TNBPSlot\" */\n                    '@egt/tnbpslot'\n                );\n            }\n            if ('TWCLHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TWCLHSlot\" */\n                    '@egt/twclhslot'\n                );\n            }\n            if ('TWBPSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TWBPSlot\" */\n                    '@egt/twbpslot'\n                );\n            }\n            if ('TWSPSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TWSPSlot\" */\n                    '@egt/twspslot'\n                );\n            }\n            if ('TWSRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TWSRSlot\" */\n                    '@egt/twsrslot'\n                );\n            }\n            if ('TSDIBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TSDIBSlot\" */\n                    '@egt/tsdibslot'\n                );\n            }\n            if ('FRCLHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRCLHSlot\" */\n                    '@egt/frclhslot'\n                );\n            }\n            if ('OHCLHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OHCLHSlot\" */\n                    '@egt/ohclhslot'\n                );\n            }\n            if ('OHBPSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OHBPSlot\" */\n                    '@egt/ohbpslot'\n                );\n            }\n            if ('FVSHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FVSHSlot\" */\n                    '@egt/fvshslot'\n                );\n            }\n            if ('TNSHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TNSHRSlot\" */\n                    '@egt/tnshrslot'\n                );\n            }\n            if ('TNSHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TNSHSlot\" */\n                    '@egt/tnshslot'\n                );\n            }\n            if ('TNCHTSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TNCHTSlot\" */\n                    '@egt/tnchtslot'\n                );\n            }\n            if ('FSHBLBVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSHBLBVSlot\" */\n                    '@egt/fshblbvslot'\n                );\n            }\n            if ('TWSHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TWSHSlot\" */\n                    '@egt/twshslot'\n                );\n            }\n            if ('TWSHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TWSHRSlot\" */\n                    '@egt/twshrslot'\n                );\n            }\n            if ('TWCHTSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TWCHTSlot\" */\n                    '@egt/twchtslot'\n                );\n            }\n            if ('FSHBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSHBLVSlot\" */\n                    '@egt/fshblvslot'\n                );\n            }\n            if ('FSHBLCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSHBLCSlot\" */\n                    '@egt/fshblcslot'\n                );\n            }\n            if ('FSHBLBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSHBLBSlot\" */\n                    '@egt/fshblbslot'\n                );\n            }\n            if ('FSHBLMAKSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSHBLMAKSlot\" */\n                    '@egt/fshblmakslot'\n                );\n            }\n            if ('FSHBLBPSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSHBLBPSlot\" */\n                    '@egt/fshblbpslot'\n                );\n            }\n            if ('FSHBLVLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSHBLVLSlot\" */\n                    '@egt/fshblvlslot'\n                );\n            }\n            if ('FSHBLSBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSHBLSBSlot\" */\n                    '@egt/fshblsbslot'\n                );\n            }\n            if ('FSHBLNBHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSHBLNBHSlot\" */\n                    '@egt/fshblnbhslot'\n                );\n            }\n            if ('FSHBLOBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSHBLOBSlot\" */\n                    '@egt/fshblobslot'\n                );\n            }\n            if ('FSHBLVBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSHBLVBSlot\" */\n                    '@egt/fshblvbslot'\n                );\n            }\n            if ('FRVHBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRVHBLSlot\" */\n                    '@egt/frvhblslot'\n                );\n            }\n            if ('FSHBLOXSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSHBLOXSlot\" */\n                    '@egt/fshbloxslot'\n                );\n            }\n            if ('FSHBLVOXSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSHBLVOXSlot\" */\n                    '@egt/fshblvoxslot'\n                );\n            }\n            if ('FRSCBLBTSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRSCBLBTSlot\" */\n                    '@egt/frscblbtslot'\n                );\n            }\n            if ('FRSCBLBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRSCBLBSlot\" */\n                    '@egt/frscblbslot'\n                );\n            }\n            if ('FRSCBLCBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRSCBLCBSlot\" */\n                    '@egt/frscblcbslot'\n                );\n            }\n            if ('FRSCBLMRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRSCBLMRSlot\" */\n                    '@egt/frscblmrslot'\n                );\n            }\n            if ('FRSCBLMDSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRSCBLMDSlot\" */\n                    '@egt/frscblmdslot'\n                );\n            }\n            if ('TSHBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TSHBLVSlot\" */\n                    '@egt/tshblvslot'\n                );\n            }\n            if ('VNBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/VNBLVSlot\" */\n                    '@egt/vnblvslot'\n                );\n            }\n            if ('FDHBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FDHBLVSlot\" */\n                    '@egt/fdhblvslot'\n                );\n            }\n            if ('FHEBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLVSlot\" */\n                    '@egt/fheblvslot'\n                );\n            }\n            if ('FHEBLPNSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLPNSlot\" */\n                    '@egt/fheblpnslot'\n                );\n            }\n            if ('FHEBLVCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLVCSlot\" */\n                    '@egt/fheblvcslot'\n                );\n            }\n            if ('FHEBLVDSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLVDSlot\" */\n                    '@egt/fheblvdslot'\n                );\n            }\n            if ('FHEBLBYSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLBYSlot\" */\n                    '@egt/fheblbyslot'\n                );\n            }\n            if ('FHEBLCCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLCCSlot\" */\n                    '@egt/fheblccslot'\n                );\n            }\n            if ('FHEBLBCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLBCSlot\" */\n                    '@egt/fheblbcslot'\n                );\n            }\n            if ('FHEBLBFSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLBFSlot\" */\n                    '@egt/fheblbfslot'\n                );\n            }\n            if ('FHEBLKNSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLKNSlot\" */\n                    '@egt/fheblknslot'\n                );\n            }\n            if ('FHEBLKBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLKBSlot\" */\n                    '@egt/fheblkbslot'\n                );\n            }\n            if ('FHEBLVMKSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLVMKSlot\" */\n                    '@egt/fheblvmkslot'\n                );\n            }\n            if ('FHEBLVVDCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLVVDCSlot\" */\n                    '@egt/fheblvvdcslot'\n                );\n            }\n            if ('FHEBLVBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLVBSlot\" */\n                    '@egt/fheblvbslot'\n                );\n            }\n            if ('CBLOVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/CBLOVSlot\" */\n                    '@egt/cblovslot'\n                );\n            }\n            if ('BCBLVKRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BCBLVKRSlot\" */\n                    '@egt/bcblvkrslot'\n                );\n            }\n            if ('BCBLMBVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BCBLMBVSlot\" */\n                    '@egt/bcblmbvslot'\n                );\n            }\n            if ('BCBLVBCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BCBLVBCSlot\" */\n                    '@egt/bcblvbcslot'\n                );\n            }\n            if ('BCBLVABSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BCBLVABSlot\" */\n                    '@egt/bcblvabslot'\n                );\n            }\n            if ('FHEBLHBVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLHBVSlot\" */\n                    '@egt/fheblhbvslot'\n                );\n            }\n            if ('FHEBLJBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLJBSlot\" */\n                    '@egt/fhebljbslot'\n                );\n            }\n            if ('FHEBLBPSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLBPSlot\" */\n                    '@egt/fheblbpslot'\n                );\n            }\n            if ('FHEBLVHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLVHSlot\" */\n                    '@egt/fheblvhslot'\n                );\n            }\n            if ('FHEBLSTSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLSTSlot\" */\n                    '@egt/fheblstslot'\n                );\n            }\n            if ('FHEBLFSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLFSlot\" */\n                    '@egt/fheblfslot'\n                );\n            }\n            if ('FHEBLCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLCSlot\" */\n                    '@egt/fheblcslot'\n                );\n            }\n            if ('FSHBLLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSHBLLSlot\" */\n                    '@egt/fshbllslot'\n                );\n            }\n            if ('FSHBLGSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSHBLGSlot\" */\n                    '@egt/fshblgslot'\n                );\n            }\n            if ('FSHBLFPSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSHBLFPSlot\" */\n                    '@egt/fshblfpslot'\n                );\n            }\n            if ('SCBLMSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SCBLMSlot\" */\n                    '@egt/scblmslot'\n                );\n            }\n            if ('SCBLTPSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SCBLTPSlot\" */\n                    '@egt/scbltpslot'\n                );\n            }\n            if ('FHEBLNSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLNSlot\" */\n                    '@egt/fheblnslot'\n                );\n            }\n            if ('FHBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHBLVSlot\" */\n                    '@egt/fhblvslot'\n                );\n            }\n            if ('FSCBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSCBLVSlot\" */\n                    '@egt/fscblvslot'\n                );\n            }\n            if ('FSCBLVCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSCBLVCSlot\" */\n                    '@egt/fscblvcslot'\n                );\n            }\n            if ('FSCBLVBOSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSCBLVBOSlot\" */\n                    '@egt/fscblvboslot'\n                );\n            }\n            if ('FSCBLVGBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSCBLVGBSlot\" */\n                    '@egt/fscblvgbslot'\n                );\n            }\n            if ('PFSCBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/PFSCBLSlot\" */\n                    '@egt/pfscblslot'\n                );\n            }\n            if ('FFSCBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FFSCBLSlot\" */\n                    '@egt/ffscblslot'\n                );\n            }\n            if ('FRSCBLMBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRSCBLMBSlot\" */\n                    '@egt/frscblmbslot'\n                );\n            }\n            if ('FSCBLPNSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSCBLPNSlot\" */\n                    '@egt/fscblpnslot'\n                );\n            }\n            if ('FSCBLMBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSCBLMBSlot\" */\n                    '@egt/fscblmbslot'\n                );\n            }\n            if ('FRSCBLBHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRSCBLBHSlot\" */\n                    '@egt/frscblbhslot'\n                );\n            }\n            if ('FSCBLVPBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSCBLVPBSlot\" */\n                    '@egt/fscblvpbslot'\n                );\n            }\n            if ('FRSCBLUSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRSCBLUSlot\" */\n                    '@egt/frscbluslot'\n                );\n            }\n            if ('FRSCBLSSSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRSCBLSSSlot\" */\n                    '@egt/frscblssslot'\n                );\n            }\n            if ('SCBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SCBLVSlot\" */\n                    '@egt/scblvslot'\n                );\n            }\n            if ('FBHBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLVSlot\" */\n                    '@egt/fbhblvslot'\n                );\n            }\n            if ('FBRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBRSlot\" */\n                    '@egt/fbrslot'\n                );\n            }\n            if ('OHBRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OHBRSlot\" */\n                    '@egt/ohbrslot'\n                );\n            }\n            if ('TWBRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TWBRSlot\" */\n                    '@egt/twbrslot'\n                );\n            }\n            if ('TNBRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TNBRSlot\" */\n                    '@egt/tnbrslot'\n                );\n            }\n            if ('FBHBLMBVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLMBVSlot\" */\n                    '@egt/fbhblmbvslot'\n                );\n            }\n            if ('BHBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BHBLVSlot\" */\n                    '@egt/bhblvslot'\n                );\n            }\n            if ('FSFBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSFBLVSlot\" */\n                    '@egt/fsfblvslot'\n                );\n            }\n            if ('TSFBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TSFBLVSlot\" */\n                    '@egt/tsfblvslot'\n                );\n            }\n            if ('SACBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SACBLVSlot\" */\n                    '@egt/sacblvslot'\n                );\n            }\n            if ('SACBLPUSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SACBLPUSlot\" */\n                    '@egt/sacblpuslot'\n                );\n            }\n            if ('ZWBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/ZWBLVSlot\" */\n                    '@egt/zwblvslot'\n                );\n            }\n            if ('FZWBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FZWBLVSlot\" */\n                    '@egt/fzwblvslot'\n                );\n            }\n            if ('FLKBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FLKBLVSlot\" */\n                    '@egt/flkblvslot'\n                );\n            }\n            if ('TNSPSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TNSPSlot\" */\n                    '@egt/tnspslot'\n                );\n            }\n            if ('FRLKEBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRLKEBLSlot\" */\n                    '@egt/frlkeblslot'\n                );\n            }\n            if ('FBHBLPBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLPBSlot\" */\n                    '@egt/fbhblpbslot'\n                );\n            }\n            if ('PRCJWSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/PRCJWSlot\" */\n                    '@egt/prcjwslot'\n                );\n            }\n            if ('PRRJWSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/PRRJWSlot\" */\n                    '@egt/prrjwslot'\n                );\n            }\n            if ('ODJWSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/ODJWSlot\" */\n                    '@egt/odjwslot'\n                );\n            }\n            if ('SVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SVSlot\" */\n                    '@egt/svslot'\n                );\n            }\n            if ('OTSVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OTSVSlot\" */\n                    '@egt/otsvslot'\n                );\n            }\n            if ('OTSVSSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OTSVSSlot\" */\n                    '@egt/otsvsslot'\n                );\n            }\n            if ('SMSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SMSlot\" */\n                    '@egt/smslot'\n                );\n            }\n            if ('TNJHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TNJHSlot\" */\n                    '@egt/tnjhslot'\n                );\n            }\n            if ('TNSRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TNSRSlot\" */\n                    '@egt/tnsrslot'\n                );\n            }\n            if ('FBHBLPBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLPBSlot\" */\n                    '@egt/fbhblpbslot'\n                );\n            }\n            if ('ALGKLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/ALGKLSlot\" */\n                    '@egt/algklslot'\n                );\n            }\n            if ('ALGKLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/ALGKLVSlot\" */\n                    '@egt/algklvslot'\n                );\n            }\n            if ('MHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/MHSlot\" */\n                    '@egt/mhslot'\n                );\n            }\n            if ('FRLKEBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRLKEBLVSlot\" */\n                    '@egt/frlkeblvslot'\n                );\n            }\n            if ('FVJHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FVJHSlot\" */\n                    '@egt/fvjhslot'\n                );\n            }\n            if ('TNJRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TNJRSlot\" */\n                    '@egt/tnjrslot'\n                );\n            }\n            if ('FVJRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FVJRSlot\" */\n                    '@egt/fvjrslot'\n                );\n            }\n            if ('TWJHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TWJHSlot\" */\n                    '@egt/twjhslot'\n                );\n            }\n            if ('FRJHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRJHSlot\" */\n                    '@egt/frjhslot'\n                );\n            }\n            if ('OHJHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OHJHSlot\" */\n                    '@egt/ohjhslot'\n                );\n            }\n            if ('OHJRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OHJRSlot\" */\n                    '@egt/ohjrslot'\n                );\n            }\n            if ('FRJRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRJRSlot\" */\n                    '@egt/frjrslot'\n                );\n            }\n            if ('TWJRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TWJRSlot\" */\n                    '@egt/twjrslot'\n                );\n            }\n            if ('FRLKEBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRLKEBLVSlot\" */\n                    '@egt/frlkeblvslot'\n                );\n            }\n            if ('BOSHBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BOSHBLSlot\" */\n                    '@egt/boshblslot'\n                );\n            }\n            if ('PGASlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/PGASlot\" */\n                    '@egt/pgaslot'\n                );\n            }\n            if ('OTPGASlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OTPGASlot\" */\n                    '@egt/otpgaslot'\n                );\n            }\n            if ('FYHBWSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FYHBWSlot\" */\n                    '@egt/fyhbwslot'\n                );\n            }\n            if ('BOSHBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BOSHBLVSlot\" */\n                    '@egt/boshblvslot'\n                );\n            }\n            if ('MDBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/MDBLSlot\" */\n                    '@egt/mdblslot'\n                );\n            }\n            if ('FBHBLBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLBSlot\" */\n                    '@egt/fbhblbslot'\n                );\n            }\n            if ('FBHBLZSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLZSlot\" */\n                    '@egt/fbhblzslot'\n                );\n            }\n            if ('MDBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/MDBLVSlot\" */\n                    '@egt/mdblvslot'\n                );\n            }\n            if ('FHEBLMSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLMSlot\" */\n                    '@egt/fheblmslot'\n                );\n            }\n            if ('RORGKLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/RORGKLSlot\" */\n                    '@egt/rorgklslot'\n                );\n            }\n            if ('TCHBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TCHBSlot\" */\n                    '@egt/tchbslot'\n                );\n            }\n            if ('SXSFSSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SXSFSSlot\" */\n                    '@egt/sxsfsslot'\n                );\n            }\n            if ('RORGKLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/RORGKLVSlot\" */\n                    '@egt/rorgklvslot'\n                );\n            }\n            if ('QASlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/QASlot\" */\n                    '@egt/qaslot'\n                );\n            }\n            if ('FBHSPSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHSPSlot\" */\n                    '@egt/fbhspslot'\n                );\n            }\n            if ('FSHBLMKSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSHBLMKSlot\" */\n                    '@egt/fshblmkslot'\n                );\n            }\n            if ('FBCBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBCBSlot\" */\n                    '@egt/fbcbslot'\n                );\n            }\n            if ('TSHBLSSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TSHBLSSlot\" */\n                    '@egt/tshblsslot'\n                );\n            }\n            if ('OGGKLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OGGKLSlot\" */\n                    '@egt/oggklslot'\n                );\n            }\n            if ('CCGKLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/CCGKLSlot\" */\n                    '@egt/ccgklslot'\n                );\n            }\n            if ('CCGKLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/CCGKLVSlot\" */\n                    '@egt/ccgklvslot'\n                );\n            }\n            if ('CKHGKLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/CKHGKLSlot\" */\n                    '@egt/ckhgklslot'\n                );\n            }\n            if ('LKHGKLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/LKHGKLSlot\" */\n                    '@egt/lkhgklslot'\n                );\n            }\n            if ('SCBLHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SCBLHSlot\" */\n                    '@egt/scblhslot'\n                );\n            }\n            if ('FBHBLGPBVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLGPBVSlot\" */\n                    '@egt/fbhblgpbvslot'\n                );\n            }\n            if ('TNLRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TNLRSlot\" */\n                    '@egt/tnlrslot'\n                );\n            }\n            if ('FVLRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FVLRSlot\" */\n                    '@egt/fvlrslot'\n                );\n            }\n            if ('TWLRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TWLRSlot\" */\n                    '@egt/twlrslot'\n                );\n            }\n            if ('FRLRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRLRSlot\" */\n                    '@egt/frlrslot'\n                );\n            }\n            if ('OHLRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OHLRSlot\" */\n                    '@egt/ohlrslot'\n                );\n            }\n            if ('FRLKEBLCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRLKEBLCSlot\" */\n                    '@egt/frlkeblcslot'\n                );\n            }\n            if ('FHBLVPSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHBLVPSlot\" */\n                    '@egt/fhblvpslot'\n                );\n            }\n            if ('OTSRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OTSRSlot\" */\n                    '@egt/otsrslot'\n                );\n            }\n            if ('OGGKLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OGGKLVSlot\" */\n                    '@egt/oggklvslot'\n                );\n            }\n            if ('SCBLTSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SCBLTSlot\" */\n                    '@egt/scbltslot'\n                );\n            }\n            if ('SCBLVPSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SCBLVPSlot\" */\n                    '@egt/scblvpslot'\n                );\n            }\n            if ('FRLKEBLVBMSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRLKEBLVBMSlot\" */\n                    '@egt/frlkeblvbmslot'\n                );\n            }\n            if ('EITHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/EITHSlot\" */\n                    '@egt/eithslot'\n                );\n            }\n            if ('EITHHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/EITHHRSlot\" */\n                    '@egt/eithhrslot'\n                );\n            }\n            if ('EITRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/EITRSlot\" */\n                    '@egt/eitrslot'\n                );\n            }\n            if ('EITRHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/EITRHRSlot\" */\n                    '@egt/eitrhrslot'\n                );\n            }\n            if ('ORSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/ORSlot\" */\n                    '@egt/orslot'\n                );\n            }\n            if ('BCBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BCBLSlot\" */\n                    '@egt/bcblslot'\n                );\n            }\n            if ('BCBLNBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BCBLNBSlot\" */\n                    '@egt/bcblnbslot'\n                );\n            }\n            if ('BCSSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BCSSlot\" */\n                    '@egt/bcsslot'\n                );\n            }\n            if ('BCSHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BCSHRSlot\" */\n                    '@egt/bcshrslot'\n                );\n            }\n            if ('SCSSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SCSSlot\" */\n                    '@egt/scsslot'\n                );\n            }\n            if ('SCSHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SCSHRSlot\" */\n                    '@egt/scshrslot'\n                );\n            }\n            if ('MFTDSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/MFTDSlot\" */\n                    '@egt/mftdslot'\n                );\n            }\n            if ('BCBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BCBLVSlot\" */\n                    '@egt/bcblvslot'\n                );\n            }\n            if ('FBHBLBWSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FBHBLBWSlot\" */\n                    '@egt/fbhblbwslot'\n                );\n            }\n            if ('FHEBLBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHEBLBSlot\" */\n                    '@egt/fheblbslot'\n                );\n            }\n            if ('SBBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SBBLSlot\" */\n                    '@egt/sbblslot'\n                );\n            }\n            if ('BHBLSSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BHBLSSlot\" */\n                    '@egt/bhblsslot'\n                );\n            }\n            if ('FHBLVJSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHBLVJSlot\" */\n                    '@egt/fhblvjslot'\n                );\n            }\n            if ('FHBLGSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHBLGSlot\" */\n                    '@egt/fhblgslot'\n                );\n            }\n            if ('FHBLGGSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHBLGGSlot\" */\n                    '@egt/fhblggslot'\n                );\n            }\n            if ('FHBLLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FHBLLSlot\" */\n                    '@egt/fhbllslot'\n                );\n            }\n            if ('FSHBLMSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FSHBLMSlot\" */\n                    '@egt/fshblmslot'\n                );\n            }\n            if ('SBBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SBBLVSlot\" */\n                    '@egt/sbblvslot'\n                );\n            }\n            if ('SBBLESlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SBBLESlot\" */\n                    '@egt/sbbleslot'\n                );\n            }\n            if ('FRSCBLKSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRSCBLKSlot\" */\n                    '@egt/frscblkslot'\n                );\n            }\n            if ('FVDRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FVDRSlot\" */\n                    '@egt/fvdrslot'\n                );\n            }\n            if ('FRDRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRDRSlot\" */\n                    '@egt/frdrslot'\n                );\n            }\n            if ('OHDRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OHDRSlot\" */\n                    '@egt/ohdrslot'\n                );\n            }\n            if ('TNDRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TNDRSlot\" */\n                    '@egt/tndrslot'\n                );\n            }\n            if ('TWDRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TWDRSlot\" */\n                    '@egt/twdrslot'\n                );\n            }\n            if ('OTSDSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OTSDSlot\" */\n                    '@egt/otsdslot'\n                );\n            }\n            if ('BPBLBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BPBLBSlot\" */\n                    '@egt/bpblbslot'\n                );\n            }\n            if ('SPBLBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SPBLBSlot\" */\n                    '@egt/spblbslot'\n                );\n            }\n            if ('FRSRBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRSRBSlot\" */\n                    '@egt/frsrbslot'\n                );\n            }\n            if ('BDBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BDBLSlot\" */\n                    '@egt/bdblslot'\n                );\n            }\n            if ('BDBLVMBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BDBLVMBSlot\" */\n                    '@egt/bdblvmbslot'\n                );\n            }\n            if ('BDMBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BDMBLVSlot\" */\n                    '@egt/bdmblvslot'\n                );\n            }\n            if ('BDBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BDBLVSlot\" */\n                    '@egt/bdblvslot'\n                );\n            }\n            if ('TNTJSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TNTJSlot\" */\n                    '@egt/tntjslot'\n                );\n            }\n            if ('TNTJHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TNTJHRSlot\" */\n                    '@egt/tntjhrslot'\n                );\n            }\n            if ('BFCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BFCSlot\" */\n                    '@egt/bfcslot'\n                );\n            }\n            if ('BFCHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BFCHRSlot\" */\n                    '@egt/bfchrslot'\n                );\n            }\n            if ('HFTTSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/HFTTSlot\" */\n                    '@egt/hfttslot'\n                );\n            }\n            if ('HFTTHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/HFTTHRSlot\" */\n                    '@egt/hftthrslot'\n                );\n            }\n            if ('HFMSSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/HFMSSlot\" */\n                    '@egt/hfmsslot'\n                );\n            }\n            if ('HFMSHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/HFMSHRSlot\" */\n                    '@egt/hfmshrslot'\n                );\n            }\n            if ('HRFMSSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/HRFMSSlot\" */\n                    '@egt/hrfmsslot'\n                );\n            }\n            if ('AVRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/AVRSlot\" */\n                    '@egt/avrslot'\n                );\n            }\n            if ('KPBSPSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/KPBSPSlot\" */\n                    '@egt/kpbspslot'\n                );\n            }\n            if ('KPBSPHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/KPBSPHRSlot\" */\n                    '@egt/kpbsphrslot'\n                );\n            }\n            if ('SSSPSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SSSPSlot\" */\n                    '@egt/ssspslot'\n                );\n            }\n            if ('RVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/RVSlot\" */\n                    '@egt/rvslot'\n                );\n            }\n            if ('RVHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/RVHRSlot\" */\n                    '@egt/rvhrslot'\n                );\n            }\n            if ('LWHWTXTSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/LWHWTXTSlot\" */\n                    '@egt/lwhwtxtslot'\n                );\n            }\n            if ('FRSRBHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRSRBHRSlot\" */\n                    '@egt/frsrbhrslot'\n                );\n            }\n            if ('SACRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SACRSlot\" */\n                    '@egt/sacrslot'\n                );\n            }\n            if ('PRRJWHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/PRRJWHRSlot\" */\n                    '@egt/prrjwhrslot'\n                );\n            }\n            if ('ARMSSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/ARMSSlot\" */\n                    '@egt/armsslot'\n                );\n            }\n            if ('BSBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BSBLSlot\" */\n                    '@egt/bsblslot'\n                );\n            }\n            if ('BSBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BSBLVSlot\" */\n                    '@egt/bsblvslot'\n                );\n            }\n            if ('JCCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/JCCSlot\" */\n                    '@egt/jccslot'\n                );\n            }\n            if ('JCESlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/JCESlot\" */\n                    '@egt/jceslot'\n                );\n            }\n            if ('ORHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/ORHRSlot\" */\n                    '@egt/orhrslot'\n                );\n            }\n            if ('TLBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TLBLSlot\" */\n                    '@egt/tlblslot'\n                );\n            }\n            if ('TLBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TLBLVSlot\" */\n                    '@egt/tlblvslot'\n                );\n            }\n            if ('TSDPWSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/TSDPWSlot\" */\n                    '@egt/tsdpwslot'\n                );\n            }\n            if ('SPBLBVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/SPBLBVSlot\" */\n                    '@egt/spblbvslot'\n                );\n            }\n            if ('BPBLBVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BPBLBVSlot\" */\n                    '@egt/bpblbvslot'\n                );\n            }\n            if ('QAHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/QAHRSlot\" */\n                    '@egt/qahrslot'\n                );\n            }\n            if ('OTSDHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OTSDHRSlot\" */\n                    '@egt/otsdhrslot'\n                );\n            }\n            if ('BLCBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BLCBLSlot\" */\n                    '@egt/blcblslot'\n                );\n            }\n            if ('FRSHBLBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRSHBLBSlot\" */\n                    '@egt/frshblbslot'\n                );\n            }\n            if ('FRSHBLBVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRSHBLBVSlot\" */\n                    '@egt/frshblbvslot'\n                );\n            }\n            if ('MSPBLBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/MSPBLBSlot\" */\n                    '@egt/mspblbslot'\n                );\n            }\n            if ('MSPBLBVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/MSPBLBVSlot\" */\n                    '@egt/mspblbvslot'\n                );\n            }\n            if ('JCCHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/JCCHRSlot\" */\n                    '@egt/jcchrslot'\n                );\n            }\n            if ('MBPBLBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/MBPBLBSlot\" */\n                    '@egt/mbpblbslot'\n                );\n            }\n            if ('MBPBLBVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/MBPBLBVSlot\" */\n                    '@egt/mbpblbvslot'\n                );\n            }\n            if ('FRSDBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRSDBLSlot\" */\n                    '@egt/frsdblslot'\n                );\n            }\n            if ('BLHIBBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BLHIBBLSlot\" */\n                    '@egt/blhibblslot'\n                );\n            }\n            if ('BLJBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BLJBLSlot\" */\n                    '@egt/bljblslot'\n                );\n            }\n            if ('GKBLCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/GKBLCSlot\" */\n                    '@egt/gkblcslot'\n                );\n            }\n            if ('GKBLKSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/GKBLKSlot\" */\n                    '@egt/gkblkslot'\n                );\n            }\n            if ('GKBLMKSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/GKBLMKSlot\" */\n                    '@egt/gkblmkslot'\n                );\n            }\n            if ('GKBLBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/GKBLBSlot\" */\n                    '@egt/gkblbslot'\n                );\n            }\n            if ('GKBLMSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/GKBLMSlot\" */\n                    '@egt/gkblmslot'\n                );\n            }\n            if ('GKBLGSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/GKBLGSlot\" */\n                    '@egt/gkblgslot'\n                );\n            }\n            if ('GKBLMBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/GKBLMBSlot\" */\n                    '@egt/gkblmbslot'\n                );\n            }\n            if ('GKBLSSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/GKBLSSlot\" */\n                    '@egt/gkblsslot'\n                );\n            }\n            if ('GKBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/GKBLSlot\" */\n                    '@egt/gkblslot'\n                );\n            }\n            if ('IGKBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/IGKBLSlot\" */\n                    '@egt/igkblslot'\n                );\n            }\n            if ('WGKBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/WGKBLSlot\" */\n                    '@egt/wgkblslot'\n                );\n            }\n            if ('PGAASlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/PGAASlot\" */\n                    '@egt/pgaaslot'\n                );\n            }\n            if ('BLCBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BLCBLVSlot\" */\n                    '@egt/blcblvslot'\n                );\n            }\n            if ('LWHWTXTHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/LWHWTXTHRSlot\" */\n                    '@egt/lwhwtxthrslot'\n                );\n            }\n            if ('FRBRSSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRBRSSlot\" */\n                    '@egt/frbrsslot'\n                );\n            }\n            if ('FRBRSHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRBRSHRSlot\" */\n                    '@egt/frbrshrslot'\n                );\n            }\n            if ('CKHGKLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/CKHGKLVSlot\" */\n                    '@egt/ckhgklvslot'\n                );\n            }\n            if ('LKHGKLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/LKHGKLVSlot\" */\n                    '@egt/lkhgklvslot'\n                );\n            }\n            if ('GKBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/GKBLVSlot\" */\n                    '@egt/gkblvslot'\n                );\n            }\n            if ('IGKBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/IGKBLVSlot\" */\n                    '@egt/igkblvslot'\n                );\n            }\n            if ('WGKBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/WGKBLVSlot\" */\n                    '@egt/wgkblvslot'\n                );\n            }\n            if ('JCHWSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/JCHWSlot\" */\n                    '@egt/jchwslot'\n                );\n            }\n            if ('STOTHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/STOTHRSlot\" */\n                    '@egt/stothrslot'\n                );\n            }\n            if ('FRSDBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRSDBLVSlot\" */\n                    '@egt/frsdblvslot'\n                );\n            }\n            if ('OTPGAHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OTPGAHRSlot\" */\n                    '@egt/otpgahrslot'\n                );\n            }\n            if ('GKBBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/GKBBLSlot\" */\n                    '@egt/gkbblslot'\n                );\n            }\n            if ('BGKBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BGKBLVSlot\" */\n                    '@egt/bgkblvslot'\n                );\n            }\n            if ('BLBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BLBLSlot\" */\n                    '@egt/blblslot'\n                );\n            }\n            if ('BLIBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BLIBLSlot\" */\n                    '@egt/bliblslot'\n                );\n            }\n            if ('BLIBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BLIBLVSlot\" */\n                    '@egt/bliblvslot'\n                );\n            }\n            if ('BLWBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BLWBLSlot\" */\n                    '@egt/blwblslot'\n                );\n            }\n            if ('BLWBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BLWBLVSlot\" */\n                    '@egt/blwblvslot'\n                );\n            }\n            if ('GKBLHBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/GKBLHBSlot\" */\n                    '@egt/gkblhbslot'\n                );\n            }\n            if ('GKBLVHBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/GKBLVHBSlot\" */\n                    '@egt/gkblvhbslot'\n                );\n            }\n            if ('FRSHCBLBSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRSHCBLBSlot\" */\n                    '@egt/frshcblbslot'\n                );\n            }\n            if ('FRSHCBLBVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/FRSHCBLBVSlot\" */\n                    '@egt/frshcblbvslot'\n                );\n            }\n            if ('BLHIBBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BLHIBBLVSlot\" */\n                    '@egt/blhibblvslot'\n                );\n            }\n            if ('BLHBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BLHBLSlot\" */\n                    '@egt/blhblslot'\n                );\n            }\n            if ('BLBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BLBLVSlot\" */\n                    '@egt/blblvslot'\n                );\n            }\n            if ('OHSCSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/OHSCSlot\" */\n                    '@egt/ohscslot'\n                );\n            }\n            if ('BLHBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BLHBLVSlot\" */\n                    '@egt/blhblvslot'\n                );\n            }\n            if ('ARMSHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/ARMSHRSlot\" */\n                    '@egt/armshrslot'\n                );\n            }\n            if ('BLCCBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BLCCBLSlot\" */\n                    '@egt/blccblslot'\n                );\n            }\n            if ('JCHWHRSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/JCHWHRSlot\" */\n                    '@egt/jchwhrslot'\n                );\n            }\n            if ('BLSBLSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BLSBLSlot\" */\n                    '@egt/blsblslot'\n                );\n            }\n            if ('BLSBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BLSBLVSlot\" */\n                    '@egt/blsblvslot'\n                );\n            }\n            if ('BLCCBLVSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/BLCCBLVSlot\" */\n                    '@egt/blccblvslot'\n                );\n            }\n            if ('JCSHSlot' === gameKey) {\n                return import(\n                    /* webpackChunkName: \"games/JCSHSlot\" */\n                    '@egt/jcshslot'\n                );\n            }\n    return Promise.reject();\n    /* ===== End of code block ===== */\n};\n/* tslint:enable:trailing-comma */\n\n/* tslint:disable:trailing-comma */\nCore.importTemplate = (templateName: string): Promise<any> => {\n    /* ===== template start placeholder ===== */\n    return Promise.resolve();\n    /* ===== template end placeholder ===== */\n};\n/* tslint:enable:trailing-comma */\n\n/* tslint:disable:trailing-comma */\nCore.importFeature = (featureName: string): Promise<any> => {\n    /* ===== This code block was automatically generated by prebuild.js ===== */\n    /* ===== Start of code block ===== */\n    switch(featureName) {\n    \n        case \"CUSTOM_RESULT\":\n            return import(\n                /* webpackChunkName: \"features/custom-result\" */\n                \"@egt/custom-result\")\n        case \"CUSTOM_REACT\":\n            return import(\n                /* webpackChunkName: \"features/custom-react\" */\n                \"@egt/custom-react\")\n        case \"CUSTOM_SCALER\":\n            return import(\n                /* webpackChunkName: \"features/custom-scaler\" */\n                \"@egt/custom-scaler\")\n        case \"GIFT_SPINS\":\n            return import(\n                /* webpackChunkName: \"features/gift-spins\" */\n                \"@egt/gift-spins\")\n        case \"SG_JACKPOT\":\n            return import(\n                /* webpackChunkName: \"features/sg-jackpot\" */\n                \"@egt/sg-jackpot\")\n        case \"COIN\":\n            return import(\n                /* webpackChunkName: \"features/coin\" */\n                \"@egt/coin\")\n        case \"GAMBLE\":\n            return import(\n                /* webpackChunkName: \"features/gamble\" */\n                \"@egt/gamble\")\n        case \"FREE_SPINS\":\n            return import(\n                /* webpackChunkName: \"features/free-spins\" */\n                \"@egt/free-spins\")\n        case \"FREE_SPINS_PICK\":\n            return import(\n                /* webpackChunkName: \"features/free-spins-pick\" */\n                \"@egt/free-spins-pick\")\n        case \"MULTIPLIER\":\n            return import(\n                /* webpackChunkName: \"features/multiplier\" */\n                \"@egt/multiplier\")\n        case \"ROOT_ELEMENTS_ANIMATION\":\n            return import(\n                /* webpackChunkName: \"features/root-elements-animation\" */\n                \"@egt/root-elements-animation\")\n        case \"BL_JACKPOT\":\n            return import(\n                /* webpackChunkName: \"features/bl-jackpot\" */\n                \"@egt/bl-jackpot\")\n        case \"BL_BOOST_JACKPOT\":\n            return import(\n                /* webpackChunkName: \"features/bl-boost-jackpot\" */\n                \"@egt/bl-boost-jackpot\")\n        case \"GAKL_JACKPOT_V1\":\n            return import(\n                /* webpackChunkName: \"features/gakl-jackpot-v1\" */\n                \"@egt/gakl-jackpot-v1\")\n        case \"GAKL_JACKPOT_BASE\":\n            return import(\n                /* webpackChunkName: \"features/gakl-jackpot-base\" */\n                \"@egt/gakl-jackpot-base\")\n        case \"EXPAND\":\n            return import(\n                /* webpackChunkName: \"features/expand\" */\n                \"@egt/expand\")\n        case \"PICK_ME_BONUS\":\n            return import(\n                /* webpackChunkName: \"features/pick-me-bonus\" */\n                \"@egt/pick-me-bonus\")\n        case \"REPLAYER\":\n            return import(\n                /* webpackChunkName: \"features/replayer\" */\n                \"@egt/replayer\")\n        case \"RESPIN\":\n            return import(\n                /* webpackChunkName: \"features/respin\" */\n                \"@egt/respin\")\n        case \"MYSTERY_JACKPOT\":\n            return import(\n                /* webpackChunkName: \"features/mystery-jackpot\" */\n                \"@egt/mystery-jackpot\")\n        case \"PREMIUM_LINK_JACKPOT\":\n            return import(\n                /* webpackChunkName: \"features/premium-link-jackpot\" */\n                \"@egt/premium-link-jackpot\")\n        case \"HIGH_CASH_SLOT\":\n            return import(\n                /* webpackChunkName: \"features/high-cash-slot\" */\n                \"@egt/high-cash-slot\")\n        case \"HIGH_CASH_BALL\":\n            return import(\n                /* webpackChunkName: \"features/high-cash-ball\" */\n                \"@egt/high-cash-ball\")\n        case \"HIGH_CASH_COIN\":\n            return import(\n                /* webpackChunkName: \"features/high-cash-coin\" */\n                \"@egt/high-cash-coin\")\n        case \"BLITZ_PLAY\":\n            return import(\n                /* webpackChunkName: \"features/blitz-play\" */\n                \"@egt/blitz-play\")\n        case \"HOLD_RESPIN\":\n            return import(\n                /* webpackChunkName: \"features/hold-respin\" */\n                \"@egt/hold-respin\")\n        case \"HIGH_CASH_COUNTERS\":\n            return import(\n                /* webpackChunkName: \"features/high-cash-counters\" */\n                \"@egt/high-cash-counters\")\n        case \"HIGH_CASH_CHOICE\":\n            return import(\n                /* webpackChunkName: \"features/high-cash-choice\" */\n                \"@egt/high-cash-choice\")\n        case \"HIGH_CASH_FREE_SPINS\":\n            return import(\n                /* webpackChunkName: \"features/high-cash-free-spins\" */\n                \"@egt/high-cash-free-spins\")\n        case \"HIGH_CASH_JACKPOT_WON\":\n            return import(\n                /* webpackChunkName: \"features/high-cash-jackpot-won\" */\n                \"@egt/high-cash-jackpot-won\")\n        case \"HIGH_CASH_PICKER\":\n            return import(\n                /* webpackChunkName: \"features/high-cash-picker\" */\n                \"@egt/high-cash-picker\")\n        case \"HIGH_CASH_RESPIN\":\n            return import(\n                /* webpackChunkName: \"features/high-cash-respin\" */\n                \"@egt/high-cash-respin\")\n        case \"HIGH_CASH_WHEEL\":\n            return import(\n                /* webpackChunkName: \"features/high-cash-wheel\" */\n                \"@egt/high-cash-wheel\")\n        case \"HIGH_CASH_RESPIN_CREDIT_WHEEL\":\n            return import(\n                /* webpackChunkName: \"features/high-cash-respin-credit-wheel\" */\n                \"@egt/high-cash-respin-credit-wheel\")\n        case \"HIGH_CASH_EXPAND\":\n            return import(\n                /* webpackChunkName: \"features/high-cash-expand\" */\n                \"@egt/high-cash-expand\")\n        case \"TOURNAMENTS\":\n            return import(\n                /* webpackChunkName: \"features/tournaments\" */\n                \"@egt/tournaments\")\n        case \"CAMPAIGN_MANAGER\":\n            return import(\n                /* webpackChunkName: \"features/campaign-manager\" */\n                \"@egt/campaign-manager\")\n        case \"PRIZE_POPS\":\n            return import(\n                /* webpackChunkName: \"features/prize-pops\" */\n                \"@egt/prize-pops\")\n        case \"BASE_FREE_SPINS\":\n            return import(\n                /* webpackChunkName: \"features/base-free-spins\" */\n                \"@egt/base-free-spins\")\n        case \"CASCADE_MULTIPLIER\":\n            return import(\n                /* webpackChunkName: \"features/cascade-multiplier\" */\n                \"@egt/cascade-multiplier\")\n        case \"CASCADE_TOTAL_MULTIPLIER\":\n            return import(\n                /* webpackChunkName: \"features/cascade-total-multiplier\" */\n                \"@egt/cascade-total-multiplier\")\n        case \"CASCADE_GLOBAL_MULTIPLIER\":\n            return import(\n                /* webpackChunkName: \"features/cascade-global-multiplier\" */\n                \"@egt/cascade-global-multiplier\")\n        case \"BIG_WIN\":\n            return import(\n                /* webpackChunkName: \"features/big-win\" */\n                \"@egt/big-win\")\n        case \"SMALL_WIN\":\n            return import(\n                /* webpackChunkName: \"features/small-win\" */\n                \"@egt/small-win\")\n        case \"MAX_WIN\":\n            return import(\n                /* webpackChunkName: \"features/max-win\" */\n                \"@egt/max-win\")\n        case \"CASCADE_SPINE_VIDEOS\":\n            return import(\n                /* webpackChunkName: \"features/cascade-spine-videos\" */\n                \"@egt/cascade-spine-videos\")\n        case \"CASCADE_RESPIN\":\n            return import(\n                /* webpackChunkName: \"features/cascade-respin\" */\n                \"@egt/cascade-respin\")\n        case \"CHARACTER_ANIMATIONS\":\n            return import(\n                /* webpackChunkName: \"features/character-animations\" */\n                \"@egt/character-animations\")\n        case \"VIDEOS\":\n            return import(\n                /* webpackChunkName: \"features/videos\" */\n                \"@egt/videos\")\n        case \"LINES\":\n            return import(\n                /* webpackChunkName: \"features/lines\" */\n                \"@egt/lines\")\n        case \"BRANDING\":\n            return import(\n                /* webpackChunkName: \"features/branding\" */\n                \"@egt/branding\")\n        case \"WAYS_MYSTERY\":\n            return import(\n                /* webpackChunkName: \"features/ways-mystery\" */\n                \"@egt/ways-mystery\")\n        case \"JUMBO_WAYS_SLOT\":\n            return import(\n                /* webpackChunkName: \"features/jumbo-ways-slot\" */\n                \"@egt/jumbo-ways-slot\")\n        case \"MULTI_REELS_SLOT\":\n            return import(\n                /* webpackChunkName: \"features/multi-reels-slot\" */\n                \"@egt/multi-reels-slot\")\n        case \"MULTI_REELS_ANIMATIONS\":\n            return import(\n                /* webpackChunkName: \"features/multi-reels-animations\" */\n                \"@egt/multi-reels-animations\")\n        case \"MAX_WIN_LIMIT\":\n            return import(\n                /* webpackChunkName: \"features/max-win-limit\" */\n                \"@egt/max-win-limit\")\n        case \"SYMBOL_POP_VIDEO\":\n            return import(\n                /* webpackChunkName: \"features/symbol-pop-video\" */\n                \"@egt/symbol-pop-video\")\n        case \"SYMBOL_REPLACE_VIDEO\":\n            return import(\n                /* webpackChunkName: \"features/symbol-replace-video\" */\n                \"@egt/symbol-replace-video\")\n        case \"CASH_HEAT\":\n            return import(\n                /* webpackChunkName: \"features/cash-heat\" */\n                \"@egt/cash-heat\")\n        case \"SCRATCH_WIN_VISUALIZATION\":\n            return import(\n                /* webpackChunkName: \"features/scratch-win-visualization\" */\n                \"@egt/scratch-win-visualization\")\n        case \"SCRATCH_RESTORE_FEATURE\":\n            return import(\n                /* webpackChunkName: \"features/scratch-restore-feature\" */\n                \"@egt/scratch-restore-feature\")\n        case \"SCRATCH_MYSTERY_JACKPOT\":\n            return import(\n                /* webpackChunkName: \"features/scratch-mystery-jackpot\" */\n                \"@egt/scratch-mystery-jackpot\")\n        case \"SCRATCH_AUTOPLAY_FEATURE\":\n            return import(\n                /* webpackChunkName: \"features/scratch-autoplay-feature\" */\n                \"@egt/scratch-autoplay-feature\")\n        case \"SCRATCH_AUTOPLAY_NUMERIC_INPUT_FEATURE\":\n            return import(\n                /* webpackChunkName: \"features/scratch-autoplay-numeric-input-feature\" */\n                \"@egt/scratch-autoplay-numeric-input-feature\")\n        case \"SCRATCH_BOARD_GAME\":\n            return import(\n                /* webpackChunkName: \"features/scratch-board-game\" */\n                \"@egt/scratch-board-game\")\n        case \"SCRATCH_PLAYER_SYMBOLS\":\n            return import(\n                /* webpackChunkName: \"features/scratch-player-symbols\" */\n                \"@egt/scratch-player-symbols\")\n        case \"SCRATCH_WINNING_SYMBOLS\":\n            return import(\n                /* webpackChunkName: \"features/scratch-winning-symbols\" */\n                \"@egt/scratch-winning-symbols\")\n        case \"SCRATCH_BIG_WIN\":\n            return import(\n                /* webpackChunkName: \"features/scratch-big-win\" */\n                \"@egt/scratch-big-win\")\n        case \"FRAME_EXPAND\":\n            return import(\n                /* webpackChunkName: \"features/frame-expand\" */\n                \"@egt/frame-expand\")\n        case \"SCRATCH_MAX_WIN\":\n            return import(\n                /* webpackChunkName: \"features/scratch-max-win\" */\n                \"@egt/scratch-max-win\")\n        case \"SCRATCH_GIFT_SPINS\":\n            return import(\n                /* webpackChunkName: \"features/scratch-gift-spins\" */\n                \"@egt/scratch-gift-spins\")\n        case \"SCRATCH_TOURNAMENTS\":\n            return import(\n                /* webpackChunkName: \"features/scratch-tournaments\" */\n                \"@egt/scratch-tournaments\")\n        case \"SCRATCH_CAMPAIGN_MANAGER\":\n            return import(\n                /* webpackChunkName: \"features/scratch-campaign-manager\" */\n                \"@egt/scratch-campaign-manager\")\n        case \"SCRATCH_PRIZE_POPS\":\n            return import(\n                /* webpackChunkName: \"features/scratch-prize-pops\" */\n                \"@egt/scratch-prize-pops\")\n        case \"SYMBOL_ANTICIPATION_ANIM\":\n            return import(\n                /* webpackChunkName: \"features/symbol-anticipation-anim\" */\n                \"@egt/symbol-anticipation-anim\")\n        case \"BL_CHRISTMAS\":\n            return import(\n                /* webpackChunkName: \"features/bl-christmas\" */\n                \"@egt/bl-christmas\")\n        case \"FULL_LINE_ANIMATION\":\n            return import(\n                /* webpackChunkName: \"features/full-line-animation\" */\n                \"@egt/full-line-animation\")\n        case \"WHEEL\":\n            return import(\n                /* webpackChunkName: \"features/wheel\" */\n                \"@egt/wheel\")\n        case \"EXPLOSION\":\n            return import(\n                /* webpackChunkName: \"features/explosion\" */\n                \"@egt/explosion\")\n        case \"ACTIVATOR\":\n            return import(\n                /* webpackChunkName: \"features/activator\" */\n                \"@egt/activator\")\n        case \"WILD_REPLACE\":\n            return import(\n                /* webpackChunkName: \"features/wild-replace\" */\n                \"@egt/wild-replace\")\n        case \"INTRO_ANIMATION\":\n            return import(\n                /* webpackChunkName: \"features/intro-animation\" */\n                \"@egt/intro-animation\")\n        case \"WIN_ANIMATIONS_PREVIEW\":\n            return import(\n                /* webpackChunkName: \"features/win-animations-preview\" */\n                \"@egt/win-animations-preview\") }\n        return Promise.reject();\n    /* ===== End of code block ===== */\n};\n/* tslint:enable:trailing-comma */\n\n/* tslint:disable:trailing-comma */\nCore.importComponent = (componentName: string): Promise<any> => {\n    /* ===== This code block was automatically generated by prebuild.js ===== */\n    /* ===== Start of code block ===== */\n    switch(componentName) {\n    \n        case \"UI_MAIN_PANEL\":\n            return import(\n                /* webpackChunkName: \"components/ui-main-panel\" */\n                \"@egt/ui-main-panel\")\n        case \"UI_VIEW\":\n            return import(\n                /* webpackChunkName: \"components/ui-view\" */\n                \"@egt/ui-view\")\n        case \"WIN\":\n            return import(\n                /* webpackChunkName: \"components/win\" */\n                \"@egt/win\")\n        case \"CLOCK\":\n            return import(\n                /* webpackChunkName: \"components/clock\" */\n                \"@egt/clock\")\n        case \"CHANGE_GAME_MODE\":\n            return import(\n                /* webpackChunkName: \"components/change-game-mode\" */\n                \"@egt/change-game-mode\")\n        case \"DOWNLOAD\":\n            return import(\n                /* webpackChunkName: \"components/download\" */\n                \"@egt/download\")\n        case \"REELS\":\n            return import(\n                /* webpackChunkName: \"components/reels\" */\n                \"@egt/reels\")\n        case \"NON_PROPORTIONAL_REELS\":\n            return import(\n                /* webpackChunkName: \"components/non-proportional-reels\" */\n                \"@egt/non-proportional-reels\")\n        case \"UNIVERSAL_REELS\":\n            return import(\n                /* webpackChunkName: \"components/universal-reels\" */\n                \"@egt/universal-reels\")\n        case \"CASCADE_REELS\":\n            return import(\n                /* webpackChunkName: \"components/cascade-reels\" */\n                \"@egt/cascade-reels\")\n        case \"CASCADE_WAYS_REELS\":\n            return import(\n                /* webpackChunkName: \"components/cascade-ways-reels\" */\n                \"@egt/cascade-ways-reels\")\n        case \"MESSAGE_BAR\":\n            return import(\n                /* webpackChunkName: \"components/message-bar\" */\n                \"@egt/message-bar\")\n        case \"MESSAGE_ALERT\":\n            return import(\n                /* webpackChunkName: \"components/message-alert\" */\n                \"@egt/message-alert\")\n        case \"MATCH_ID\":\n            return import(\n                /* webpackChunkName: \"components/match-id\" */\n                \"@egt/match-id\")\n        case \"REELS_OVERLAY\":\n            return import(\n                /* webpackChunkName: \"components/reels-overlay\" */\n                \"@egt/reels-overlay\")\n        case \"FLOATING_AMOUNT\":\n            return import(\n                /* webpackChunkName: \"components/floating-amount\" */\n                \"@egt/floating-amount\")\n        case \"GAME_LOGO\":\n            return import(\n                /* webpackChunkName: \"components/game-logo\" */\n                \"@egt/game-logo\")\n        case \"DEMO_MODE\":\n            return import(\n                /* webpackChunkName: \"components/demo-mode\" */\n                \"@egt/demo-mode\")\n        case \"MODAL_LAYER\":\n            return import(\n                /* webpackChunkName: \"components/modal-layer\" */\n                \"@egt/modal-layer\")\n        case \"GAME_TITLE\":\n            return import(\n                /* webpackChunkName: \"components/game-title\" */\n                \"@egt/game-title\")\n        case \"LINE_BUTTON\":\n            return import(\n                /* webpackChunkName: \"components/line-button\" */\n                \"@egt/line-button\")\n        case \"BACKGROUND\":\n            return import(\n                /* webpackChunkName: \"components/background\" */\n                \"@egt/background\")\n        case \"STAGE_MASK\":\n            return import(\n                /* webpackChunkName: \"components/stage-mask\" */\n                \"@egt/stage-mask\")\n        case \"BET_BUTTONS\":\n            return import(\n                /* webpackChunkName: \"components/bet-buttons\" */\n                \"@egt/bet-buttons\")\n        case \"FLOATING_TEXT\":\n            return import(\n                /* webpackChunkName: \"components/floating-text\" */\n                \"@egt/floating-text\")\n        case \"BG_ANIMATION\":\n            return import(\n                /* webpackChunkName: \"components/bg-animation\" */\n                \"@egt/bg-animation\")\n        case \"BACKGROUND_SOUND\":\n            return import(\n                /* webpackChunkName: \"components/background-sound\" */\n                \"@egt/background-sound\")\n        case \"MULTILAYERED_BG_SOUND\":\n            return import(\n                /* webpackChunkName: \"components/multilayered-bg-sound\" */\n                \"@egt/multilayered-bg-sound\")\n        case \"BUY_BONUS\":\n            return import(\n                /* webpackChunkName: \"components/buy-bonus\" */\n                \"@egt/buy-bonus\")\n        case \"CHARACTERS_ANIMATION\":\n            return import(\n                /* webpackChunkName: \"components/characters-animation\" */\n                \"@egt/characters-animation\")\n        case \"FRAME\":\n            return import(\n                /* webpackChunkName: \"components/frame\" */\n                \"@egt/frame\")\n        case \"PORTRAIT_LOGOS\":\n            return import(\n                /* webpackChunkName: \"components/portrait-logos\" */\n                \"@egt/portrait-logos\")\n        case \"HIGH_CASH_ANTICIPATION\":\n            return import(\n                /* webpackChunkName: \"components/high-cash-anticipation\" */\n                \"@egt/high-cash-anticipation\")\n        case \"HIGH_CASH_TRANSITION\":\n            return import(\n                /* webpackChunkName: \"components/high-cash-transition\" */\n                \"@egt/high-cash-transition\")\n        case \"HIGH_CASH_JACKPOT_LOGO\":\n            return import(\n                /* webpackChunkName: \"components/high-cash-jackpot-logo\" */\n                \"@egt/high-cash-jackpot-logo\")\n        case \"CASH_HEAT_LOGO\":\n            return import(\n                /* webpackChunkName: \"components/cash-heat-logo\" */\n                \"@egt/cash-heat-logo\")\n        case \"AUTOPLAY_POPUP\":\n            return import(\n                /* webpackChunkName: \"components/autoplay-popup\" */\n                \"@egt/autoplay-popup\")\n        case \"DENOMINATION_POPUP\":\n            return import(\n                /* webpackChunkName: \"components/denomination-popup\" */\n                \"@egt/denomination-popup\")\n        case \"SETTINGS_POPUP\":\n            return import(\n                /* webpackChunkName: \"components/settings-popup\" */\n                \"@egt/settings-popup\")\n        case \"FG_ANIMATION\":\n            return import(\n                /* webpackChunkName: \"components/fg-animation\" */\n                \"@egt/fg-animation\")\n        case \"PORTRAIT_GRADIENT\":\n            return import(\n                /* webpackChunkName: \"components/portrait-gradient\" */\n                \"@egt/portrait-gradient\")\n        case \"HOME_BUTTON\":\n            return import(\n                /* webpackChunkName: \"components/home-button\" */\n                \"@egt/home-button\")\n        case \"WAYS_COUNTER\":\n            return import(\n                /* webpackChunkName: \"components/ways-counter\" */\n                \"@egt/ways-counter\")\n        case \"CASCADE_WAYS_COUNTER\":\n            return import(\n                /* webpackChunkName: \"components/cascade-ways-counter\" */\n                \"@egt/cascade-ways-counter\")\n        case \"REEL_ANTICIPATION_ANIM\":\n            return import(\n                /* webpackChunkName: \"components/reel-anticipation-anim\" */\n                \"@egt/reel-anticipation-anim\")\n        case \"MULTI_REELS_MASK\":\n            return import(\n                /* webpackChunkName: \"components/multi-reels-mask\" */\n                \"@egt/multi-reels-mask\")\n        case \"SCRATCH_CLOCK\":\n            return import(\n                /* webpackChunkName: \"components/scratch-clock\" */\n                \"@egt/scratch-clock\")\n        case \"SCRATCH_BACKGROUND\":\n            return import(\n                /* webpackChunkName: \"components/scratch-background\" */\n                \"@egt/scratch-background\")\n        case \"SCRATCH_GAME_LOGO\":\n            return import(\n                /* webpackChunkName: \"components/scratch-game-logo\" */\n                \"@egt/scratch-game-logo\")\n        case \"SCRATCH_GAME_TITLE\":\n            return import(\n                /* webpackChunkName: \"components/scratch-game-title\" */\n                \"@egt/scratch-game-title\")\n        case \"SCRATCH_PANEL_BACKGROUND\":\n            return import(\n                /* webpackChunkName: \"components/scratch-panel-background\" */\n                \"@egt/scratch-panel-background\")\n        case \"SCRATCH_MAIN_PANEL\":\n            return import(\n                /* webpackChunkName: \"components/scratch-main-panel\" */\n                \"@egt/scratch-main-panel\")\n        case \"SCRATCH_UI_VIEW\":\n            return import(\n                /* webpackChunkName: \"components/scratch-ui-view\" */\n                \"@egt/scratch-ui-view\")\n        case \"SCRATCH_BONUS_PANEL\":\n            return import(\n                /* webpackChunkName: \"components/scratch-bonus-panel\" */\n                \"@egt/scratch-bonus-panel\")\n        case \"SCRATCH_WIN\":\n            return import(\n                /* webpackChunkName: \"components/scratch-win\" */\n                \"@egt/scratch-win\")\n        case \"SCRATCH_BALANCE\":\n            return import(\n                /* webpackChunkName: \"components/scratch-balance\" */\n                \"@egt/scratch-balance\")\n        case \"SCRATCH_MATCH_ID\":\n            return import(\n                /* webpackChunkName: \"components/scratch-match-id\" */\n                \"@egt/scratch-match-id\")\n        case \"SCRATCH_MESSAGE_BAR\":\n            return import(\n                /* webpackChunkName: \"components/scratch-message-bar\" */\n                \"@egt/scratch-message-bar\")\n        case \"SCRATCH_MODAL_POPUPS_BACKGROUND\":\n            return import(\n                /* webpackChunkName: \"components/scratch-modal-popups-background\" */\n                \"@egt/scratch-modal-popups-background\")\n        case \"SCRATCH_HELP\":\n            return import(\n                /* webpackChunkName: \"components/scratch-help\" */\n                \"@egt/scratch-help\")\n        case \"SCRATCH_PAYTABLE\":\n            return import(\n                /* webpackChunkName: \"components/scratch-paytable\" */\n                \"@egt/scratch-paytable\")\n        case \"SCRATCH_GENERAL_SETTINGS\":\n            return import(\n                /* webpackChunkName: \"components/scratch-general-settings\" */\n                \"@egt/scratch-general-settings\")\n        case \"SCRATCH_BG_ANIMATION\":\n            return import(\n                /* webpackChunkName: \"components/scratch-bg-animation\" */\n                \"@egt/scratch-bg-animation\")\n        case \"SCRATCH_STAGE_MASK\":\n            return import(\n                /* webpackChunkName: \"components/scratch-stage-mask\" */\n                \"@egt/scratch-stage-mask\")\n        case \"SCRATCH_BG_SOUND\":\n            return import(\n                /* webpackChunkName: \"components/scratch-bg-sound\" */\n                \"@egt/scratch-bg-sound\")\n        case \"JACKPOT_STATS\":\n            return import(\n                /* webpackChunkName: \"components/jackpot-stats\" */\n                \"@egt/jackpot-stats\")\n        case \"SCRATCH_STAGE_BLOCKER\":\n            return import(\n                /* webpackChunkName: \"components/scratch-stage-blocker\" */\n                \"@egt/scratch-stage-blocker\")\n        case \"SCRATCH_MODAL_LAYER\":\n            return import(\n                /* webpackChunkName: \"components/scratch-modal-layer\" */\n                \"@egt/scratch-modal-layer\")\n        case \"SCRATCH_JACKPOT_STATS\":\n            return import(\n                /* webpackChunkName: \"components/scratch-jackpot-stats\" */\n                \"@egt/scratch-jackpot-stats\")\n        case \"STAGE_BLOCKER\":\n            return import(\n                /* webpackChunkName: \"components/stage-blocker\" */\n                \"@egt/stage-blocker\")\n        case \"CONTAINER_REELS\":\n            return import(\n                /* webpackChunkName: \"components/container-reels\" */\n                \"@egt/container-reels\")\n        case \"HORIZONTAL_REEL\":\n            return import(\n                /* webpackChunkName: \"components/horizontal-reel\" */\n                \"@egt/horizontal-reel\")\n        case \"CASCADE_REEL_MULTIPLIER\":\n            return import(\n                /* webpackChunkName: \"components/cascade-reel-multiplier\" */\n                \"@egt/cascade-reel-multiplier\")\n        case \"CONTAINER_REELS\":\n            return import(\n                /* webpackChunkName: \"components/container-reels\" */\n                \"@egt/container-reels\")\n        case \"CASCADE_IDLE_ANIMATIONS\":\n            return import(\n                /* webpackChunkName: \"components/cascade-idle-animations\" */\n                \"@egt/cascade-idle-animations\")\n        case \"CASCADE_ANTICIPATION_ANIMATION\":\n            return import(\n                /* webpackChunkName: \"components/cascade-anticipation-animation\" */\n                \"@egt/cascade-anticipation-animation\")\n        case \"SCRATCH_HOME_BUTTON\":\n            return import(\n                /* webpackChunkName: \"components/scratch-home-button\" */\n                \"@egt/scratch-home-button\")\n        case \"FOOTER_BACKGROUND\":\n            return import(\n                /* webpackChunkName: \"components/footer-background\" */\n                \"@egt/footer-background\")\n        case \"BET_CALCULATOR\":\n            return import(\n                /* webpackChunkName: \"components/bet-calculator\" */\n                \"@egt/bet-calculator\")\n        case \"BET_PROGRESS\":\n            return import(\n                /* webpackChunkName: \"components/bet-progress\" */\n                \"@egt/bet-progress\")\n        case \"HIGH_RTP_BADGE\":\n            return import(\n                /* webpackChunkName: \"components/high-rtp-badge\" */\n                \"@egt/high-rtp-badge\")\n        case \"MAX_WIN_PROBABILITY\":\n            return import(\n                /* webpackChunkName: \"components/max-win-probability\" */\n                \"@egt/max-win-probability\")\n        case \"SYMBOL_FRAMES\":\n            return import(\n                /* webpackChunkName: \"components/symbol-frames\" */\n                \"@egt/symbol-frames\")\n        case \"VLT\":\n            return import(\n                /* webpackChunkName: \"components/vlt\" */\n                \"@egt/vlt\")\n        case \"BL_BOOST_SPECIAL_BELLS_ANIMATIONS\":\n            return import(\n                /* webpackChunkName: \"components/bl-boost-special-bells-animations\" */\n                \"@egt/bl-boost-special-bells-animations\") }\n        return Promise.reject();\n    /* ===== End of code block ===== */\n};\n/* tslint:disable:trailing-comma */\n\n/* ===== This code block was automatically generated by prebuild.js ===== */\n/* ===== Start of code block ===== */\nCore.configuration.protocol = 'https';\nCore.configuration.host = 'casino3-game-server-ong-qa-ext.egt-ong.com/game-websocket/';\nCore.configuration.multiplayerHost = 'multigs-ong-qa-ext.egt-ong.com/multiplayer-websocket';\nCore.configuration.demo = true;\nCore.configuration.devTools = true;\nCore.configuration.language = 'EN';\nCore.configuration.sessionToken = '12f33168-5ead-419a-aa72-b552dfdaf841';\nCore.configuration.playerId = '1101';\nCore.configuration.casinoId = 'EGTBG';\nCore.configuration.gameKey = 'RORSlot';\nCore.configuration.resourcesRootDir = '';\nCore.configuration.currencyCode = 'EGT';\nCore.configuration.hasPortal = true;\nCore.configuration.historyHost = 'https://player-history-ong-qa-ext.egt-ong.com/#/';\nCore.configuration.tournamentHost = 'https://tournaments-ong-qa-ext.egt-ong.com/';\nCore.configuration.prizePopServiceHost = 'https://prize-pop-service-qa-ext.egt-ong.com/';\nCore.configuration.multiplayerApi = 'https://multiplay-ong-qa-ext.egt-ong.com/api/custom/crash-factor/';\nCore.configuration.scenarioHost = 'https://api-uc-ong-qa-ext.egt-ong.com/';\nCore.configuration.assetPackHost = 'https://assets-texture-tool-ong-dev.egtnext.com/';\nCore.configuration.allowHostOverrideFromUrl = true;\nCore.configuration.lobbyHost = 'https://egtd-lobby-ong-dev.egt-ong.com';\nCore.configuration.apiIntegrationHost = 'https://casino3-api-ong-qa-ext.egt-ong.com';\nCore.configuration.replayHost = 'https://replays-ong-qa-ext.egt-ong.com/replayservice/';\nCore.configuration.version = '1.65.0-rc.11';\n/* ===== End of code block ===== */\n\n/* ===== This code block was automatically generated by prebuild.js ===== */\n        /* ===== Start of code block ===== */\nimport { DeveloperTools } from '@egt/dev-tools';\nCore.devTools = new DeveloperTools(Core.environment);\n/* ===== End of code block ===== */\n\n/* ===== This code block was automatically generated by prebuild.js ===== */\n/* ===== Start of code block ===== */\nCore.init();\n/* ===== End of code block ===== */\n","import Core, { AssetPriority, BaseComponent, IModeConfig, Log } from '@egt/core';\nimport { SlotComponents, ZOrders } from '@egt/slot';\nimport { Lifecycle } from 'tsyringe';\nimport AutoplayPopupModesConfigurations, { AutoplayPopupModes } from './AutoplayPopupFactory';\nimport { AutoplayPopupConfigFactoryDefault } from './modes/default/configuration/AutoplayPopupComponentConfigurationDefault';\nimport AutoplayPopupSubjectsDefault from './modes/default/subjects/AutoplayPopupSubjectsDefault';\nimport { AutoplayPopupConfigFactoryExtended } from './modes/extended/configuration/AutoplayPopupComponentConfigurationExtended';\nimport AutoplayPopupControllerExtended from './modes/extended/controllers/AutoplayPopupControllerExtended';\nimport { IAutoplayPopupComponentConfigurationExtended } from './modes/extended/interfaces/InterfacesExtended';\nimport AutoplayPopupViewExtended from './modes/extended/views/AutoplayPopupViewExtended';\nimport { AutoplayPopupConfigFactoryMaxBet } from './modes/max-bet/configuration/AutoplayPopupComponentConfigurationMaxBet';\nimport AutoplayPopupShadowViewMaxBet from './modes/max-bet/views/AutoplayPopupShadowViewMaxBet';\nimport { AutoplayPopupConfigFactoryNumeric } from './modes/numeric/configuration/AutoplayPopupComponentConfigurationNumeric';\n\nexport default class AutoplayPopupComponent extends BaseComponent {\n    public static configurationName = 'AutoplayPopupComponent';\n\n    public autoplayPopup: AutoplayPopupViewExtended;\n    public autoplayShadowView: AutoplayPopupShadowViewMaxBet;\n    public autoplayPopupController: AutoplayPopupControllerExtended;\n    public componentType = SlotComponents.AUTOPLAY_POPUP;\n    public configuration: IAutoplayPopupComponentConfigurationExtended;\n    public rootView;\n\n    constructor(modeConfig: IModeConfig) {\n        super();\n        const baseConfigs = {\n            [AutoplayPopupModes.DEFAULT]: AutoplayPopupConfigFactoryDefault,\n            [AutoplayPopupModes.EXTENDED]: AutoplayPopupConfigFactoryExtended,\n            [AutoplayPopupModes.NUMERIC]: AutoplayPopupConfigFactoryNumeric,\n            [AutoplayPopupModes.MAX_BET]: AutoplayPopupConfigFactoryMaxBet,\n        };\n        this.modeFactory = this.initMode<AutoplayPopupModesConfigurations>(modeConfig, {\n            defaultModeType: AutoplayPopupModes.DEFAULT,\n            baseConfigs,\n            defaultFactory: AutoplayPopupModesConfigurations,\n        });\n    }\n\n    public destroy(): void {\n        this.autoplayPopupController.destroy();\n        // @ts-ignore\n        this.autoplayPopupController = null;\n        // @ts-ignore\n        this.autoplayPopup = null;\n\n        (this.configuration as any)?.destroy();\n        // @ts-ignore\n        this.configuration = null;\n        // @ts-ignore\n        this.dependencyContainer = null;\n        // @ts-ignore\n        this.config = null;\n        // @ts-ignore\n        this.rootView = null;\n        // @ts-ignore\n        this.initialSettings = null;\n\n        super.destroy();\n    }\n\n    public onAfterGameConfigurationCreated(): void {\n        super.onAfterGameConfigurationCreated();\n        this.configuration = this.dependencyContainer.resolve('AutoplayPopupComponentConfiguration');\n    }\n\n    public onRegisterDependencies(container: any): void {\n        super.onRegisterDependencies(container);\n\n        // if (!this.dependencyContainer.isRegistered('AutoplayPopupView')) {\n        this.dependencyContainer.register(\n            'AutoplayPopupView',\n            { useClass: this.mode.view },\n            { lifecycle: Lifecycle.Singleton },\n        );\n        // }\n\n        // if (!this.dependencyContainer.isRegistered('AutoplayPopupController')) {\n        this.dependencyContainer.register(\n            'AutoplayPopupController',\n            { useClass: this.mode.controller },\n            { lifecycle: Lifecycle.Singleton },\n        );\n        // }\n\n        // if (this.config) {\n        //     this.dependencyContainer.register(\n        //         'AutoplayPopupComponentConfiguration',\n        //         this.config(autoplayPopupConfigFactoryExtended()),\n        //     );\n        // } else {\n        this.dependencyContainer.register('AutoplayPopupComponentConfiguration', this.mode.configuration);\n        // }\n\n        if (this.modeFactory.modeType === AutoplayPopupModes.MAX_BET) {\n            this.dependencyContainer.register(\n                'AutoplayPopupShadowView',\n                { useClass: this.mode.secondView },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n\n        if (this.modeFactory.modeType === AutoplayPopupModes.DEFAULT) {\n            this.dependencyContainer.register(\n                'AutoplayPopupSubjects',\n                { useClass: AutoplayPopupSubjectsDefault },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n    }\n\n    public onPrepareResources(_container: any): void {\n        if (this.modeFactory.modeType !== AutoplayPopupModes.DEFAULT) {\n            Core.fonts.addAssets([\n                {\n                    id: 'RobotoCondensed-Regular',\n                    url: '../assets/Fonts/Roboto/RobotoCondensed-Regular.ttf',\n                    priority: AssetPriority.HIGHEST,\n                    type: 'font',\n                },\n                {\n                    id: 'RobotoCondensed-Bold',\n                    url: '../assets/Fonts/Roboto/RobotoCondensed-Bold.ttf',\n                    priority: AssetPriority.HIGHEST,\n                    type: 'font',\n                },\n            ]);\n        }\n        Core.assets.addAssets(this.configuration?.assets?.toArray() || []);\n    }\n\n    public onResolveDependencies(container: any): void {\n        super.onResolveDependencies(container);\n\n        // to do: remove this - this view component must be injected dynamicaly on popup component\n        this.rootView = this.dependencyContainer.resolve('RootView');\n        this.autoplayPopup = this.dependencyContainer.resolve('AutoplayPopupView');\n        this.autoplayPopupController = this.dependencyContainer.resolve('AutoplayPopupController');\n        this.autoplayPopup.zIndex = ZOrders.POPUP_LEVEL;\n        this.rootView.addChild(this.autoplayPopup);\n\n        if (this.modeFactory.modeType === AutoplayPopupModes.MAX_BET) {\n            this.autoplayShadowView = this.dependencyContainer.resolve('AutoplayPopupShadowView');\n            this.autoplayShadowView.zIndex = ZOrders.REELS_LEVEL;\n            this.rootView.addChild(this.autoplayShadowView);\n        }\n\n        if (Core?.devTools) {\n            const scalerInstance = this.dependencyContainer.resolve('CustomScaler');\n            switch (this.modeFactory.modeType) {\n                case AutoplayPopupModes.EXTENDED:\n                    import('./modes/extended/configuration/AutoplayPopupExtendedScalerConfigInitializer')\n                        .then((initializerImport) => initializerImport.default(scalerInstance))\n                        .catch((err) => Log.debug('error loading scaler config file: ', err));\n                    break;\n                case AutoplayPopupModes.NUMERIC:\n                    import('./modes/numeric/configuration/AutoplayPopupNumericScalerConfigInitializer')\n                        .then((initializerImport) => initializerImport.default(scalerInstance))\n                        .catch((err) => Log.debug('error loading scaler config file: ', err));\n                    break;\n                case AutoplayPopupModes.MAX_BET:\n                    import('./modes/max-bet/configuration/AutoplayPopupMaxBetScalerConfigInitializer')\n                        .then((initializerImport) => initializerImport.default(scalerInstance))\n                        .catch((err) => Log.debug('error loading scaler config file: ', err));\n                    break;\n                default:\n                    import('./modes/default/configuration/AutoplayPopupDefaultScalerConfigInitializer')\n                        .then((initializerImport) => initializerImport.default(scalerInstance))\n                        .catch((err) => Log.debug('error loading scaler config file: ', err));\n                    break;\n            }\n        }\n    }\n\n    public onInit(): void {\n        this.autoplayPopup.init();\n        this.autoplayPopupController.init();\n        if (this.modeFactory.modeType === AutoplayPopupModes.MAX_BET) {\n            this.autoplayShadowView.init();\n        }\n    }\n}\n","import { BaseModesConfigurations, IForceSetConfig, IModes } from '@egt/core';\nimport AutoplayPopupControllerDefault from './modes/default/controllers/AutoplayPopupControllerDefault';\nimport AutoplayPopupViewDefault from './modes/default/views/AutoplayPopupViewDefault';\nimport { AutoplayPopupConfigFactoryDefault } from './modes/default/configuration/AutoplayPopupComponentConfigurationDefault';\nimport { AutoplayPopupConfigFactoryExtended } from './modes/extended/configuration/AutoplayPopupComponentConfigurationExtended';\nimport AutoplayPopupViewExtended from './modes/extended/views/AutoplayPopupViewExtended';\nimport AutoplayPopupControllerExtended from './modes/extended/controllers/AutoplayPopupControllerExtended';\nimport { AutoplayPopupConfigFactoryNumeric } from './modes/numeric/configuration/AutoplayPopupComponentConfigurationNumeric';\nimport AutoplayPopupViewNumeric from './modes/numeric/views/AutoplayPopupViewNumeric';\nimport AutoplayPopupControllerNumeric from './modes/numeric/controllers/AutoplayPopupControllerNumeric';\nimport AutoplayPopupControllerMaxBet from './modes/max-bet/controllers/AutoplayPopupControllerMaxBet';\nimport AutoplayPopupViewMaxBet from './modes/max-bet/views/AutoplayPopupViewMaxBet';\nimport { AutoplayPopupConfigFactoryMaxBet } from './modes/max-bet/configuration/AutoplayPopupComponentConfigurationMaxBet';\nimport AutoplayPopupShadowViewMaxBet from './modes/max-bet/views/AutoplayPopupShadowViewMaxBet';\nexport default class AutoplayPopupModesConfigurations extends BaseModesConfigurations<AutoplayPopupModes> {\n    constructor(modeType: AutoplayPopupModes, forceSetConfig?: IForceSetConfig) {\n        super(modeType, forceSetConfig);\n    }\n\n    protected createBaseModesConfig(modeType: AutoplayPopupModes): IModes {\n        switch (modeType) {\n            case AutoplayPopupModes.EXTENDED:\n                return {\n                    controller: AutoplayPopupControllerExtended,\n                    view: AutoplayPopupViewExtended,\n                    configuration: AutoplayPopupConfigFactoryExtended(),\n                };\n            case AutoplayPopupModes.NUMERIC:\n                return {\n                    controller: AutoplayPopupControllerNumeric,\n                    view: AutoplayPopupViewNumeric,\n                    configuration: AutoplayPopupConfigFactoryNumeric(),\n                };\n            case AutoplayPopupModes.MAX_BET:\n                return {\n                    controller: AutoplayPopupControllerMaxBet,\n                    view: AutoplayPopupViewMaxBet,\n                    secondView: AutoplayPopupShadowViewMaxBet,\n                    configuration: AutoplayPopupConfigFactoryMaxBet(),\n                };\n            default:\n                return {\n                    controller: AutoplayPopupControllerDefault,\n                    view: AutoplayPopupViewDefault,\n                    configuration: AutoplayPopupConfigFactoryDefault(),\n                };\n        }\n    }\n}\n\nexport enum AutoplayPopupModes {\n    DEFAULT = 'default',\n    EXTENDED = 'extended',\n    NUMERIC = 'numeric',\n    MAX_BET = 'max-bet',\n}\n","import AutoplayPopupComponent from './AutoplayPopupComponent';\nimport {\n    IAutoPlayArrowPositionsExtended,\n    IAutoPlayPositionsExtended,\n    IAutoPlaySelectedBtnPositionsExtended,\n    IAutoplayBtnTextExtended,\n    IAutoplayPopUpTextExtended,\n    IAutoplayPopUpTitleTextExtended,\n    IAutoplayPositionObjectExtended,\n    IBalanceAndBetTextExtended,\n    IAutoplayPopupComponentConfigurationExtended,\n    IMainContainerPositionExtended,\n    ISliderPositionObjectExtended,\n} from './modes/extended/interfaces/InterfacesExtended';\nimport {\n    IAutoplayPopupComponentConfigurationDefault,\n    IAutoplayButtonInterfaceDefault,\n    IAutoplayPopupInterfaceDefault,\n} from './modes/default/interfaces/InterfacesDefault';\nimport {\n    IAutoplayPopupConfigurationNumeric,\n    IAutoPlayPositionsNumeric,\n    IAutoplayPositionObjectNumeric,\n    IAutoplayPopUpTextNumeric,\n    IAutoPlayArrowPositionsNumeric,\n    IBalanceAndBetTextNumeric,\n    IAutoPlaySelectedBtnPositionsNumeric,\n    IMainContainerPositionNumeric,\n    IAutoplayBtnTextNumeric,\n    IAutoplayPopUpTitleTextNumeric,\n} from './modes/numeric/interfaces/InterfacesNumeric';\nimport AutoplayPopupComponentConfigurationDefault, {\n    AutoplayPopupConfigFactoryDefault,\n} from './modes/default/configuration/AutoplayPopupComponentConfigurationDefault';\nimport AutoplayPopupControllerDefault from './modes/default/controllers/AutoplayPopupControllerDefault';\nimport AutoplayPopupViewDefault from './modes/default/views/AutoplayPopupViewDefault';\nimport AutoplayPopupSubjectsDefault from './modes/default/subjects/AutoplayPopupSubjectsDefault';\nimport AutoplayPopupComponentConfigurationExtended, {\n    AutoplayPopupConfigFactoryExtended,\n} from './modes/extended/configuration/AutoplayPopupComponentConfigurationExtended';\nimport AutoplayPopupComponentConfigurationNumeric from './modes/numeric/configuration/AutoplayPopupComponentConfigurationNumeric';\nimport { MandatoryValuesNumeric } from './modes/numeric/controllers/AutoplayPopupControllerNumeric';\nimport AutoplayPopupComponentConfigurationMaxBet, {\n    AutoplayPopupConfigFactoryMaxBet,\n} from './modes/max-bet/configuration/AutoplayPopupComponentConfigurationMaxBet';\nimport AutoplayPopupModesConfigurations, { AutoplayPopupModes } from './AutoplayPopupFactory';\nimport AutoplayPopupControllerExtended from './modes/extended/controllers/AutoplayPopupControllerExtended';\nimport AutoplayPopupViewExtended from './modes/extended/views/AutoplayPopupViewExtended';\nimport AutoplayPopupControllerMaxBet from './modes/max-bet/controllers/AutoplayPopupControllerMaxBet';\nimport AutoplayPopupViewMaxBet from './modes/max-bet/views/AutoplayPopupViewMaxBet';\nimport {\n    IAutoPlayArrowPositionsMaxBet,\n    IAutoPlaySelectedBtnPositionsMaxBet,\n    IMainContainerPositionMaxBet,\n    ITextContainerMaxBet,\n    IAutoPlayPositionsMaxBet,\n    IAutoplayPositionObjectMaxBet,\n    ICurvePositionMaxBet,\n    IAutoplayPopupConfigurationMaxBet,\n    IAutoplayPopUpTextMaxBet,\n} from './modes/max-bet/interfaces/InterfacesMaxBet';\n\nexport {\n    IAutoplayPopupComponentConfigurationDefault,\n    IAutoplayButtonInterfaceDefault,\n    IAutoplayPopupInterfaceDefault,\n    AutoplayPopupComponentConfigurationDefault,\n    AutoplayPopupControllerDefault,\n    AutoplayPopupViewDefault,\n    AutoplayPopupSubjectsDefault,\n    IAutoplayPopupConfigurationNumeric,\n    AutoplayPopupComponentConfigurationNumeric,\n    IAutoPlayPositionsNumeric,\n    IAutoplayPositionObjectNumeric,\n    IAutoplayPopUpTextNumeric,\n    IAutoPlayArrowPositionsNumeric,\n    IBalanceAndBetTextNumeric,\n    IAutoPlaySelectedBtnPositionsNumeric,\n    IMainContainerPositionNumeric,\n    IAutoplayBtnTextNumeric,\n    IAutoplayPopUpTitleTextNumeric,\n    MandatoryValuesNumeric,\n    IAutoplayPopupComponentConfigurationExtended,\n    AutoplayPopupComponentConfigurationExtended,\n    IAutoPlayPositionsExtended,\n    IAutoplayPositionObjectExtended,\n    IAutoplayPopUpTextExtended,\n    IAutoPlayArrowPositionsExtended,\n    IBalanceAndBetTextExtended,\n    IAutoPlaySelectedBtnPositionsExtended,\n    IMainContainerPositionExtended,\n    ISliderPositionObjectExtended,\n    IAutoplayBtnTextExtended,\n    IAutoplayPopUpTitleTextExtended,\n    AutoplayPopupComponentConfigurationMaxBet,\n    AutoplayPopupModes,\n    AutoplayPopupControllerExtended,\n    AutoplayPopupViewExtended,\n    AutoplayPopupControllerMaxBet,\n    AutoplayPopupViewMaxBet,\n    AutoplayPopupModesConfigurations,\n    IAutoPlayArrowPositionsMaxBet,\n    IAutoPlaySelectedBtnPositionsMaxBet,\n    IAutoplayPopUpTextMaxBet,\n    IMainContainerPositionMaxBet,\n    ITextContainerMaxBet,\n    IAutoPlayPositionsMaxBet,\n    IAutoplayPositionObjectMaxBet,\n    IAutoplayPopupConfigurationMaxBet,\n    AutoplayPopupConfigFactoryExtended,\n    AutoplayPopupConfigFactoryMaxBet,\n    AutoplayPopupConfigFactoryDefault,\n    ICurvePositionMaxBet,\n};\nexport default AutoplayPopupComponent;\n","import {\n    AssetsCollection,\n    BaseComponentConfiguration,\n    DefaultAssets,\n    DefaultValue,\n    DynamicPositionObject,\n} from '@egt/core';\nimport { TextStyle } from 'pixi.js';\nimport {\n    IAutoplayButtonInterfaceDefault,\n    IAutoplayPopupComponentConfigurationDefault,\n    IAutoplayPopupInterfaceDefault,\n} from '../interfaces/InterfacesDefault';\n\nexport default class AutoplayPopupComponentConfigurationDefault extends BaseComponentConfiguration {}\nexport function AutoplayPopupConfigFactoryDefault(): any {\n    class InternalAutoplayPopupComponentConfigurationDefault\n        extends AutoplayPopupComponentConfigurationDefault\n        implements IAutoplayPopupComponentConfigurationDefault\n    {\n        @DefaultAssets([])\n        public assets: AssetsCollection;\n\n        @DefaultValue<IAutoplayPopupInterfaceDefault>({\n            defaults: {\n                x: 99,\n                y: 960,\n                width: 178,\n                leftHandX: 0,\n                arrowYOffset: 9,\n                arrowXOffset: 89,\n                arrowAngle: 90,\n                arrowLeftHandAngle: 0,\n                buttonsContainerYOffset: 20,\n                hasOverlayBackground: false,\n                titleStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fontSize: 24,\n                    fill: '#CFCFCF',\n                    align: 'center',\n                    letterSpacing: 1.2,\n                }),\n                hasShadow: true,\n                headerBorderColor: 0x787878,\n                headerColor: 0x141414,\n                borderRadius: 10,\n                borderColor: 0xf1f1f1,\n                borderSize: 2,\n                useArcs: true,\n                backgroundColor: 0x0,\n                backgroundAlpha: 1,\n            },\n            landscape: {\n                x: 1017,\n                y: 7,\n                leftHandX: 165,\n                arrowYOffset: 96,\n                arrowXOffset: 9,\n                arrowAngle: 0,\n                arrowLeftHandAngle: 180,\n            },\n            desktop: { x: 1026, y: 17, width: 160, arrowYOffset: 189, arrowXOffset: 9, arrowAngle: 0 },\n        })\n        public popupProps: DynamicPositionObject<IAutoplayPopupInterfaceDefault> & IAutoplayPopupInterfaceDefault;\n\n        @DefaultValue<IAutoplayButtonInterfaceDefault>({\n            defaults: {\n                buttonTextures: ['svgBet', 'svgBetPressed', 'svgBet', 'svgBet'],\n                buttonWidth: 120,\n                buttonHeight: 96,\n                buttonOffsetY: 18,\n                additionalButtonOffsetY: 70,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fill: '#FFFFFF',\n                    fontWeight: 'bold',\n                    fontSize: 42,\n                }),\n                textOffsetX: 0,\n                textOffsetY: 0,\n                autoplayMenuShow: true,\n                infinityTexture: 'svgInfinityBoldedSelected',\n            },\n            desktop: {\n                buttonWidth: 94,\n                buttonHeight: 74,\n                buttonOffsetY: 20,\n            },\n        })\n        public autoplayButtonProps: DynamicPositionObject<IAutoplayButtonInterfaceDefault> &\n            IAutoplayButtonInterfaceDefault;\n    }\n\n    return InternalAutoplayPopupComponentConfigurationDefault;\n}\n","import Core, { BaseController } from '@egt/core';\nimport { RootStore } from '@egt/slot';\nimport { merge } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport AutoplayPopupSubjectsDefault from '../subjects/AutoplayPopupSubjectsDefault';\nimport AutoplayPopupViewDefault from '../views/AutoplayPopupViewDefault';\n\n@injectable()\nexport default class AutoplayPopupControllerDefault extends BaseController {\n    constructor(\n        @inject('AutoplayPopupView') protected autoplayPopup: AutoplayPopupViewDefault,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('AutoplayPopupSubjects') protected subjects: AutoplayPopupSubjectsDefault,\n    ) {\n        super(autoplayPopup);\n    }\n\n    public destroy(): void {\n        super.destroy();\n    }\n\n    public init(): void {\n        this.rootStore.subjects.TOGGLE_AUTOPLAY_POPUP.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.toggleAutoplayPopup.bind(this),\n        );\n        this.rootStore.subjects.CLOSE_ALL_POPUPS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.forceClosePopup.bind(this),\n        );\n        const closeFlow = merge(this.DESTROY, this.rootStore.subjects.CLOSE_AUTOPLAY_POPUP);\n        closeFlow.pipe(takeUntil(closeFlow)).subscribe(this.closePopup.bind(this, false));\n\n        this.rootStore.subjects.MODAL_PRESSED.pipe(takeUntil(this.DESTROY)).subscribe(this.closePopup.bind(this, true));\n    }\n\n    private toggleAutoplayPopup(): void {\n        if (this.autoplayPopup.isOpened) {\n            Core.sounds.play('hideDenominationsSound');\n            this.closePopup();\n        } else {\n            Core.sounds.play('showDenominationsSound');\n            this.openPopup();\n        }\n    }\n\n    private closePopup(animation: boolean = true): void {\n        if (this.autoplayPopup.isOpened) {\n            this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(false);\n            this.autoplayPopup.close(animation);\n        }\n    }\n\n    private forceClosePopup(): void {\n        if (this.autoplayPopup.isOpened) {\n            this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(false);\n        }\n        this.autoplayPopup.forceClose();\n    }\n\n    private openPopup(animation: boolean = true): void {\n        if (!this.autoplayPopup.isOpened) {\n            this.rootStore.subjects.CLOSE_ALL_POPUPS.next();\n            this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(true);\n            this.autoplayPopup.open(animation);\n        }\n    }\n}\n","import { Subject } from 'rxjs';\nimport { injectable } from 'tsyringe';\n\n@injectable()\nexport default class AutoplayPopupSubjectsDefault {\n    public readonly BEFORE_CLOSE: Subject<void> = new Subject();\n    public readonly BEFORE_OPEN: Subject<void> = new Subject();\n    public readonly AFTER_OPEN: Subject<void> = new Subject();\n}\n","import Core, { ErrorTypes, IErrorData, IOrientation } from '@egt/core';\nimport { SettingsTab } from '@egt/settings-popup';\nimport { InitialSettings, RootStore } from '@egt/slot';\nimport { Button, ButtonStates, ITitledWindowConfig, TitledWindow, ViewContainer } from '@egt/ui-lib';\nimport { gsap } from 'gsap';\nimport { Container, Graphics, Sprite, Text, TextStyle } from 'pixi.js';\nimport { fromEvent } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { IAutoplayPopupComponentConfigurationDefault } from '../interfaces/InterfacesDefault';\nimport AutoplayPopupSubjectsDefault from '../subjects/AutoplayPopupSubjectsDefault';\n\n@injectable()\nexport default class AutoplayPopupViewDefault extends ViewContainer {\n    public backgroundWindow: TitledWindow;\n    public arrowSprite: Sprite;\n    public config = {} as ITitledWindowConfig;\n    public autoplayButtonsTextures: any[] = [];\n    public buttonsCount = 0;\n\n    protected buttonsContainer: Container;\n    private _isOpened: boolean = false;\n    private animationTween: any;\n    private overlay: Graphics;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('AutoplayPopupSubjects') protected subjects: AutoplayPopupSubjectsDefault,\n        @inject('AutoplayPopupComponentConfiguration')\n        protected componentConfiguration: IAutoplayPopupComponentConfigurationDefault,\n    ) {\n        super();\n    }\n\n    public init(): void {\n        this.initialRender();\n\n        Core.LEFT_HAND_MODE.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.setOrientation(Core.ORIENTATION.value);\n        });\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n    }\n\n    public get isOpened(): boolean {\n        return this._isOpened;\n    }\n\n    public set isOpened(value: boolean) {\n        this._isOpened = value;\n    }\n\n    public destroy(): void {\n        this.killAllAnimations();\n        this.subjects.BEFORE_CLOSE.complete();\n        this.subjects.BEFORE_OPEN.complete();\n        this.subjects.AFTER_OPEN.complete();\n        // @ts-ignore\n        this.BEFORE_CLOSE = null;\n        // @ts-ignore\n        this.BEFORE_OPEN = null;\n        // @ts-ignore\n        this.AFTER_OPEN = null;\n\n        if (this.overlay) {\n            this.removeChild(this.overlay);\n            this.overlay.destroy();\n            // @ts-ignore\n            this.overly = null;\n        }\n\n        if (this.buttonsContainer) {\n            this.buttonsContainer.removeChildren();\n            this.buttonsContainer.destroy({ children: true, texture: true });\n            // @ts-ignore\n            this.buttonsContainer = null;\n        }\n        if (this.backgroundWindow) {\n            this.backgroundWindow.destroy();\n            // @ts-ignore\n            this.backgroundWindow = null;\n        }\n        if (this.arrowSprite) {\n            this.arrowSprite.destroy();\n            // @ts-ignore\n            this.arrowSprite = null;\n        }\n        if (this.autoplayButtonsTextures) {\n            this.autoplayButtonsTextures.forEach((texture) => {\n                texture.destroy();\n            });\n            this.autoplayButtonsTextures.length = 0;\n            // @ts-ignore\n            this.autoplayButtonsTextures = null;\n        }\n        super.destroy();\n    }\n\n    public open(animation: boolean): void {\n        this.subjects.BEFORE_OPEN.next();\n        this.killAllAnimations();\n\n        // Reset\n        this.alpha = 0;\n        this.visible = true;\n\n        if (animation) {\n            this.animationTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/autoplay-popup/src/egt/modes/default/views/AutoplayPopupViewDefault.ts:108:35\",null]), gsap.to(this, {\n                duration: 0.2,\n                alpha: 1,\n                ease: 'power2.in',\n                onComplete: () => {\n                    this.isOpened = true;\n                    this.subjects.AFTER_OPEN.next();\n                },\n            }));\n        } else {\n            this.isOpened = true;\n            this.alpha = 1;\n            this.subjects.AFTER_OPEN.next();\n        }\n    }\n\n    public close(animation: boolean): void {\n        this.subjects.BEFORE_CLOSE.next();\n        this.killAllAnimations();\n\n        // Reset\n        this.alpha = 1;\n\n        if (animation) {\n            this.animationTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/autoplay-popup/src/egt/modes/default/views/AutoplayPopupViewDefault.ts:132:35\",null]), gsap.to(this, {\n                duration: 0.2,\n                alpha: 0,\n                ease: 'power2.in',\n                onComplete: () => {\n                    this.visible = false;\n                    this.isOpened = false;\n                },\n            }));\n        } else {\n            this.alpha = 0;\n            this.visible = false;\n            this.isOpened = false;\n        }\n    }\n\n    public forceClose(): void {\n        this.killAllAnimations();\n        this.alpha = 0;\n        this.visible = false;\n        this.isOpened = false;\n    }\n\n    protected setOrientation(orientation: IOrientation): void {\n        if (this.isOpened) {\n            this.close(false);\n            this.open(false);\n        }\n\n        const isLandscape: boolean = orientation.isLandscape;\n\n        isLandscape ? this.pivot.set(0, 0) : this.pivot.set(0, this.config.height);\n\n        this.x = this.componentConfiguration.popupProps.x;\n        this.y = this.componentConfiguration.popupProps.y;\n\n        if (isLandscape) {\n            if (Core.LEFT_HAND_MODE.value) {\n                this.config.shadow = 'right';\n                this.arrowSprite.angle = this.componentConfiguration.popupProps.arrowLeftHandAngle;\n                this.arrowSprite.x = -this.componentConfiguration.popupProps.arrowXOffset;\n            } else {\n                this.config.shadow = 'left';\n                this.arrowSprite.angle = this.componentConfiguration.popupProps.arrowAngle;\n                this.arrowSprite.x = this.config.width + this.componentConfiguration.popupProps.arrowXOffset;\n            }\n            this.arrowSprite.y = this.componentConfiguration.popupProps.arrowYOffset;\n        } else {\n            this.config.shadow = 'left';\n            this.arrowSprite.angle = this.componentConfiguration.popupProps.arrowAngle;\n            this.arrowSprite.x = this.componentConfiguration.popupProps.arrowXOffset;\n            this.arrowSprite.y = this.config.height + this.componentConfiguration.popupProps.arrowYOffset;\n        }\n        if (this.overlay) {\n            this.overlay.width = orientation.width;\n            this.overlay.height = orientation.height;\n            this.overlay.x = -this.componentConfiguration.popupProps.x;\n            this.overlay.y = isLandscape\n                ? -this.componentConfiguration.popupProps.y\n                : -this.componentConfiguration.popupProps.y + this.config.height;\n        }\n        this.backgroundWindow.redrawShadows();\n    }\n\n    protected initialRender(): void {\n        this.alpha = 0;\n        this.visible = false;\n\n        this.buttonsContainer = new Container();\n        this.createAutoplayBets();\n        this.createAutoplayBackground();\n\n        if (this.componentConfiguration.popupProps.hasOverlayBackground) {\n            this.createOverlayBackground();\n        }\n\n        // buttons\n        this.addChild(this.buttonsContainer);\n        this.buttonsContainer.y =\n            this.config.headerHeight + this.componentConfiguration.popupProps.buttonsContainerYOffset;\n        this.buttonsContainer.x = (this.config.width - this.buttonsContainer.width) / 2;\n\n        // arrow\n        this.arrowSprite = new Sprite(Core.assets.getTextureFromSpriteSheet('miscellaneous', 'arrowBlack.png'));\n        this.arrowSprite.pivot.set(this.arrowSprite.width / 2, this.arrowSprite.height / 2);\n        this.arrowSprite.interactive = true;\n        this.addChild(this.arrowSprite);\n        this.interactive = true;\n    }\n\n    protected createAutoplayBackground(): void {\n        this.config.borderLeftUpTexture = Core.assets.getTextureFromSpriteSheet('miscellaneous', 'windowCornerLu.png');\n\n        if (this.componentConfiguration.popupProps.hasShadow) {\n            this.config.textureShadow = Core.assets.getTextureFromSpriteSheet('miscellaneous', 'shadow.png');\n            this.config.shadow = 'left';\n        }\n        this.config.backgroundColor = this.componentConfiguration.popupProps.backgroundColor;\n        this.config.backgroundAlpha = this.componentConfiguration.popupProps.backgroundAlpha;\n        this.config.useArcs = this.componentConfiguration.popupProps.useArcs;\n        this.config.headerBorderColor = this.componentConfiguration.popupProps.headerBorderColor;\n        this.config.headerColor = this.componentConfiguration.popupProps.headerColor;\n        this.config.borderRadius = this.componentConfiguration.popupProps.borderRadius;\n        this.config.borderSize = this.componentConfiguration.popupProps.borderSize;\n        this.config.borderColor = this.componentConfiguration.popupProps.borderColor;\n\n        this.config.width = this.componentConfiguration.popupProps.width;\n        this.config.height =\n            this.buttonsCount *\n                (this.componentConfiguration.autoplayButtonProps.buttonHeight +\n                    this.componentConfiguration.autoplayButtonProps.buttonOffsetY) +\n            this.componentConfiguration.autoplayButtonProps.additionalButtonOffsetY;\n        this.config.title = Core.translator.translate('Autoplay').toUpperCase();\n        this.config.titleStyle = this.componentConfiguration.popupProps.titleStyle;\n        this.backgroundWindow = new TitledWindow(this.config);\n        this.backgroundWindow.interactive = true;\n        this.addChild(this.backgroundWindow);\n    }\n\n    protected createOverlayBackground(): void {\n        this.overlay = new Graphics();\n        this.overlay\n            .beginFill(0x000000, 0.75)\n            .drawRect(0, 0, Core.ORIENTATION.value.width, Core.ORIENTATION.value.height)\n            .endFill();\n        this.addChildAt(this.overlay, 0);\n        this.overlay.interactive = true;\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/default/views/AutoplayPopupViewDefault.ts:260:9\",(this.overlay),\"pointerup\"]), fromEvent(this.overlay, 'pointerup')).pipe(takeUntil(this.DESTROY)).subscribe(this.close.bind(this, true));\n    }\n\n    protected createAutoplayBets(): void {\n        this.autoplayButtonsTextures = [\n            Core.assets.getAsset(this.componentConfiguration.autoplayButtonProps.buttonTextures[ButtonStates.Normal])\n                .texture,\n            Core.assets.getAsset(this.componentConfiguration.autoplayButtonProps.buttonTextures[ButtonStates.Pressed])\n                .texture,\n            Core.assets.getAsset(this.componentConfiguration.autoplayButtonProps.buttonTextures[ButtonStates.Normal])\n                .texture,\n            Core.assets.getAsset(this.componentConfiguration.autoplayButtonProps.buttonTextures[ButtonStates.Disabled])\n                .texture,\n        ];\n\n        let autoButton: Button = new Button();\n        this.buttonsCount = 0;\n        this.settings.autoplayRestrictions.autoPlays.forEach((autoBet) => {\n            if (autoBet !== 0) {\n                autoButton = this.createAutoplayBet(autoBet, this.componentConfiguration.autoplayButtonProps.textStyle);\n                autoButton.y =\n                    (this.componentConfiguration.autoplayButtonProps.buttonHeight +\n                        this.componentConfiguration.autoplayButtonProps.buttonOffsetY) *\n                    this.buttonsCount;\n                this.buttonsContainer.addChild(autoButton);\n                this.buttonsCount++;\n            }\n        });\n        if (this.buttonsCount === 0) {\n            return;\n        }\n        if (\n            Core.isDesktopMode &&\n            this.settings.autoplayRestrictions.extend &&\n            this.componentConfiguration.autoplayButtonProps.autoplayMenuShow &&\n            this.settings.autoplayRestrictions.mandatory.length === 0\n        ) {\n            const autoMenuButton: Button = this.createMenuButton(\n                this.componentConfiguration.autoplayButtonProps.textStyle,\n            );\n            autoMenuButton.y =\n                (this.componentConfiguration.autoplayButtonProps.buttonHeight +\n                    this.componentConfiguration.autoplayButtonProps.buttonOffsetY) *\n                this.buttonsCount;\n            this.buttonsContainer.addChild(autoMenuButton);\n            this.buttonsCount++;\n        }\n    }\n\n    protected createMenuButton(style: TextStyle): Button {\n        const menuButton: Button = new Button(this.autoplayButtonsTextures);\n        menuButton.interactive = true;\n        menuButton.CLICK.pipe(takeUntil(this.DESTROY)).subscribe(this.onGoToMenuPressed.bind(this));\n\n        const text: Text = new Text('...', style);\n        text.x = (menuButton.width - text.width) / 2;\n        text.y = (menuButton.height - text.height) / 2;\n        menuButton.addChild(text);\n\n        return menuButton;\n    }\n\n    protected createAutoplayBet(bet: number, style: TextStyle): Button {\n        const autoButton: Button = new Button(this.autoplayButtonsTextures);\n        autoButton.interactive = true;\n        autoButton.CLICK.pipe(takeUntil(this.DESTROY)).subscribe(this.onPressed.bind(this, bet));\n        if (bet === -1) {\n            const infinitySprite: Sprite = new Sprite();\n            infinitySprite.texture = Core.assets.getAsset(\n                this.componentConfiguration.autoplayButtonProps.infinityTexture,\n            ).texture;\n            infinitySprite.x = (autoButton.width - infinitySprite.width) / 2;\n            infinitySprite.y =\n                (this.componentConfiguration.autoplayButtonProps.buttonHeight - infinitySprite.height) / 2;\n            autoButton.addChild(infinitySprite);\n        } else {\n            const text: Text = new Text(bet.toString(), style);\n            text.x = (autoButton.width - text.width) / 2; // + confing.buttonProps.textOffsetX\n            text.y = (this.componentConfiguration.autoplayButtonProps.buttonHeight - text.height) / 2; // + confing.buttonProps.textOffsetY\n            autoButton.addChild(text);\n        }\n        return autoButton;\n    }\n\n    private onPressed(bet: number): void {\n        if (this.settings.settings.settings.jurisdiction?.autoplayRestrictions?.confirmationModal) {\n            const modalData = this.rootStore.getModalData(bet);\n            const messData = {} as IErrorData;\n\n            (messData.code = Core.translator\n                .translate('AUTOPLAY.MODAL.MESSAGE')\n                .replace('<<totalAmount>>', modalData.totalBetAmount.toString().replace(/\\s+/g, '\\u00A0'))\n\n                .replace('<<numberOfSpins>>', bet.toString())\n                .replace('<<betAmount>>', modalData.betAmount)),\n                (messData.btnText = Core.translator.translate('AUTOPLAY.MODAL.CANCEL_BUTTON')),\n                (messData.type = ErrorTypes.CONFIRMATION),\n                (messData.hasConfirmButton = true),\n                (messData.confirmButtonText = Core.translator.translate('AUTOPLAY.MODAL.CONFIRM_BUTTON')),\n                (messData.callback = this.confirmStartAutoplay.bind(this, bet)),\n                Core.SHOW_ERROR.next(messData);\n            return;\n        }\n        this.confirmStartAutoplay(bet);\n    }\n\n    private confirmStartAutoplay(numberOfAutoplaySpins: number): void {\n        this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.next(numberOfAutoplaySpins);\n        this.rootStore.subjects.CLOSE_AUTOPLAY_POPUP.next();\n        this.rootStore.subjects.START_AUTOPLAY.next(numberOfAutoplaySpins);\n    }\n\n    private killAllAnimations(): void {\n        if (this.animationTween) {\n            this.animationTween.kill();\n            this.animationTween = null;\n        }\n    }\n\n    private onGoToMenuPressed(): void {\n        this.rootStore.uiStore.SELECTED_SETTINGS_TAB.next(SettingsTab.AUTOPLAY);\n        this.rootStore.subjects.OPEN_SETTINGS_POPUP.next();\n    }\n}\n","const enum AutoplayButtonStatesExtended {\n    Normal,\n    Over,\n    Selected,\n    Disabled,\n}\n\nexport default AutoplayButtonStatesExtended;\n","import { Texture } from 'pixi.js';\n\nexport default class AutoplayButtonTexturesExtended {\n    constructor(\n        public normalTexture: Texture,\n        public selectedTexture: Texture,\n        public disabledTexture: Texture,\n        public overTexture: Texture,\n    ) {\n        //\n    }\n\n    public destroy() {\n        this.normalTexture.destroy();\n        // @ts-ignore\n        this.normalTexture = null;\n\n        this.selectedTexture.destroy();\n        // @ts-ignore\n        this.selectedTexture = null;\n\n        if (this.disabledTexture) {\n            this.disabledTexture.destroy();\n            // @ts-ignore\n            this.disabledTexture = null;\n        }\n\n        if (this.overTexture) {\n            this.overTexture.destroy();\n            // @ts-ignore\n            this.overTexture = null;\n        }\n    }\n}\n","import Core from '@egt/core';\nimport { ButtonShapes, ViewContainer } from '@egt/ui-lib';\nimport { Sprite, Text, TextStyle } from 'pixi.js';\nimport { Subject, fromEvent } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport AutoplayButtonStatesExtended from './AutoplayButtonStatesExtended';\nimport AutoplayButtonTexturesExtended from './AutoplayButtonTexturesExtended';\n\nexport default class AutoplayStartButtonExtended extends ViewContainer {\n    public readonly CLICK = new Subject();\n\n    protected factor: number;\n    protected buttonBackground: Sprite;\n\n    protected _state: AutoplayButtonStatesExtended = AutoplayButtonStatesExtended.Normal;\n    protected _shape: ButtonShapes = ButtonShapes.Rectangle;\n\n    protected textures: AutoplayButtonTexturesExtended;\n    protected btnText: Text;\n    protected btnTextStyleNormal: TextStyle;\n    protected btnTextStyleDisabled: TextStyle;\n    protected infinitySign: Sprite;\n    protected label: string;\n    protected boundsBtnTextOffset: number = 10;\n\n    constructor(\n        label: string,\n        textures: AutoplayButtonTexturesExtended,\n        btnTextStyleNormal: TextStyle,\n        btnTextStyleDisabled?: TextStyle,\n    ) {\n        super();\n        this.interactive = true;\n        this.textures = textures;\n        this.btnTextStyleNormal = btnTextStyleNormal;\n        this.btnTextStyleDisabled = btnTextStyleDisabled ? btnTextStyleDisabled : btnTextStyleNormal;\n        this.label = label;\n\n        this.createBtnBackground();\n        this.addBtnText();\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/extended/buttons/AutoplaySartButtonExtended.ts:42:9\",(this.buttonBackground),\"pointerdown\"]), fromEvent(this.buttonBackground, 'pointerdown'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerDown.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/extended/buttons/AutoplaySartButtonExtended.ts:46:9\",(this.buttonBackground),\"pointerup\"]), fromEvent(this.buttonBackground, 'pointerup'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerUp.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/extended/buttons/AutoplaySartButtonExtended.ts:50:9\",(this.buttonBackground),\"pointerupoutside\"]), fromEvent(this.buttonBackground, 'pointerupoutside'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerOut.bind(this));\n\n        fromEvent(this.buttonBackground, 'pointerenter')\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerOver.bind(this));\n\n        fromEvent(this.buttonBackground, 'pointerleave')\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerOut.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/extended/buttons/AutoplaySartButtonExtended.ts:62:9\",(this.buttonBackground),\"pointertap\"]), fromEvent(this.buttonBackground, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerTap.bind(this));\n    }\n\n    public destroy(): void {\n        this.removeChildren();\n\n        this.buttonBackground.destroy({ children: true });\n        this.textures.destroy();\n        // @ts-ignore\n        this.textures = null;\n\n        this.btnText.destroy();\n        // @ts-ignore\n        this.btnText = null;\n\n        super.destroy();\n    }\n\n    public fakeClick(): void {\n        this.buttonBackground.emit('pointertap');\n    }\n\n    public onPointerDown(): void {\n        if (\n            this.state === AutoplayButtonStatesExtended.Disabled ||\n            this.state === AutoplayButtonStatesExtended.Selected\n        ) {\n            return;\n        }\n        this.state = AutoplayButtonStatesExtended.Over;\n    }\n\n    /**\n     *\n     */\n    public onPointerOut(): void {\n        if (\n            this.state === AutoplayButtonStatesExtended.Disabled ||\n            this.state === AutoplayButtonStatesExtended.Selected\n        ) {\n            return;\n        }\n        this.state = AutoplayButtonStatesExtended.Normal;\n    }\n\n    public setDisabled(): void {\n        this.state = AutoplayButtonStatesExtended.Disabled;\n        this.buttonBackground.texture = this.textures.disabledTexture;\n        this.btnText.style = this.btnTextStyleDisabled;\n        this.scaleTextToFit();\n    }\n\n    public setNormal(): void {\n        this.state = AutoplayButtonStatesExtended.Normal;\n        this.buttonBackground.texture = this.textures.normalTexture;\n        this.btnText.style = this.btnTextStyleNormal;\n    }\n\n    protected addBtnText(): void {\n        this.btnText = new Text(this.label, this.btnTextStyleNormal);\n        this.btnText.resolution = 2;\n        this.btnText.anchor.set(0.5);\n        this.btnText.x = this.width / 2;\n        this.btnText.y = this.height / 2;\n        this.scaleTextToFit();\n        this.addChild(this.btnText);\n    }\n\n    protected scaleTextToFit(): void {\n        if (!this.btnText || !this.buttonBackground) return;\n\n        const bounds = this.buttonBackground.width - this.boundsBtnTextOffset;\n\n        this.btnText.scale.set(1);\n\n        if (this.btnText.width > bounds) {\n            this.btnText.scale.set(bounds / this.btnText.width);\n        }\n\n        this.btnText.x = this.width / 2;\n        this.btnText.y = this.height / 2;\n    }\n\n    protected createBtnBackground(): void {\n        this.buttonBackground = new Sprite(this.textures.normalTexture);\n        this.buttonBackground.interactive = true;\n        this.addChild(this.buttonBackground);\n    }\n\n    protected onPointerUp(): void {\n        if (\n            this.state === AutoplayButtonStatesExtended.Disabled ||\n            this.state === AutoplayButtonStatesExtended.Selected\n        ) {\n            return;\n        }\n        this.state = AutoplayButtonStatesExtended.Over;\n    }\n\n    protected onPointerOver(): void {\n        if (\n            this.state === AutoplayButtonStatesExtended.Disabled ||\n            this.state === AutoplayButtonStatesExtended.Selected\n        ) {\n            return;\n        }\n        this.state = AutoplayButtonStatesExtended.Over;\n    }\n\n    protected onPointerTap(): void {\n        if (\n            this.state === AutoplayButtonStatesExtended.Disabled ||\n            this.state === AutoplayButtonStatesExtended.Selected\n        ) {\n            return;\n        }\n        this.CLICK.next(this);\n    }\n\n    protected getTexture(): AutoplayButtonTexturesExtended {\n        return this.textures;\n    }\n\n    protected addInfinitySign(): void {\n        this.infinitySign = new Sprite(Core.assets.getAsset('svgInfinity').texture);\n        this.infinitySign.anchor.set(0.5);\n        this.infinitySign.x = this.width / 2;\n        this.infinitySign.y = this.height / 2;\n        this.addChild(this.infinitySign);\n    }\n\n    get state(): AutoplayButtonStatesExtended {\n        return this._state;\n    }\n    set state(state: AutoplayButtonStatesExtended) {\n        this._state = state;\n        this.buttonBackground.cursor = 'pointer';\n\n        switch (state) {\n            case AutoplayButtonStatesExtended.Normal:\n                this.buttonBackground.texture = this.textures.normalTexture;\n                break;\n            case AutoplayButtonStatesExtended.Over:\n                if (this.textures.overTexture) {\n                    this.buttonBackground.texture = this.textures.overTexture;\n                } else {\n                    this.buttonBackground.texture = this.textures.normalTexture;\n                }\n                break;\n            case AutoplayButtonStatesExtended.Selected:\n                this.buttonBackground.texture = this.textures.selectedTexture;\n                break;\n            case AutoplayButtonStatesExtended.Disabled:\n                this.buttonBackground.buttonMode = false;\n                this.buttonBackground.cursor = 'default';\n                if (this.textures.disabledTexture) {\n                    this.buttonBackground.texture = this.textures.disabledTexture;\n                } else {\n                    this.buttonBackground.texture = this.textures.normalTexture;\n                }\n                break;\n        }\n    }\n}\n","import Core from '@egt/core';\nimport { ButtonShapes, ViewContainer } from '@egt/ui-lib';\nimport { Sprite, Text, TextStyle } from 'pixi.js';\nimport { Subject, fromEvent } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport AutoplayButtonStatesExtended from './AutoplayButtonStatesExtended';\nimport AutoplayButtonTexturesExtended from './AutoplayButtonTexturesExtended';\n\nexport default class AutoplaySettingButtonExtended extends ViewContainer {\n    public readonly CLICK = new Subject();\n\n    public numberOfAutoPlays: number;\n    protected factor: number;\n    protected buttonBackground: Sprite;\n\n    protected _state: AutoplayButtonStatesExtended = AutoplayButtonStatesExtended.Normal;\n    protected _shape: ButtonShapes = ButtonShapes.Rectangle;\n\n    protected textures: AutoplayButtonTexturesExtended;\n    protected btnText: Text;\n    protected btnTextStyleNormal: TextStyle;\n    protected btnTextStyleSelected: TextStyle;\n    protected infinitySign: Sprite;\n\n    constructor(\n        numberOfAutoPlays: number,\n        textures: AutoplayButtonTexturesExtended,\n        btnTextStyleNormal: TextStyle,\n        btnTextStyleSelected: TextStyle,\n        width?: number,\n        height?: number,\n    ) {\n        super();\n        this.interactive = true;\n        this.numberOfAutoPlays = numberOfAutoPlays;\n        this.textures = textures;\n        this.btnTextStyleNormal = btnTextStyleNormal;\n        this.btnTextStyleSelected = btnTextStyleSelected;\n\n        this.createBtnBackground(width, height);\n        if (numberOfAutoPlays > 0) {\n            this.addBtnText();\n        } else {\n            this.addInfinitySign();\n        }\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/extended/buttons/AutoplaySettingButtonExtended.ts:47:9\",(this.buttonBackground),\"pointerdown\"]), fromEvent(this.buttonBackground, 'pointerdown'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerDown.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/extended/buttons/AutoplaySettingButtonExtended.ts:51:9\",(this.buttonBackground),\"pointerup\"]), fromEvent(this.buttonBackground, 'pointerup'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerUp.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/extended/buttons/AutoplaySettingButtonExtended.ts:55:9\",(this.buttonBackground),\"pointerupoutside\"]), fromEvent(this.buttonBackground, 'pointerupoutside'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerOut.bind(this));\n\n        fromEvent(this.buttonBackground, 'pointerenter')\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerOver.bind(this));\n\n        fromEvent(this.buttonBackground, 'pointerleave')\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerOut.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/extended/buttons/AutoplaySettingButtonExtended.ts:67:9\",(this.buttonBackground),\"pointertap\"]), fromEvent(this.buttonBackground, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerTap.bind(this));\n    }\n\n    public destroy(): void {\n        this.removeChildren();\n\n        this.buttonBackground.destroy({ children: true });\n        this.textures.destroy();\n        // @ts-ignore\n        this.textures = null;\n\n        if (this.btnText) {\n            this.btnText.destroy();\n            // @ts-ignore\n            this.btnText = null;\n        }\n\n        super.destroy();\n    }\n\n    public fakeClick(): void {\n        this.buttonBackground.emit('pointertap');\n    }\n\n    public onPointerDown(): void {\n        if (\n            this.state === AutoplayButtonStatesExtended.Disabled ||\n            this.state === AutoplayButtonStatesExtended.Selected\n        ) {\n            return;\n        }\n        this.state = AutoplayButtonStatesExtended.Over;\n    }\n\n    /**\n     *\n     */\n    public onPointerOut(): void {\n        if (\n            this.state === AutoplayButtonStatesExtended.Disabled ||\n            this.state === AutoplayButtonStatesExtended.Selected\n        ) {\n            return;\n        }\n        this.state = AutoplayButtonStatesExtended.Normal;\n    }\n\n    public setSelected(): void {\n        this.state = AutoplayButtonStatesExtended.Selected;\n        this.buttonBackground.texture = this.textures.selectedTexture;\n        if (this.btnText) {\n            this.btnText.style = this.btnTextStyleSelected;\n        }\n        if (this.infinitySign) {\n            this.infinitySign.texture = Core.assets.getAsset('infinityIconSelected').texture;\n        }\n    }\n\n    public setNormal(): void {\n        this.state = AutoplayButtonStatesExtended.Normal;\n        this.buttonBackground.texture = this.textures.normalTexture;\n        if (this.btnText) {\n            this.btnText.style = this.btnTextStyleNormal;\n        }\n        if (this.infinitySign) {\n            this.infinitySign.texture = Core.assets.getAsset('infinityIcon').texture;\n        }\n    }\n\n    protected addBtnText(): void {\n        this.btnText = new Text(this.numberOfAutoPlays, this.btnTextStyleNormal);\n        this.btnText.resolution = 2;\n        this.btnText.anchor.set(0.5);\n        this.btnText.x = this.width / 2;\n        this.btnText.y = this.height / 2;\n        this.addChild(this.btnText);\n    }\n\n    protected createBtnBackground(width?: number, height?: number): void {\n        this.buttonBackground = new Sprite(this.textures.normalTexture);\n        this.buttonBackground.interactive = true;\n        if (width) {\n            this.buttonBackground.width = width;\n        }\n        if (height) {\n            this.buttonBackground.height = height;\n        }\n        this.addChild(this.buttonBackground);\n    }\n\n    protected onPointerUp(): void {\n        if (\n            this.state === AutoplayButtonStatesExtended.Disabled ||\n            this.state === AutoplayButtonStatesExtended.Selected\n        ) {\n            return;\n        }\n        this.state = AutoplayButtonStatesExtended.Normal;\n    }\n\n    protected onPointerOver(): void {\n        if (\n            this.state === AutoplayButtonStatesExtended.Disabled ||\n            this.state === AutoplayButtonStatesExtended.Selected\n        ) {\n            return;\n        }\n        this.state = AutoplayButtonStatesExtended.Over;\n    }\n\n    protected onPointerTap(): void {\n        if (\n            this.state === AutoplayButtonStatesExtended.Disabled ||\n            this.state === AutoplayButtonStatesExtended.Selected\n        ) {\n            return;\n        }\n        this.CLICK.next(this);\n    }\n\n    protected getTexture(): AutoplayButtonTexturesExtended {\n        return this.textures;\n    }\n\n    protected addInfinitySign(): void {\n        this.infinitySign = new Sprite(Core.assets.getAsset('infinityIcon').texture);\n        this.infinitySign.anchor.set(0.5);\n        this.infinitySign.x = this.width / 2;\n        this.infinitySign.y = this.height / 2;\n        this.addChild(this.infinitySign);\n    }\n\n    get state(): AutoplayButtonStatesExtended {\n        return this._state;\n    }\n    set state(state: AutoplayButtonStatesExtended) {\n        this._state = state;\n        this.cursor = 'normal';\n        this.buttonBackground.cursor = 'pointer';\n        switch (state) {\n            case AutoplayButtonStatesExtended.Normal:\n                this.buttonBackground.texture = this.textures.normalTexture;\n                break;\n            case AutoplayButtonStatesExtended.Over:\n                this.cursor = 'pointer';\n                if (this.textures.overTexture) {\n                    this.buttonBackground.texture = this.textures.overTexture;\n                } else {\n                    this.buttonBackground.texture = this.textures.normalTexture;\n                }\n                break;\n            case AutoplayButtonStatesExtended.Selected:\n                this.buttonBackground.texture = this.textures.selectedTexture;\n                break;\n            case AutoplayButtonStatesExtended.Disabled:\n                this.buttonBackground.buttonMode = false;\n                this.buttonBackground.cursor = 'default';\n                if (this.textures.disabledTexture) {\n                    this.buttonBackground.texture = this.textures.disabledTexture;\n                } else {\n                    this.buttonBackground.texture = this.textures.normalTexture;\n                }\n                break;\n        }\n    }\n}\n","import {\n    AssetPriority,\n    AssetsCollection,\n    BaseComponentConfiguration,\n    DefaultAssets,\n    DefaultValue,\n    DynamicPositionObject,\n} from '@egt/core';\nimport { TextStyle } from 'pixi.js';\nimport {\n    IAutoPlayArrowPositionsExtended,\n    IAutoPlayPositionsExtended,\n    IAutoPlaySelectedBtnPositionsExtended,\n    IAutoplayBtnTextExtended,\n    IAutoplayPopUpTextExtended,\n    IAutoplayPopUpTitleTextExtended,\n    IAutoplayPositionObjectExtended,\n    IBalanceAndBetTextExtended,\n    IAutoplayPopupComponentConfigurationExtended,\n    IMainContainerPositionExtended,\n    ISliderPositionObjectExtended,\n} from '../interfaces/InterfacesExtended';\n\nexport default class AutoplayPopupComponentConfigurationExtended extends BaseComponentConfiguration {}\nexport function AutoplayPopupConfigFactoryExtended(): any {\n    class AutoplayPopupComponentConfigurationExtendedInternalClass\n        extends AutoplayPopupComponentConfigurationExtended\n        implements IAutoplayPopupComponentConfigurationExtended\n    {\n        public buttonsToHide = ['betButtons', 'autoPlayButton'];\n\n        public mainViewComponentsToHide = ['balanceContainer', 'winContainer'];\n\n        @DefaultAssets([\n            {\n                id: 'autoplayResources',\n                url: '../assets/components/slot/autoplay-popup/common/autoplayResources.json',\n                priority: AssetPriority.HIGHEST,\n                type: 'texture',\n            },\n            {\n                id: 'svgAutoplaySelected',\n                url: '../assets/components/slot/autoplay-popup/extended/ui-svg/autoplaySelected.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 132, height: 132 },\n                    desktop: { width: 99, height: 99 },\n                },\n            },\n            {\n                id: 'svgSliderDotActive',\n                url: '../assets/components/slot/autoplay-popup/common/ui-svg/sliderDotActive.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 74, height: 74 },\n                    desktop: { width: 74, height: 74 },\n                },\n            },\n            {\n                id: 'svgSliderDotInactive',\n                url: '../assets/components/slot/autoplay-popup/common/ui-svg/sliderDotInactive.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 74, height: 74 },\n                    desktop: { width: 74, height: 74 },\n                },\n            },\n            {\n                id: 'svgSliderDotPressed',\n                url: '../assets/components/slot/autoplay-popup/common/ui-svg/sliderDotPressed.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 74, height: 74 },\n                    desktop: { width: 74, height: 74 },\n                },\n            },\n            {\n                id: 'svgSliderDotHover',\n                url: '../assets/components/slot/autoplay-popup/common/ui-svg/sliderDotHover.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 74, height: 74 },\n                    desktop: { width: 74, height: 74 },\n                },\n            },\n            {\n                id: 'svgAutoplayPopUpHover',\n                url: '../assets/components/slot/autoplay-popup/extended/ui-svg/autoplayPopUpHover.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 104, height: 74 },\n                    desktop: { width: 104, height: 74 },\n                },\n            },\n            {\n                id: 'svgAutoplayPopUpNormal',\n                url: '../assets/components/slot/autoplay-popup/extended/ui-svg/autoplayPopUpNormal.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 104, height: 74 },\n                    desktop: { width: 104, height: 74 },\n                },\n            },\n            {\n                id: 'svgAutoplayPopUpSelected',\n                url: '../assets/components/slot/autoplay-popup/extended/ui-svg/autoplayPopUpSelected.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 104, height: 74 },\n                    desktop: { width: 104, height: 74 },\n                },\n            },\n            {\n                id: 'svgAutoplayStartDisabled',\n                url: '../assets/components/slot/autoplay-popup/extended/ui-svg/autoplayStartDisabled.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 222, height: 78 },\n                    desktop: { width: 222, height: 78 },\n                },\n            },\n            {\n                id: 'svgAutoplayStartHover',\n                url: '../assets/components/slot/autoplay-popup/extended/ui-svg/autoplayStartHover.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 222, height: 78 },\n                    desktop: { width: 222, height: 78 },\n                },\n            },\n            {\n                id: 'svgAutoplayStartNormal',\n                url: '../assets/components/slot/autoplay-popup/extended/ui-svg/autoplayStartNormal.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 222, height: 78 },\n                    desktop: { width: 222, height: 78 },\n                },\n            },\n            {\n                id: 'infinityIcon',\n                url: '../assets/components/slot/autoplay-popup/common/ui-svg/infinityIcon.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 46, height: 45 },\n                    desktop: { width: 46, height: 45 },\n                },\n            },\n            {\n                id: 'infinityIconSelected',\n                url: '../assets/components/slot/autoplay-popup/common/ui-svg/infinityIconSelected.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 46, height: 45 },\n                    desktop: { width: 46, height: 45 },\n                },\n            },\n        ])\n        public assets: AssetsCollection;\n\n        @DefaultValue<IMainContainerPositionExtended>({\n            defaults: {\n                x: 0,\n                y: 0,\n                leftHandX: -276,\n            },\n        })\n        public mainContainerPosition: DynamicPositionObject<IMainContainerPositionExtended> &\n            IMainContainerPositionExtended;\n\n        @DefaultValue<IAutoplayPopUpTitleTextExtended>({\n            defaults: {\n                yOffset: 30,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                    fontSize: 36,\n                    fill: '#FFFFFF',\n                    align: 'center',\n                }),\n            },\n        })\n        public popUpTitle: DynamicPositionObject<IAutoplayPopUpTitleTextExtended> & IAutoplayPopUpTitleTextExtended;\n\n        @DefaultValue<IBalanceAndBetTextExtended>({\n            defaults: {\n                x: 466,\n                y: 732,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFD200',\n                    fontSize: 24,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                valueStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 36,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                currencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 22,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n            },\n            portrait: {\n                x: 30,\n                y: 916,\n            },\n        })\n        public balanceText: DynamicPositionObject<IBalanceAndBetTextExtended> & IBalanceAndBetTextExtended;\n\n        @DefaultValue<IBalanceAndBetTextExtended>({\n            defaults: {\n                x: 1170,\n                y: 732,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFD200',\n                    fontSize: 24,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                valueStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 36,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                currencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 22,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n            },\n            portrait: {\n                x: 734,\n                y: 916,\n            },\n        })\n        public betText: DynamicPositionObject<IBalanceAndBetTextExtended> & IBalanceAndBetTextExtended;\n\n        @DefaultValue<IAutoplayPopUpTextExtended>({\n            defaults: {\n                x: 818,\n                y: 88,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                    fontSize: 28,\n                    lineHeight: 30,\n                    fill: '#FFFFFF',\n                    align: 'center',\n                }),\n            },\n            portrait: {\n                x: 382,\n                y: 273,\n            },\n        })\n        public stopOnTitle: DynamicPositionObject<IAutoplayPopUpTextExtended> & IAutoplayPopUpTextExtended;\n\n        @DefaultValue<IAutoplayPopUpTextExtended>({\n            defaults: {\n                x: 818,\n                y: 456,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                    fontSize: 28,\n                    fill: '#FFFFFF',\n                    align: 'center',\n                }),\n            },\n            portrait: {\n                x: 382,\n                y: 643,\n            },\n        })\n        public autoplayTitle: DynamicPositionObject<IAutoplayPopUpTextExtended> & IAutoplayPopUpTextExtended;\n\n        @DefaultValue<IAutoplayPopUpTextExtended>({\n            defaults: {\n                x: -25,\n                y: -28,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Book, RobotoCondensed-Bold, Arial',\n                    fontSize: 30,\n                    fill: '#FFFFFF',\n                    align: 'left',\n                }),\n            },\n        })\n        public slidersTitleText: DynamicPositionObject<IAutoplayPopUpTextExtended> & IAutoplayPopUpTextExtended;\n\n        @DefaultValue<IAutoplayPopUpTextExtended>({\n            defaults: {\n                x: 587,\n                y: -28,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                    fontSize: 34,\n                    fill: '#FFD200',\n                    align: 'right',\n                }),\n            },\n        })\n        public slidersValueText: DynamicPositionObject<IAutoplayPopUpTextExtended> & IAutoplayPopUpTextExtended;\n\n        @DefaultValue<IAutoplayPopUpTextExtended>({\n            defaults: {\n                x: 591,\n                y: -32,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                    fontSize: 17,\n                    fill: '#FFD200',\n                    align: 'right',\n                }),\n            },\n        })\n        public slidersCurrencyText: DynamicPositionObject<IAutoplayPopUpTextExtended> & IAutoplayPopUpTextExtended;\n\n        @DefaultValue<IAutoplayPopUpTextExtended>({\n            defaults: {\n                x: 591,\n                y: -28,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                    fontSize: 26,\n                    lineHeight: 30,\n                    fill: '#FF0000',\n                    align: 'right',\n                }),\n            },\n        })\n        public slidersValueMandatoryText: DynamicPositionObject<IAutoplayPopUpTextExtended> &\n            IAutoplayPopUpTextExtended;\n\n        @DefaultValue<IAutoplayPopUpTextExtended>({\n            defaults: {\n                x: 591,\n                y: -28,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Book, RobotoCondensed-Bold, Arial',\n                    fontSize: 30,\n                    fill: '#909090',\n                    align: 'right',\n                }),\n            },\n        })\n        public slidersValueNoLimit: DynamicPositionObject<IAutoplayPopUpTextExtended> & IAutoplayPopUpTextExtended;\n\n        @DefaultValue<IAutoplayBtnTextExtended>({\n            defaults: {\n                xOffset: 6,\n                width: 108,\n                height: 78,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    fontSize: 42,\n                    fill: '#C6C5C5',\n                    align: 'center',\n                }),\n                selectedTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    fontSize: 42,\n                    fill: '#FFFFFF',\n                    align: 'center',\n                }),\n            },\n        })\n        public buttonValueText: DynamicPositionObject<IAutoplayBtnTextExtended> & IAutoplayBtnTextExtended;\n\n        @DefaultValue<IAutoPlayPositionsExtended>({\n            defaults: {\n                x: 536,\n                y: 493,\n            },\n            portrait: {\n                y: 680,\n            },\n        })\n        public buttonsContainerPositions: DynamicPositionObject<IAutoPlayPositionsExtended> &\n            IAutoPlayPositionsExtended;\n\n        @DefaultValue<IAutoplayPositionObjectExtended>({\n            defaults: {\n                width: 744,\n                height: 752,\n                x: 446,\n                y: 2,\n            },\n            portrait: {\n                x: 10,\n                y: 187,\n            },\n        })\n        public popUpGraphicsContainer: DynamicPositionObject<IAutoplayPositionObjectExtended> &\n            IAutoplayPositionObjectExtended;\n\n        @DefaultValue<IAutoplayPositionObjectExtended>({\n            defaults: {\n                width: 704,\n                height: 360,\n                x: 466,\n                y: 78,\n            },\n            portrait: {\n                x: 30,\n                y: 263,\n            },\n        })\n        public popUpFirstSectionPosition: DynamicPositionObject<IAutoplayPositionObjectExtended> &\n            IAutoplayPositionObjectExtended;\n\n        @DefaultValue<IAutoplayPositionObjectExtended>({\n            defaults: {\n                width: 704,\n                height: 139,\n                x: 466,\n                y: 446,\n            },\n            portrait: {\n                x: 30,\n                y: 633,\n            },\n        })\n        public popUpSecondSectionPosition: DynamicPositionObject<IAutoplayPositionObjectExtended> &\n            IAutoplayPositionObjectExtended;\n\n        @DefaultValue<ISliderPositionObjectExtended>({\n            defaults: {\n                x: 532,\n                y: 197,\n                width: 565, // (616 - 51)\n                height: 6,\n                selectedFill: 0x6aaf08,\n                notSelectedFill: 0x616161,\n            },\n            portrait: {\n                x: 99,\n                y: 386,\n            },\n        })\n        public balanceSliderLessContainer: DynamicPositionObject<ISliderPositionObjectExtended> &\n            ISliderPositionObjectExtended;\n\n        @DefaultValue<ISliderPositionObjectExtended>({\n            defaults: {\n                x: 532,\n                y: 298,\n                width: 565,\n                height: 6,\n                selectedFill: 0x6aaf08,\n                notSelectedFill: 0x616161,\n            },\n            portrait: {\n                x: 99,\n                y: 487,\n            },\n        })\n        public balanceSliderMoreContainer: DynamicPositionObject<ISliderPositionObjectExtended> &\n            ISliderPositionObjectExtended;\n\n        @DefaultValue<ISliderPositionObjectExtended>({\n            defaults: {\n                x: 532,\n                y: 399,\n                width: 565,\n                height: 6,\n                selectedFill: 0x6aaf08,\n                notSelectedFill: 0x616161,\n            },\n            portrait: {\n                x: 99,\n                y: 588,\n            },\n        })\n        public winSliderContainer: DynamicPositionObject<ISliderPositionObjectExtended> & ISliderPositionObjectExtended;\n\n        @DefaultValue<IAutoplayPopUpTextExtended>({\n            defaults: {\n                x: 0,\n                y: -20,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                    fontSize: 36,\n                    fill: '#FFFFFF',\n                    align: 'center',\n                }),\n            },\n        })\n        public startAutoplayNormalText: DynamicPositionObject<IAutoplayPopUpTextExtended> & IAutoplayPopUpTextExtended;\n\n        @DefaultValue<IAutoplayPopUpTextExtended>({\n            defaults: {\n                x: 0,\n                y: -20,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                    fontSize: 36,\n                    fill: '#818c86',\n                    align: 'center',\n                }),\n            },\n        })\n        public startAutoplayDisabledText: DynamicPositionObject<IAutoplayPopUpTextExtended> &\n            IAutoplayPopUpTextExtended;\n\n        @DefaultValue<IAutoPlayPositionsExtended>({\n            defaults: {\n                x: 707,\n                y: 593,\n            },\n            portrait: {\n                x: 271,\n                y: 778,\n            },\n        })\n        public startAutoplayBtn: DynamicPositionObject<IAutoPlayPositionsExtended> & IAutoPlayPositionsExtended;\n\n        @DefaultValue<IAutoPlayArrowPositionsExtended>({\n            defaults: {\n                x: 1186,\n                y: 127,\n                angle: 270,\n                leftHandX: 174,\n                leftHandY: 76,\n                leftHandAngle: 90,\n            },\n            portrait: {\n                x: 162,\n                y: 935,\n                angle: 0,\n            },\n            desktop: {\n                y: 228,\n            },\n        })\n        public arrowPosition: DynamicPositionObject<IAutoPlayArrowPositionsExtended> & IAutoPlayArrowPositionsExtended;\n\n        @DefaultValue<IAutoPlaySelectedBtnPositionsExtended>({\n            defaults: {\n                x: 1285,\n                y: 101,\n                leftHandX: 75,\n                scale: 1,\n            },\n            portrait: {\n                x: 187,\n                y: 1061,\n            },\n            desktop: {\n                x: 1272.5,\n                y: 198.5,\n            },\n        })\n        selectedButton: DynamicPositionObject<IAutoPlaySelectedBtnPositionsExtended> &\n            IAutoPlaySelectedBtnPositionsExtended;\n    }\n    return AutoplayPopupComponentConfigurationExtendedInternalClass;\n}\n","import Core, { BaseController, ErrorTypes, IErrorData } from '@egt/core';\nimport { FeatureController, InitialSettings, RootStore } from '@egt/slot';\nimport { fromEvent, merge } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport AutoplaySettingButtonExtended from '../buttons/AutoplaySettingButtonExtended';\nimport { IAutoplayPopupComponentConfigurationExtended } from '../interfaces/InterfacesExtended';\nimport AutoplayPopupViewExtended from '../views/AutoplayPopupViewExtended';\n\n@injectable()\nexport default class AutoplayPopupControllerExtended extends BaseController {\n    private numberOfAutoPlays: number;\n\n    constructor(\n        @inject('AutoplayPopupView') protected extendedAutoplayPopup: AutoplayPopupViewExtended,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('AutoplayPopupComponentConfiguration')\n        protected componentConfiguration: IAutoplayPopupComponentConfigurationExtended,\n        @inject('FeatureController') protected featureController: FeatureController,\n    ) {\n        super(extendedAutoplayPopup);\n    }\n\n    public init(): void {\n        if (!this.settings.autoplay) {\n            return;\n        }\n        this.attachEventListeners();\n    }\n\n    public attachEventListeners(): void {\n        this.rootStore.uiStore.BALANCE.pipe(takeUntil(this.DESTROY)).subscribe(this.onBalanceChanged.bind(this));\n        this.rootStore.uiStore.SELECTED_BET.pipe(takeUntil(this.DESTROY)).subscribe(this.onBetChanged.bind(this));\n        Core.SELECTED_DENOMINATION.pipe(takeUntil(this.DESTROY)).subscribe(this.onBetChanged.bind(this));\n        this.rootStore.subjects.TOGGLE_AUTOPLAY_POPUP.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.toggleAutoplayPopup.bind(this),\n        );\n        this.rootStore.subjects.CLOSE_ALL_POPUPS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.forceClosePopup.bind(this),\n        );\n        const closeFlow = merge(this.DESTROY, this.rootStore.subjects.CLOSE_AUTOPLAY_POPUP);\n        closeFlow.pipe(takeUntil(closeFlow)).subscribe(this.closePopup.bind(this, false));\n\n        this.rootStore.subjects.MODAL_PRESSED.pipe(takeUntil(this.DESTROY)).subscribe(this.closePopup.bind(this, true));\n\n        this.rootStore.subjects.FACTOR_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(this.onFactorChanged.bind(this));\n\n        this.rootStore.subjects.RESET_AUTOPLAY_RESTRICTIONS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.resetAutoPlayRestrictions.bind(this),\n        );\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/extended/controllers/AutoplayPopupControllerExtended.ts:53:9\",(this.extendedAutoplayPopup.selectedBtn),\"pointerup\"]), fromEvent(this.extendedAutoplayPopup.selectedBtn, 'pointerup'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.closePopup.bind(this, true));\n\n        this.extendedAutoplayPopup.startAutoplayButton.CLICK.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.startAutoplay.bind(this),\n        );\n\n        for (const btn of this.extendedAutoplayPopup.autoplayButtons) {\n            btn.CLICK.pipe(takeUntil(this.DESTROY)).subscribe(this.onChoseAutoPlayBtn.bind(this));\n        }\n    }\n\n    protected startAutoplay(): void {\n        if (this.settings.settings.settings.jurisdiction?.autoplayRestrictions?.confirmationModal) {\n            const modalData = this.rootStore.getModalData(this.numberOfAutoPlays);\n            const messData = {} as IErrorData;\n\n            (messData.code = Core.translator\n                .translate('AUTOPLAY.MODAL.MESSAGE')\n                .replace('<<totalAmount>>', modalData.totalBetAmount.toString().replace(/\\s+/g, '\\u00A0'))\n\n                .replace('<<numberOfSpins>>', this.numberOfAutoPlays.toString())\n                .replace('<<betAmount>>', modalData.betAmount)),\n                (messData.btnText = Core.translator.translate('AUTOPLAY.MODAL.CANCEL_BUTTON')),\n                (messData.type = ErrorTypes.CONFIRMATION),\n                (messData.hasConfirmButton = true),\n                (messData.confirmButtonText = Core.translator.translate('AUTOPLAY.MODAL.CONFIRM_BUTTON')),\n                (messData.callback = this.confirmStartAutoplay.bind(this)),\n                Core.SHOW_ERROR.next(messData);\n            // Reset the button so it doesn't stay stuck on the over texture after the modal is declined.\n            this.extendedAutoplayPopup.startAutoplayButton.setNormal();\n            return;\n        }\n\n        this.confirmStartAutoplay();\n    }\n    protected confirmStartAutoplay(): void {\n        this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.next(this.numberOfAutoPlays);\n        this.forceClosePopup();\n        this.rootStore.subjects.START_AUTOPLAY.next(this.numberOfAutoPlays);\n    }\n\n    protected resetAutoPlayRestrictions(): void {\n        this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.next(0);\n        this.rootStore.uiStore.autoPlayFromSettings = false;\n        this.extendedAutoplayPopup.resetSliders();\n    }\n\n    protected onFactorChanged(): void {\n        this.extendedAutoplayPopup.updateBetValue();\n    }\n\n    private onBalanceChanged(): void {\n        this.extendedAutoplayPopup.updateBalance();\n    }\n\n    private onBetChanged(): void {\n        this.extendedAutoplayPopup.updateBetValue();\n    }\n\n    private onChoseAutoPlayBtn(button: AutoplaySettingButtonExtended): void {\n        for (const btn of this.extendedAutoplayPopup.autoplayButtons) {\n            if (btn === button) {\n                Core.sounds.play('autoplaySelectSound');\n                btn.setSelected();\n                this.numberOfAutoPlays = button.numberOfAutoPlays;\n            } else {\n                btn.setNormal();\n            }\n        }\n    }\n\n    private toggleAutoplayPopup(): void {\n        if (this.extendedAutoplayPopup.isOpened) {\n            this.closePopup();\n        } else {\n            this.openPopup();\n        }\n    }\n\n    private closePopup(animation: boolean = true): void {\n        if (this.extendedAutoplayPopup.isOpened) {\n            Core.sounds.play('hideDenominationsSound');\n            this.toggleCustomButtons(true);\n            this.extendedAutoplayPopup.close(animation);\n            this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(false);\n            this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_OUTSIDE_BETS_VISIBLE.next(true);\n            this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(false);\n        }\n    }\n\n    private forceClosePopup(): void {\n        if (this.extendedAutoplayPopup.isOpened) {\n            this.toggleCustomButtons(true);\n            this.extendedAutoplayPopup.forceClose();\n            this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(false);\n            this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_OUTSIDE_BETS_VISIBLE.next(true);\n            this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(false);\n        }\n    }\n\n    private openPopup(animation: boolean = true): void {\n        if (!this.extendedAutoplayPopup.isOpened) {\n            Core.sounds.play('showDenominationsSound');\n            this.rootStore.subjects.CLOSE_ALL_POPUPS.next();\n            this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(true);\n            this.extendedAutoplayPopup.open(animation);\n            this.numberOfAutoPlays = this.extendedAutoplayPopup.autoplayButtons[0].numberOfAutoPlays;\n            this.toggleCustomButtons(false);\n            this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(false);\n            this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_OUTSIDE_BETS_VISIBLE.next(false);\n        }\n    }\n\n    protected toggleCustomButtons(visible: boolean): void {\n        this.componentConfiguration.buttonsToHide.forEach((btnName) => {\n            if (btnName === 'betButtons') {\n                this.rootStore.uiStore.SHOW_HIDE_BET_BUTTONS.next(visible);\n                if (this.featureController.isInGiftSpins) {\n                    this.rootStore.uiStore.SHOW_HIDE_GIFT_SPINS_VIEW.next(visible);\n                }\n            } else {\n                this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                    name: btnName,\n                    actions: 'visible',\n                    values: visible,\n                });\n            }\n        });\n\n        this.componentConfiguration.mainViewComponentsToHide.forEach((mainViewComponent) => {\n            this.rootStore.subjects.SHOW_HIDE_MAIN_VIEW_COMPONENTS.next({\n                name: mainViewComponent,\n                actions: 'visible',\n                values: visible,\n            });\n        });\n    }\n}\n\nexport enum MandatoryValuesExtended {\n    BALANCE_LES = 'lossLimits',\n    BALANCE_MORE = 'winLimits',\n    WIN_OVER = 'singleWinLimit',\n}\n","import Core, { Money } from '@egt/core';\nimport { InitialSettings, RootStore } from '@egt/slot';\nimport { Button, ButtonShapes, SteppedSlider, ViewContainer } from '@egt/ui-lib';\nimport { gsap } from 'gsap';\nimport { Container, NineSlicePlane, Sprite, Text, TextStyle } from 'pixi.js';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport AutoplayButtonTexturesExtended from '../buttons/AutoplayButtonTexturesExtended';\nimport AutoplayStartButtonExtended from '../buttons/AutoplaySartButtonExtended';\nimport AutoplaySettingButtonExtended from '../buttons/AutoplaySettingButtonExtended';\nimport { MandatoryValuesExtended } from '../controllers/AutoplayPopupControllerExtended';\nimport {\n    IAutoplayPopupComponentConfigurationExtended,\n    ISliderPositionObjectExtended,\n} from '../interfaces/InterfacesExtended';\n\n@injectable()\nexport default class AutoplayPopupViewExtended extends ViewContainer {\n    public mainContainer: Container;\n    public graphicsContainer: Container;\n\n    public autoplayButtons: AutoplaySettingButtonExtended[] = [];\n    public startAutoplayButton: AutoplayStartButtonExtended;\n    public buttonValues: number[];\n\n    public selectedBtn: Button;\n\n    public balanceLess: number;\n    public balanceMore: number;\n    public winOver: number;\n\n    private autoplayButtonsContainer: Sprite;\n    private popUpBackground: NineSlicePlane;\n    private popUpShadow: NineSlicePlane;\n    private popUpFirstSection: NineSlicePlane;\n    private popUpSecondSection: NineSlicePlane;\n    private popUpTitleText: Text;\n    private stopOn: Text;\n    private autoplay: Text;\n\n    private mandatory: MandatoryValuesExtended[];\n\n    private balanceSliderLessContainer: ViewContainer;\n    private balanceLessSlider: SteppedSlider;\n    private balanceLessTitle: Text;\n    private balanceLessValue: Text;\n    private balanceLessCurrency: Text;\n    private balanceLessNoLimit: Text;\n\n    private balanceSliderMoreContainer: ViewContainer;\n    private balanceMoreSlider: SteppedSlider;\n    private balanceMoreTitle: Text;\n    private balanceMoreValue: Text;\n    private balanceMoreCurrency: Text;\n    private balanceMoreNoLimit: Text;\n\n    private winSliderContainer: ViewContainer;\n    private winSlider: SteppedSlider;\n    private winTitle: Text;\n    private winValue: Text;\n    private winCurrency: Text;\n    private winNoLimit: Text;\n\n    private balanceContainer: Sprite;\n    private balanceText: Text;\n    private balanceTextValue: Text;\n    private balanceTextCurrency: Text;\n    private betContainer: Sprite;\n    private betText: Text;\n    private betTextValue: Text;\n    private betTextCurrency: Text;\n    private balanceMoneyFormatter: Money;\n    private betMoneyFormatter: Money;\n    private wordSpacing: number = 6;\n\n    private arrow: Sprite;\n    private _isOpened: boolean = false;\n    private animationTween: any;\n\n    private startingPoint: number = 250;\n    private bounceOffset: number = 15;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('AutoplayPopupComponentConfiguration')\n        protected componentConfiguration: IAutoplayPopupComponentConfigurationExtended,\n    ) {\n        super();\n    }\n\n    public init(): void {\n        if (!this.settings.autoplay) {\n            return;\n        }\n        this.buttonValues = this.settings.settings.settings.jurisdiction.autoplayRestrictions.autoPlays;\n        this.mandatory = this.settings.autoplayRestrictions.mandatory;\n        this.createGraphicsContainer();\n        this.createMainContainer();\n        this.createSelectedBtn();\n        this.crateAutoplayPopUp();\n        this.close(false);\n        this.createBalanceText();\n        this.createBetText();\n\n        Core.LEFT_HAND_MODE.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n    }\n\n    public destroy(): void {\n        this.killAllAnimations();\n\n        this.destroyObject(this.mainContainer);\n        this.destroyObject(this.graphicsContainer);\n        this.destroyObject(this.startAutoplayButton);\n        this.destroyObject(this.selectedBtn);\n        this.destroyObject(this.autoplayButtonsContainer);\n        this.destroyObject(this.popUpBackground);\n        this.destroyObject(this.popUpShadow);\n        this.destroyObject(this.popUpFirstSection);\n        this.destroyObject(this.popUpSecondSection);\n        this.destroyObject(this.popUpTitleText);\n        this.destroyObject(this.stopOn);\n        this.destroyObject(this.autoplay);\n        this.destroyObject(this.balanceSliderLessContainer);\n        this.destroyObject(this.balanceLessSlider);\n        this.destroyObject(this.balanceLessTitle);\n        this.destroyObject(this.balanceLessValue);\n        this.destroyObject(this.balanceLessCurrency);\n        this.destroyObject(this.balanceLessNoLimit);\n        this.destroyObject(this.balanceSliderMoreContainer);\n        this.destroyObject(this.balanceMoreSlider);\n        this.destroyObject(this.balanceMoreTitle);\n        this.destroyObject(this.balanceMoreValue);\n        this.destroyObject(this.balanceMoreCurrency);\n        this.destroyObject(this.balanceMoreNoLimit);\n        this.destroyObject(this.winSliderContainer);\n        this.destroyObject(this.winSlider);\n        this.destroyObject(this.winTitle);\n        this.destroyObject(this.winValue);\n        this.destroyObject(this.winCurrency);\n        this.destroyObject(this.winNoLimit);\n        this.destroyObject(this.balanceContainer);\n        this.destroyObject(this.balanceText);\n        this.destroyObject(this.balanceTextValue);\n        this.destroyObject(this.balanceTextCurrency);\n        this.destroyObject(this.betContainer);\n        this.destroyObject(this.betText);\n        this.destroyObject(this.betTextValue);\n        this.destroyObject(this.betTextCurrency);\n        this.destroyObject(this.balanceMoneyFormatter);\n        this.destroyObject(this.betMoneyFormatter);\n        this.destroyObject(this.arrow);\n\n        this.destroyArray(this.autoplayButtons);\n        this.destroyArray(this.buttonValues);\n        this.destroyArray(this.mandatory);\n\n        this.removeChildren();\n        super.destroy();\n    }\n\n    public get isOpened(): boolean {\n        return this._isOpened;\n    }\n\n    public set isOpened(value: boolean) {\n        this._isOpened = value;\n    }\n\n    public open(animation: boolean): void {\n        this.isOpened = true;\n        this.killAllAnimations();\n        this.resetButtons();\n\n        this.balanceLessSlider.steps = [0, this.getLessBalance()];\n        this.balanceLessSlider.resetSlider();\n        this.balanceMoreSlider.steps = [0, this.getMoreBalance()];\n        this.balanceMoreSlider.resetSlider();\n        this.winSlider.steps = [0, this.getWinOver()];\n        this.winSlider.resetSlider();\n\n        this.checkForMandatory();\n\n        this.mainContainer.alpha = 0;\n        this.mainContainer.y = this.componentConfiguration.mainContainerPosition.y + this.startingPoint;\n        this.mainContainer.visible = true;\n\n        const arrowY =\n            Core.LEFT_HAND_MODE.value && Core.ORIENTATION.value.isLandscape\n                ? this.componentConfiguration.arrowPosition.leftHandY\n                : this.componentConfiguration.arrowPosition.y;\n        this.arrow.alpha = 0;\n        this.arrow.y = arrowY + this.startingPoint;\n        this.arrow.visible = true;\n\n        this.selectedBtn.visible = true;\n        this.selectedBtn.alpha = 1;\n\n        if (animation) {\n            this.animationTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/autoplay-popup/src/egt/modes/extended/views/AutoplayPopupViewExtended.ts:201:35\",null]), gsap.timeline());\n\n            const animateAlpha = (alpha: number, duration: number) => ({\n                alpha,\n                duration,\n            });\n            const animateBounce = (y: number, duration: number, ease: string) => ({\n                y,\n                duration,\n                ease,\n            });\n\n            const mainContainerY = this.componentConfiguration.mainContainerPosition.y;\n\n            const onComplete = () => {\n                this.graphicsContainer.alpha = 1;\n                this.graphicsContainer.visible = true;\n            };\n\n            this.animationTween\n                .to(this.mainContainer, animateAlpha(1, 0.3), 0)\n                .to(this.arrow, animateAlpha(1, 0.3), '<')\n                .to(this.mainContainer, animateBounce(mainContainerY - this.bounceOffset, 0.25, 'power1.out'), 0)\n                .to(this.arrow, animateBounce(arrowY - this.bounceOffset, 0.25, 'power1.out'), '<')\n                .to(this.mainContainer, animateBounce(mainContainerY, 0.2, 'power1.in'), 0.25)\n                .to(\n                    this.arrow,\n                    {\n                        ...animateBounce(arrowY, 0.2, 'power1.in'),\n                        onComplete,\n                    },\n                    '<',\n                );\n        } else {\n            this.mainContainer.alpha = 1;\n            this.arrow.alpha = 1;\n            this.graphicsContainer.alpha = 1;\n            this.graphicsContainer.visible = true;\n        }\n    }\n\n    public forceClose(): void {\n        this.isOpened = false;\n        this.killAllAnimations();\n        this.noVisibility();\n        this.graphicsContainer.alpha = 0;\n        this.graphicsContainer.visible = false;\n        this.selectedBtn.alpha = 0;\n        this.selectedBtn.visible = false;\n    }\n\n    public close(animation: boolean): void {\n        this.isOpened = false;\n        this.killAllAnimations();\n\n        this.graphicsContainer.alpha = 0;\n        this.graphicsContainer.visible = false;\n        this.mainContainer.alpha = 1;\n        this.mainContainer.visible = true;\n        this.arrow.alpha = 1;\n        this.arrow.visible = true;\n        this.selectedBtn.alpha = 0;\n        this.selectedBtn.visible = false;\n        const arrowY =\n            Core.LEFT_HAND_MODE.value && Core.ORIENTATION.value.isLandscape\n                ? this.componentConfiguration.arrowPosition.leftHandY\n                : this.componentConfiguration.arrowPosition.y;\n\n        if (animation) {\n            this.animationTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/autoplay-popup/src/egt/modes/extended/views/AutoplayPopupViewExtended.ts:270:35\",null]), gsap.timeline());\n\n            const animateBounce = (alpha: number, y: number, duration: number) => ({\n                alpha,\n                y,\n                duration,\n            });\n\n            const mainContainerY = this.componentConfiguration.mainContainerPosition.y;\n\n            const onComplete = () => {\n                this.noVisibility();\n            };\n\n            this.animationTween\n                .to(this.mainContainer, animateBounce(0, mainContainerY + this.startingPoint, 0.3))\n                .to(this.arrow, { ...animateBounce(0, arrowY + this.startingPoint, 0.3), onComplete }, '<');\n        } else {\n            this.noVisibility();\n        }\n    }\n\n    public noVisibility() {\n        this.mainContainer.alpha = 0;\n        this.mainContainer.visible = false;\n        this.arrow.alpha = 0;\n        this.arrow.visible = false;\n    }\n\n    public resetSliders() {\n        this.balanceLessSlider.resetSlider();\n        this.balanceMoreSlider.resetSlider();\n        this.winSlider.resetSlider();\n    }\n\n    public updateBetValue(): void {\n        this.betMoneyFormatter.amountMoney = this.getTotalBet();\n        this.betTextValue.text = this.betMoneyFormatter.stringMoney;\n        this.positionBetBalance();\n        this.fitBetBalanceInBounds();\n    }\n\n    public updateBalance(): void {\n        this.balanceMoneyFormatter.amountMoney = this.rootStore.uiStore.BALANCE.value;\n        this.balanceTextValue.text = this.balanceMoneyFormatter.stringMoney;\n        this.positionBetBalance();\n        this.fitBetBalanceInBounds();\n    }\n\n    public fitBetBalanceInBounds(): void {\n        const maxWidth = this.betContainer.x - this.balanceContainer.x;\n        const balanceWidth =\n            this.balanceText.width +\n            this.balanceTextValue.width +\n            this.balanceTextCurrency.width +\n            2 * this.wordSpacing;\n        const betWidth =\n            this.betText.width + this.betTextValue.width + this.betTextCurrency.width + 2 * this.wordSpacing;\n        const actualWidth = balanceWidth + this.wordSpacing + betWidth;\n        this.betContainer.scale.set(1);\n        this.balanceContainer.scale.set(1);\n        if (actualWidth > maxWidth) {\n            const scaleFactor = maxWidth / actualWidth;\n            this.betContainer.scale.set(scaleFactor);\n            this.balanceContainer.scale.set(scaleFactor);\n            this.positionBetBalance();\n        }\n    }\n\n    public positionBetBalance(): void {\n        this.balanceTextCurrency.x = this.balanceTextValue.x + this.balanceTextValue.width + this.wordSpacing;\n        this.betTextCurrency.x = this.betTextValue.x + this.betTextValue.width + this.wordSpacing;\n        this.betContainer.pivot.set(\n            this.betText.width + this.betTextValue.width + this.betTextCurrency.width + 2 * this.wordSpacing,\n            0,\n        );\n    }\n\n    private resetButtons(): void {\n        for (let i: number = 0; i < this.autoplayButtons.length; i++) {\n            if (i === 0) {\n                this.autoplayButtons[i].setSelected();\n            } else {\n                this.autoplayButtons[i].setNormal();\n            }\n        }\n    }\n\n    private createBalanceText(): void {\n        this.balanceMoneyFormatter = new Money(this.rootStore.uiStore.BALANCE.value);\n        this.balanceContainer = new Sprite();\n        this.mainContainer.addChild(this.balanceContainer);\n\n        this.balanceText = new Text(\n            Core.translator.translate('BALANCE') + ':',\n            this.componentConfiguration.balanceText.textStyle,\n        );\n        this.balanceText.resolution = 2;\n        this.balanceContainer.addChild(this.balanceText);\n        this.balanceText.pivot.set(0, this.balanceText.height);\n\n        this.balanceTextValue = new Text(\n            this.balanceMoneyFormatter.stringMoney,\n            this.componentConfiguration.balanceText.valueStyle,\n        );\n        this.balanceTextValue.pivot.set(0, this.balanceTextValue.height);\n        this.balanceTextValue.resolution = 2;\n        this.balanceContainer.addChild(this.balanceTextValue);\n        this.balanceTextValue.x = this.balanceText.x + this.balanceText.width + this.wordSpacing;\n\n        this.balanceTextCurrency = new Text(\n            this.rootStore.settings.currency,\n            this.componentConfiguration.balanceText.currencyStyle,\n        );\n        this.balanceTextCurrency.pivot.set(0, this.balanceTextCurrency.height);\n        this.balanceTextCurrency.resolution = 2;\n        this.balanceContainer.addChild(this.balanceTextCurrency);\n        this.balanceTextCurrency.x = this.balanceTextValue.x + this.balanceTextValue.width + this.wordSpacing;\n    }\n\n    private createBetText(): void {\n        this.betMoneyFormatter = new Money(this.settings.bet * this.settings.denomination * this.settings.factor);\n        this.betContainer = new Sprite();\n        this.mainContainer.addChild(this.betContainer);\n\n        this.betText = new Text(Core.translator.translate('BET') + ':', this.componentConfiguration.betText.textStyle);\n        this.betText.pivot.set(0, this.betText.height);\n        this.betText.resolution = 2;\n        this.betContainer.addChild(this.betText);\n\n        this.betTextValue = new Text(\n            this.betMoneyFormatter.stringMoney,\n            this.componentConfiguration.betText.valueStyle,\n        );\n        this.betTextValue.pivot.set(0, this.betTextValue.height);\n        this.betTextValue.resolution = 2;\n        this.betContainer.addChild(this.betTextValue);\n        this.betTextValue.x = this.betText.x + this.betText.width + this.wordSpacing;\n\n        this.betTextCurrency = new Text(\n            this.rootStore.settings.currency,\n            this.componentConfiguration.betText.currencyStyle,\n        );\n        this.betTextCurrency.pivot.set(0, this.betTextCurrency.height);\n        this.betTextCurrency.resolution = 2;\n        this.betContainer.addChild(this.betTextCurrency);\n        this.betTextCurrency.x = this.betTextValue.x + this.betTextValue.width + this.wordSpacing;\n\n        this.betContainer.pivot.set(\n            this.betText.width + this.betTextValue.width + this.betTextCurrency.width + 2 * this.wordSpacing,\n            0,\n        );\n    }\n\n    private crateAutoplayPopUp(): void {\n        this.createPopupGraphics();\n        this.createPopUpTexts();\n        this.createSliders();\n        this.createStartBtn();\n        this.crateSlidersTexts();\n        this.createArrow();\n\n        this.autoplayButtonsContainer = new Sprite();\n        this.mainContainer.addChild(this.autoplayButtonsContainer);\n        for (let i: number = 0; i < this.buttonValues.length; i++) {\n            this.createAutoplayValueButtons(this.buttonValues[i], i);\n        }\n    }\n\n    private createPopupGraphics(): void {\n        this.popUpShadow = new NineSlicePlane(\n            Core.assets.getTextureFromSpriteSheet('autoplayResources', 'shadow.png'),\n            45,\n            45,\n            45,\n            45,\n        );\n        this.mainContainer.addChild(this.popUpShadow);\n\n        this.popUpBackground = new NineSlicePlane(\n            Core.assets.getTextureFromSpriteSheet('autoplayResources', 'popup.png'),\n            60,\n            60,\n            60,\n            60,\n        );\n        this.popUpBackground.interactive = true;\n        this.mainContainer.addChild(this.popUpBackground);\n\n        this.popUpFirstSection = new NineSlicePlane(\n            Core.assets.getTextureFromSpriteSheet('autoplayResources', 'popupFill.png'),\n            15,\n            15,\n            15,\n            15,\n        );\n        this.mainContainer.addChild(this.popUpFirstSection);\n\n        this.popUpSecondSection = new NineSlicePlane(\n            Core.assets.getTextureFromSpriteSheet('autoplayResources', 'popupFill.png'),\n            15,\n            15,\n            15,\n            15,\n        );\n        this.mainContainer.addChild(this.popUpSecondSection);\n    }\n\n    private createPopUpTexts(): void {\n        this.popUpTitleText = new Text(\n            Core.translator.translate('AUTOPLAY SETTINGS'),\n            this.componentConfiguration.popUpTitle.textStyle,\n        );\n        this.popUpTitleText.resolution = 2;\n        this.popUpTitleText.anchor.set(0.5);\n        this.mainContainer.addChild(this.popUpTitleText);\n\n        this.stopOn = new Text(\n            Core.translator.translate('STOP ON').toUpperCase(),\n            this.componentConfiguration.stopOnTitle.textStyle,\n        );\n        this.stopOn.resolution = 2;\n        this.stopOn.anchor.set(0.5, 0);\n        this.mainContainer.addChild(this.stopOn);\n\n        this.autoplay = new Text(\n            Core.translator.translate('Autoplay').toUpperCase(),\n            this.componentConfiguration.autoplayTitle.textStyle,\n        );\n        this.autoplay.resolution = 2;\n        this.autoplay.anchor.set(0.5, 0);\n        this.mainContainer.addChild(this.autoplay);\n    }\n\n    private createArrow(): void {\n        this.arrow = new Sprite(Core.assets.getTextureFromSpriteSheet('autoplayResources', 'arrow.png'));\n        this.addChild(this.arrow);\n    }\n\n    protected getTotalBet(): number {\n        return Core.SELECTED_DENOMINATION.value * this.rootStore.uiStore.SELECTED_BET.value * this.settings.factor;\n    }\n\n    private getLessBalance(): number {\n        return (this.rootStore.uiStore.BALANCE.value * this.settings.autoplayRestrictions.lossLimits) / 100;\n    }\n\n    private getMoreBalance(): number {\n        return (\n            (this.rootStore.uiStore.BALANCE.value * this.settings.autoplayRestrictions.winLimits) / 100 -\n            this.rootStore.uiStore.BALANCE.value\n        );\n    }\n\n    private getWinOver(): number {\n        return this.getTotalBet() * this.settings.autoplayRestrictions.singleWinLimit;\n    }\n\n    private createSliders(): void {\n        this.balanceSliderLessContainer = new ViewContainer();\n        this.balanceLessSlider = this.createSlider(\n            this.balanceSliderLessContainer,\n            this.componentConfiguration.balanceSliderLessContainer,\n            this.getLessBalance(),\n        );\n\n        this.balanceSliderMoreContainer = new ViewContainer();\n        this.balanceMoreSlider = this.createSlider(\n            this.balanceSliderMoreContainer,\n            this.componentConfiguration.balanceSliderMoreContainer,\n            this.getMoreBalance(),\n        );\n\n        this.winSliderContainer = new ViewContainer();\n        this.winSlider = this.createSlider(\n            this.winSliderContainer,\n            this.componentConfiguration.winSliderContainer,\n            this.getWinOver(),\n        );\n    }\n\n    private createSlider(container: Container, config: ISliderPositionObjectExtended, steps: number) {\n        this.mainContainer.addChild(container);\n        const slider = new SteppedSlider({\n            sliderWidth: config.width,\n            sliderHeight: config.height,\n            minValue: 10,\n            useSteps: false,\n            inactiveHandleTexture: Core.assets.getAsset('svgSliderDotInactive').texture,\n            activeHandleTexture: Core.assets.getAsset('svgSliderDotActive').texture,\n            // hoverHandleTexture: Core.assets.getAsset('svgSliderDotHover').texture,\n            // pressedHandleTexture: Core.assets.getAsset('svgSliderDotPressed').texture,\n            inactiveDotTexture: Core.assets.getTextureFromSpriteSheet('autoplayResources', 'sliderInactivePart.png'),\n            activeDotTexture: Core.assets.getTextureFromSpriteSheet('autoplayResources', 'sliderActivePart.png'),\n            notSelectedFill: config.notSelectedFill,\n            selectedFill: config.selectedFill,\n            stepsNotSelectedTexture: Core.assets.getTextureFromSpriteSheet(\n                'autoplayResources',\n                'sliderInactiveMiddlePart.png',\n            ),\n            stepsSelectedTexture: Core.assets.getTextureFromSpriteSheet(\n                'autoplayResources',\n                'sliderActiveMiddlePart.png',\n            ),\n            steps: [0, steps],\n        });\n        container.addChild(slider);\n        slider.init();\n        return slider;\n    }\n\n    private setTextProps(\n        text: Text,\n        textValue: string,\n        style: TextStyle,\n        anchor: { x: number; y: number },\n        x: number,\n        y: number,\n    ): void {\n        text.text = textValue;\n        text.style = style;\n        text.resolution = 2;\n        text.anchor.set(anchor.x, anchor.y);\n        text.x = x;\n        text.y = y;\n    }\n\n    private crateSlidersTexts(): void {\n        this.balanceLessTitle = new Text();\n        this.balanceLessCurrency = new Text();\n        this.balanceLessValue = new Text();\n        this.balanceLessNoLimit = new Text();\n        this.createElements(\n            this.balanceSliderLessContainer,\n            this.balanceLessTitle,\n            'LOSS LIMIT',\n            this.balanceLessCurrency,\n            this.balanceLessValue,\n            this.balanceLessNoLimit,\n            MandatoryValuesExtended.BALANCE_LES,\n        );\n\n        this.balanceLessSlider.CHANGE.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.balanceLess = this.balanceLessSlider.CHANGE.value;\n            this.sliderOnChange(\n                this.balanceLess,\n                this.balanceLessSlider,\n                this.componentConfiguration.slidersValueText.x,\n                this.balanceLessValue,\n                this.balanceLessCurrency,\n                this.balanceLessNoLimit,\n            );\n            this.rootStore.uiStore.balanceDecreaseValue = this.balanceLess;\n        });\n\n        this.balanceMoreTitle = new Text();\n        this.balanceMoreCurrency = new Text();\n        this.balanceMoreValue = new Text();\n        this.balanceMoreNoLimit = new Text();\n        this.createElements(\n            this.balanceSliderMoreContainer,\n            this.balanceMoreTitle,\n            'WINS LIMIT',\n            this.balanceMoreCurrency,\n            this.balanceMoreValue,\n            this.balanceMoreNoLimit,\n            MandatoryValuesExtended.BALANCE_MORE,\n        );\n\n        this.balanceMoreSlider.CHANGE.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            if (this.balanceMoreSlider.CHANGE.value > 1) {\n                this.balanceMore = this.balanceMoreSlider.CHANGE.value + this.rootStore.uiStore.BALANCE.value;\n            } else {\n                this.balanceMore = this.balanceMoreSlider.CHANGE.value;\n            }\n            this.sliderOnChange(\n                this.balanceMore,\n                this.balanceMoreSlider,\n                this.componentConfiguration.slidersValueText.x,\n                this.balanceMoreValue,\n                this.balanceMoreCurrency,\n                this.balanceMoreNoLimit,\n            );\n            this.rootStore.uiStore.balanceIncreaseValue = this.balanceMore;\n        });\n\n        this.winTitle = new Text();\n        this.winCurrency = new Text();\n        this.winValue = new Text();\n        this.winNoLimit = new Text();\n        this.createElements(\n            this.winSliderContainer,\n            this.winTitle,\n            'STOP ON WIN',\n            this.winCurrency,\n            this.winValue,\n            this.winNoLimit,\n            MandatoryValuesExtended.WIN_OVER,\n        );\n\n        this.winSlider.CHANGE.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.winOver = this.winSlider.CHANGE.value;\n            this.sliderOnChange(\n                this.winOver,\n                this.winSlider,\n                this.componentConfiguration.slidersValueText.x,\n                this.winValue,\n                this.winCurrency,\n                this.winNoLimit,\n            );\n            this.rootStore.uiStore.winLimitValue = this.winOver;\n        });\n    }\n\n    private createElements(\n        container: ViewContainer,\n        title: Text,\n        titleTextKey: string,\n        currency: Text,\n        value: Text,\n        noLimit: Text,\n        mandatoryValue: MandatoryValuesExtended,\n    ) {\n        this.setTextProps(\n            title,\n            this.toSentenceCase(Core.translator.translate(titleTextKey)),\n            this.componentConfiguration.slidersTitleText.textStyle,\n            { x: 0, y: 1 },\n            this.componentConfiguration.slidersTitleText.x,\n            this.componentConfiguration.slidersTitleText.y,\n        );\n        container.addChild(title);\n\n        this.setTextProps(\n            currency,\n            '',\n            this.componentConfiguration.slidersCurrencyText.textStyle,\n            { x: 1, y: 1 },\n            this.componentConfiguration.slidersCurrencyText.x,\n            this.componentConfiguration.slidersCurrencyText.y,\n        );\n        container.addChild(currency);\n\n        this.setTextProps(\n            value,\n            '',\n            this.componentConfiguration.slidersValueText.textStyle,\n            { x: 1, y: 1 },\n            0,\n            this.componentConfiguration.slidersValueText.y,\n        );\n        container.addChild(value);\n\n        let text: string = this.toSentenceCase(Core.translator.translate('NO LIMIT'));\n        let textStyle: TextStyle = this.componentConfiguration.slidersValueNoLimit.textStyle;\n        if (this.mandatory.indexOf(mandatoryValue) >= 0) {\n            text = '*';\n            textStyle = this.componentConfiguration.slidersValueMandatoryText.textStyle;\n        }\n        this.setTextProps(\n            noLimit,\n            text,\n            textStyle,\n            { x: 1, y: 1 },\n            this.componentConfiguration.slidersValueNoLimit.x,\n            this.componentConfiguration.slidersValueNoLimit.y,\n        );\n        container.addChild(noLimit);\n    }\n\n    private sliderOnChange(\n        sliderValue: number,\n        slider: SteppedSlider,\n        x: number,\n        value: Text,\n        currency: Text,\n        noLimit: Text,\n    ) {\n        const moneyFormatter: Money = new Money(0);\n        moneyFormatter.amountMoney = sliderValue;\n        value.text = moneyFormatter.stringMoney;\n        currency.text = Core.PLAYER_BALANCE.value.currency;\n        value.x = x - currency.width;\n        if (slider.CHANGE.value === 0) {\n            noLimit.visible = true;\n            value.visible = false;\n            currency.visible = false;\n        } else {\n            noLimit.visible = false;\n            value.visible = true;\n            currency.visible = true;\n        }\n        this.checkForMandatory();\n    }\n\n    private createStartBtn(): void {\n        const btnTextures: AutoplayButtonTexturesExtended = new AutoplayButtonTexturesExtended(\n            Core.assets.getAsset('svgAutoplayStartNormal').texture,\n            Core.assets.getAsset('svgAutoplayStartNormal').texture,\n            Core.assets.getAsset('svgAutoplayStartDisabled').texture,\n            Core.assets.getAsset('svgAutoplayStartHover').texture,\n        );\n        this.startAutoplayButton = new AutoplayStartButtonExtended(\n            Core.translator.translate('START AUTOPLAY'),\n            btnTextures,\n            this.componentConfiguration.startAutoplayNormalText.textStyle,\n            this.componentConfiguration.startAutoplayDisabledText.textStyle,\n        );\n        this.mainContainer.addChild(this.startAutoplayButton);\n    }\n\n    private createAutoplayValueButtons(value: number, _buttonIndex: number): void {\n        const btnTextures: AutoplayButtonTexturesExtended = new AutoplayButtonTexturesExtended(\n            Core.assets.getAsset('svgAutoplayPopUpNormal').texture,\n            Core.assets.getAsset('svgAutoplayPopUpSelected').texture,\n            Core.assets.getAsset('svgAutoplayPopUpNormal').texture,\n            Core.assets.getAsset('svgAutoplayPopUpHover').texture,\n        );\n        const button: AutoplaySettingButtonExtended = new AutoplaySettingButtonExtended(\n            value,\n            btnTextures,\n            this.componentConfiguration.buttonValueText.textStyle,\n            this.componentConfiguration.buttonValueText.selectedTextStyle,\n            this.componentConfiguration.buttonValueText.width,\n            this.componentConfiguration.buttonValueText.height,\n        );\n\n        this.autoplayButtonsContainer.addChild(button);\n        this.autoplayButtons.push(button);\n    }\n\n    private setOrientation(): void {\n        this.killAllAnimations();\n        if (this.isOpened) {\n            this.mainContainer.alpha = 1;\n            this.arrow.alpha = 1;\n            this.graphicsContainer.alpha = 1;\n            this.graphicsContainer.visible = true;\n        } else {\n            this.noVisibility();\n            this.graphicsContainer.alpha = 0;\n            this.graphicsContainer.visible = false;\n        }\n        this.mainContainer.x = this.componentConfiguration.mainContainerPosition.x;\n        this.mainContainer.y = this.componentConfiguration.mainContainerPosition.y;\n\n        this.popUpBackground.x = this.componentConfiguration.popUpGraphicsContainer.x;\n        this.popUpBackground.y = this.componentConfiguration.popUpGraphicsContainer.y;\n        this.popUpBackground.width = this.componentConfiguration.popUpGraphicsContainer.width;\n        this.popUpBackground.height = this.componentConfiguration.popUpGraphicsContainer.height;\n\n        this.popUpTitleText.x =\n            this.componentConfiguration.popUpGraphicsContainer.x +\n            this.componentConfiguration.popUpGraphicsContainer.width / 2;\n        this.popUpTitleText.y = this.popUpBackground.y + this.componentConfiguration.popUpTitle.yOffset;\n\n        this.stopOn.x = this.componentConfiguration.stopOnTitle.x;\n        this.stopOn.y = this.componentConfiguration.stopOnTitle.y;\n\n        this.autoplay.x = this.componentConfiguration.autoplayTitle.x;\n        this.autoplay.y = this.componentConfiguration.autoplayTitle.y;\n\n        this.balanceSliderLessContainer.x = this.componentConfiguration.balanceSliderLessContainer.x;\n        this.balanceSliderLessContainer.y = this.componentConfiguration.balanceSliderLessContainer.y;\n\n        this.balanceSliderMoreContainer.x = this.componentConfiguration.balanceSliderMoreContainer.x;\n        this.balanceSliderMoreContainer.y = this.componentConfiguration.balanceSliderMoreContainer.y;\n\n        this.winSliderContainer.x = this.componentConfiguration.winSliderContainer.x;\n        this.winSliderContainer.y = this.componentConfiguration.winSliderContainer.y;\n\n        this.popUpShadow.x = this.componentConfiguration.popUpGraphicsContainer.x - 40;\n        this.popUpShadow.y = this.componentConfiguration.popUpGraphicsContainer.y;\n        this.popUpShadow.width = this.componentConfiguration.popUpGraphicsContainer.width + 80;\n        this.popUpShadow.height = this.componentConfiguration.popUpGraphicsContainer.height + 40;\n\n        this.popUpFirstSection.x = this.componentConfiguration.popUpFirstSectionPosition.x;\n        this.popUpFirstSection.y = this.componentConfiguration.popUpFirstSectionPosition.y;\n        this.popUpFirstSection.width = this.componentConfiguration.popUpFirstSectionPosition.width;\n        this.popUpFirstSection.height = this.componentConfiguration.popUpFirstSectionPosition.height;\n\n        this.popUpSecondSection.x = this.componentConfiguration.popUpSecondSectionPosition.x;\n        this.popUpSecondSection.y = this.componentConfiguration.popUpSecondSectionPosition.y;\n        this.popUpSecondSection.width = this.componentConfiguration.popUpSecondSectionPosition.width;\n        this.popUpSecondSection.height = this.componentConfiguration.popUpSecondSectionPosition.height;\n\n        for (let i: number = 0; i < this.autoplayButtons.length; i++) {\n            this.autoplayButtons[i].x =\n                (this.componentConfiguration.buttonValueText.xOffset +\n                    this.componentConfiguration.buttonValueText.width) *\n                i;\n        }\n\n        this.autoplayButtonsContainer.x =\n            this.popUpSecondSection.x +\n            (this.popUpSecondSection.width -\n                (114 * (this.autoplayButtons.length - 1) + this.autoplayButtons[0].width)) /\n                2;\n        this.autoplayButtonsContainer.y = this.componentConfiguration.buttonsContainerPositions.y;\n\n        this.arrow.x = this.componentConfiguration.arrowPosition.x;\n        this.arrow.y = this.componentConfiguration.arrowPosition.y;\n        this.arrow.angle = this.componentConfiguration.arrowPosition.angle;\n\n        this.balanceContainer.x = this.componentConfiguration.balanceText.x;\n        this.balanceContainer.y = this.componentConfiguration.balanceText.y;\n\n        this.betContainer.x = this.componentConfiguration.betText.x;\n        this.betContainer.y = this.componentConfiguration.betText.y;\n\n        this.startAutoplayButton.x = this.componentConfiguration.startAutoplayBtn.x;\n        this.startAutoplayButton.y = this.componentConfiguration.startAutoplayBtn.y;\n\n        this.selectedBtn.x = this.componentConfiguration.selectedButton.x;\n        this.selectedBtn.y = this.componentConfiguration.selectedButton.y;\n        this.selectedBtn.scale.set(this.componentConfiguration.selectedButton.scale);\n\n        this.setLeftHand();\n    }\n\n    private setLeftHand(): void {\n        if (Core.LEFT_HAND_MODE.value && Core.ORIENTATION.value.isLandscape) {\n            this.mainContainer.x = this.componentConfiguration.mainContainerPosition.leftHandX;\n\n            this.arrow.x = this.componentConfiguration.arrowPosition.leftHandX;\n            this.arrow.y = this.componentConfiguration.arrowPosition.leftHandY;\n            this.arrow.angle = this.componentConfiguration.arrowPosition.leftHandAngle;\n\n            this.selectedBtn.x = this.componentConfiguration.selectedButton.leftHandX;\n        }\n    }\n\n    private checkForMandatory() {\n        let mandatoryChecked: boolean = true;\n        for (const mandatory of this.mandatory) {\n            if (mandatory === MandatoryValuesExtended.BALANCE_LES && this.balanceLess === 0) {\n                mandatoryChecked = false;\n            } else if (mandatory === MandatoryValuesExtended.BALANCE_MORE && this.balanceMore === 0) {\n                mandatoryChecked = false;\n            } else if (mandatory === MandatoryValuesExtended.WIN_OVER && this.winOver === 0) {\n                mandatoryChecked = false;\n            }\n        }\n\n        if (mandatoryChecked) {\n            this.startAutoplayButton.setNormal();\n        } else {\n            this.startAutoplayButton.setDisabled();\n        }\n    }\n\n    private createSelectedBtn(): void {\n        this.selectedBtn = new Button(\n            [Core.assets.getAsset('svgAutoplaySelected').texture],\n            undefined,\n            ButtonShapes.Circle,\n        );\n        this.selectedBtn.pivot.set(this.selectedBtn.width / 2, this.selectedBtn.height / 2);\n        this.selectedBtn.interactive = true;\n        this.selectedBtn.name = 'selectedBtn';\n        this.addChild(this.selectedBtn);\n    }\n\n    private createGraphicsContainer(): void {\n        this.graphicsContainer = new Container();\n        this.graphicsContainer.visible = false;\n        this.graphicsContainer.alpha = 0;\n        this.addChild(this.graphicsContainer);\n    }\n\n    private createMainContainer(): void {\n        this.mainContainer = new Container();\n        this.mainContainer.visible = false;\n        this.mainContainer.alpha = 0;\n        this.addChild(this.mainContainer);\n    }\n\n    private killAllAnimations(): void {\n        if (this.animationTween) {\n            this.animationTween.kill();\n            this.animationTween = null;\n        }\n    }\n\n    private toSentenceCase(str: string): string {\n        return str.charAt(0).toUpperCase() + str.substring(1).toLowerCase();\n    }\n\n    private destroyArray(arr: any[]) {\n        if (arr) {\n            arr.forEach((child) => {\n                this.destroyObject(child);\n            });\n            // @ts-ignore\n            arr = null;\n        }\n    }\n\n    private destroyObject(obj: any) {\n        obj?.destroy?.();\n        // @ts-ignore\n        obj = null;\n    }\n}\n","import { ButtonShapes, ViewContainer } from '@egt/ui-lib';\nimport { Sprite, Text, TextStyle, Texture } from 'pixi.js';\nimport { fromEvent, Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\n\nexport default class AutoplayKeyboardActionButtonMaxBet extends ViewContainer {\n    public readonly CLICK = new Subject();\n    protected buttonBackground: Sprite;\n    protected _shape: ButtonShapes = ButtonShapes.Rectangle;\n    protected btnText: Text;\n    protected btnTextStyleNormal: TextStyle;\n    protected label?: string;\n    protected textures: AutoplayKeyboardActionButtonTexturesMaxBet;\n\n    constructor(textures: AutoplayKeyboardActionButtonTexturesMaxBet, btnTextStyleNormal: TextStyle, label?: string) {\n        super();\n        this.interactive = true;\n        this.textures = textures;\n        this.btnTextStyleNormal = btnTextStyleNormal;\n        this.label = label;\n        this.createBtnBackground();\n        this.addBtnText();\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/max-bet/buttons/AutoplayKeyboardActionButtonMaxBet.ts:24:9\",(this.buttonBackground),\"pointertap\"]), fromEvent(this.buttonBackground, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerTap.bind(this));\n    }\n\n    public destroy(): void {\n        this.removeChildren();\n\n        this.buttonBackground.destroy({ children: true });\n        this.textures.destroy();\n        // @ts-ignore\n        this.textures = null;\n\n        if (this.btnText) {\n            this.btnText.destroy();\n            // @ts-ignore\n            this.btnText = null;\n        }\n\n        super.destroy();\n    }\n\n    protected createBtnBackground(): void {\n        this.buttonBackground = new Sprite(this.textures.normalTexture);\n\n        this.buttonBackground.interactive = true;\n        this.addChild(this.buttonBackground);\n    }\n\n    protected addBtnText(): void {\n        this.btnText = new Text(this.label ?? '', this.btnTextStyleNormal);\n        this.btnText.resolution = 2;\n        this.btnText.anchor.set(0.5);\n        this.btnText.x = this.width / 2;\n        this.btnText.y = this.height / 2;\n        this.addChild(this.btnText);\n    }\n\n    public tintBtn(): void {\n        if (this.buttonBackground) {\n            this.buttonBackground.tint = 0x717171;\n            this.buttonBackground.interactive = false;\n        }\n        if (this.btnText) {\n            this.btnText.tint = 0x717171;\n        }\n        this.interactive = false;\n        this.cursor = 'pointer';\n    }\n\n    public untintBtn(): void {\n        if (this.buttonBackground) {\n            this.buttonBackground.tint = 0xffffff;\n            this.buttonBackground.interactive = true;\n        }\n        if (this.btnText) {\n            this.btnText.tint = 0xffffff;\n        }\n        this.interactive = true;\n        this.cursor = 'pointer';\n    }\n\n    protected onPointerTap(): void {\n        this.CLICK.next(this);\n    }\n}\n\nexport class AutoplayKeyboardActionButtonTexturesMaxBet {\n    constructor(public normalTexture: Texture) {}\n\n    public destroy() {\n        this.normalTexture.destroy();\n        // @ts-ignore\n        this.normalTexture = null;\n    }\n}\n","import { ButtonShapes, ViewContainer } from '@egt/ui-lib';\nimport { Sprite, Text, TextStyle, Texture } from 'pixi.js';\nimport { fromEvent, Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\n\nexport default class AutoplayKeyboardButtonMaxBet extends ViewContainer {\n    public readonly CLICK = new Subject();\n    protected buttonBackground: Sprite;\n    protected _shape: ButtonShapes = ButtonShapes.Rectangle;\n    protected btnText: Text;\n    protected btnTextStyleNormal: TextStyle;\n    protected textures: AutoplayKeyboardButtonTexturesMaxBet;\n    public value: string;\n\n    constructor(textures: AutoplayKeyboardButtonTexturesMaxBet, btnTextStyleNormal: TextStyle, value: string) {\n        super();\n        this.interactive = true;\n        this.textures = textures;\n        this.btnTextStyleNormal = btnTextStyleNormal;\n        this.createBtnBackground();\n        this.addBtnText(value);\n        this.value = value;\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/max-bet/buttons/AutoplayKeyboardButtonMaxBet.ts:23:9\",(this.buttonBackground),\"pointertap\"]), fromEvent(this.buttonBackground, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerTap.bind(this));\n    }\n\n    public destroy(): void {\n        this.removeChildren();\n\n        this.buttonBackground.destroy({ children: true });\n        this.textures.destroy();\n        // @ts-ignore\n        this.textures = null;\n\n        if (this.btnText) {\n            this.btnText.destroy();\n            // @ts-ignore\n            this.btnText = null;\n        }\n\n        super.destroy();\n    }\n\n    protected createBtnBackground(): void {\n        this.buttonBackground = new Sprite(this.textures.normalTexture);\n\n        this.buttonBackground.interactive = true;\n        this.addChild(this.buttonBackground);\n    }\n\n    protected addBtnText(value: string): void {\n        this.btnText = new Text(value, this.btnTextStyleNormal);\n        this.btnText.resolution = 2;\n        this.btnText.anchor.set(0.5);\n        this.btnText.x = this.width / 2;\n        this.btnText.y = this.height / 2;\n        this.addChild(this.btnText);\n    }\n\n    protected onPointerTap(): void {\n        this.CLICK.next(this);\n    }\n}\n\nexport class AutoplayKeyboardButtonTexturesMaxBet {\n    constructor(public normalTexture: Texture) {}\n    public destroy() {\n        this.normalTexture.destroy();\n        // @ts-ignore\n        this.normalTexture = null;\n    }\n}\n","const enum AutoplayPopupButtonStatesMaxBet {\n    Normal,\n    Over,\n    Selected,\n    Disabled,\n}\n\nexport default AutoplayPopupButtonStatesMaxBet;\n","import { Texture } from 'pixi.js';\n\nexport default class AutoplayPopupButtonTexturesMaxBet {\n    constructor(\n        public normalTexture: Texture,\n        public selectedTexture: Texture,\n        public disabledTexture: Texture,\n        public overTexture: Texture,\n    ) {\n        //\n    }\n\n    public destroy() {\n        this.normalTexture.destroy();\n        // @ts-ignore\n        this.normalTexture = null;\n\n        this.selectedTexture.destroy();\n        // @ts-ignore\n        this.selectedTexture = null;\n\n        if (this.disabledTexture) {\n            this.disabledTexture.destroy();\n            // @ts-ignore\n            this.disabledTexture = null;\n        }\n\n        if (this.overTexture) {\n            this.overTexture.destroy();\n            // @ts-ignore\n            this.overTexture = null;\n        }\n    }\n}\n","import Core from '@egt/core';\nimport { ButtonShapes, ViewContainer } from '@egt/ui-lib';\nimport { Sprite, Text, TextStyle } from 'pixi.js';\nimport { Subject, fromEvent } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport AutoplayPopupButtonStatesMaxBet from './AutoplayPopupButtonStatesMaxBet';\nimport AutoplayPopupButtonTexturesMaxBet from './AutoplayPopupButtonTexturesMaxBet';\n\nexport default class AutoplayPopupButtonMaxBet extends ViewContainer {\n    public readonly CLICK = new Subject();\n\n    public numberOfAutoPlays: number;\n    protected factor: number;\n    protected buttonBackground: Sprite;\n\n    protected _state: AutoplayPopupButtonStatesMaxBet = AutoplayPopupButtonStatesMaxBet.Normal;\n    protected _shape: ButtonShapes = ButtonShapes.Rectangle;\n\n    protected textures: AutoplayPopupButtonTexturesMaxBet;\n    protected btnText: Text;\n    protected btnTextStyleNormal: TextStyle;\n    protected btnTextStyleSelected: TextStyle;\n    protected infinitySign: Sprite;\n\n    constructor(\n        numberOfAutoPlays: number,\n        textures: AutoplayPopupButtonTexturesMaxBet,\n        btnTextStyleNormal: TextStyle,\n        btnTextStyleSelected: TextStyle,\n        width?: number,\n        height?: number,\n    ) {\n        super();\n        this.interactive = true;\n        this.numberOfAutoPlays = numberOfAutoPlays;\n        this.textures = textures;\n        this.btnTextStyleNormal = btnTextStyleNormal;\n        this.btnTextStyleSelected = btnTextStyleSelected;\n\n        this.createBtnBackground(width, height);\n        if (numberOfAutoPlays > 0) {\n            this.addBtnText();\n        } else {\n            this.addInfinitySign();\n        }\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/max-bet/buttons/AutoplayPopupSettingButtonMaxBet.ts:47:9\",(this.buttonBackground),\"pointerdown\"]), fromEvent(this.buttonBackground, 'pointerdown'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerDown.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/max-bet/buttons/AutoplayPopupSettingButtonMaxBet.ts:51:9\",(this.buttonBackground),\"pointerup\"]), fromEvent(this.buttonBackground, 'pointerup'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerUp.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/max-bet/buttons/AutoplayPopupSettingButtonMaxBet.ts:55:9\",(this.buttonBackground),\"pointerupoutside\"]), fromEvent(this.buttonBackground, 'pointerupoutside'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerOut.bind(this));\n\n        fromEvent(this.buttonBackground, 'pointerover')\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerOver.bind(this));\n\n        fromEvent(this.buttonBackground, 'pointerout')\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerOut.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/max-bet/buttons/AutoplayPopupSettingButtonMaxBet.ts:67:9\",(this.buttonBackground),\"pointertap\"]), fromEvent(this.buttonBackground, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerTap.bind(this));\n    }\n\n    public destroy(): void {\n        this.removeChildren();\n\n        this.buttonBackground.destroy({ children: true });\n        this.textures.destroy();\n        // @ts-ignore\n        this.textures = null;\n\n        if (this.btnText) {\n            this.btnText.destroy();\n            // @ts-ignore\n            this.btnText = null;\n        }\n\n        super.destroy();\n    }\n\n    public fakeClick(): void {\n        this.buttonBackground.emit('pointertap');\n    }\n\n    public onPointerDown(): void {\n        if (\n            this.state === AutoplayPopupButtonStatesMaxBet.Disabled ||\n            this.state === AutoplayPopupButtonStatesMaxBet.Selected\n        ) {\n            return;\n        }\n        this.state = AutoplayPopupButtonStatesMaxBet.Over;\n    }\n\n    /**\n     *\n     */\n    public onPointerOut(): void {\n        if (\n            this.state === AutoplayPopupButtonStatesMaxBet.Disabled ||\n            this.state === AutoplayPopupButtonStatesMaxBet.Selected\n        ) {\n            return;\n        }\n        this.state = AutoplayPopupButtonStatesMaxBet.Normal;\n    }\n\n    public setSelected(): void {\n        this.state = AutoplayPopupButtonStatesMaxBet.Selected;\n        this.buttonBackground.texture = this.textures.selectedTexture;\n        if (this.btnText) {\n            this.btnText.style = this.btnTextStyleSelected;\n        }\n        if (this.infinitySign) {\n            this.infinitySign.texture = Core.assets.getAsset('infinityIconSelected').texture;\n        }\n    }\n\n    public setNormal(): void {\n        this.state = AutoplayPopupButtonStatesMaxBet.Normal;\n        this.buttonBackground.texture = this.textures.normalTexture;\n        if (this.btnText) {\n            this.btnText.style = this.btnTextStyleNormal;\n        }\n        if (this.infinitySign) {\n            this.infinitySign.texture = Core.assets.getAsset('infinityIcon').texture;\n        }\n    }\n\n    protected addBtnText(): void {\n        this.btnText = new Text(this.numberOfAutoPlays, this.btnTextStyleNormal);\n        this.btnText.resolution = 2;\n        this.btnText.anchor.set(0.5);\n        this.btnText.x = this.width / 2;\n        this.btnText.y = this.height / 2;\n        this.addChild(this.btnText);\n    }\n\n    protected createBtnBackground(width?: number, height?: number): void {\n        this.buttonBackground = new Sprite(this.textures.normalTexture);\n        this.buttonBackground.interactive = true;\n        if (width) {\n            this.buttonBackground.width = width;\n        }\n        if (height) {\n            this.buttonBackground.height = height;\n        }\n        this.addChild(this.buttonBackground);\n    }\n\n    protected onPointerUp(): void {\n        if (\n            this.state === AutoplayPopupButtonStatesMaxBet.Disabled ||\n            this.state === AutoplayPopupButtonStatesMaxBet.Selected\n        ) {\n            return;\n        }\n        this.state = AutoplayPopupButtonStatesMaxBet.Normal;\n    }\n\n    protected onPointerOver(): void {\n        if (\n            this.state === AutoplayPopupButtonStatesMaxBet.Disabled ||\n            this.state === AutoplayPopupButtonStatesMaxBet.Selected\n        ) {\n            return;\n        }\n        this.state = AutoplayPopupButtonStatesMaxBet.Over;\n    }\n\n    protected onPointerTap(): void {\n        if (\n            this.state === AutoplayPopupButtonStatesMaxBet.Disabled ||\n            this.state === AutoplayPopupButtonStatesMaxBet.Selected\n        ) {\n            return;\n        }\n        this.CLICK.next(this);\n    }\n\n    protected getTexture(): AutoplayPopupButtonTexturesMaxBet {\n        return this.textures;\n    }\n\n    protected addInfinitySign(): void {\n        this.infinitySign = new Sprite(Core.assets.getAsset('infinityIcon').texture);\n        this.infinitySign.anchor.set(0.5);\n        this.infinitySign.x = this.width / 2;\n        this.infinitySign.y = this.height / 2;\n        this.addChild(this.infinitySign);\n    }\n\n    get state(): AutoplayPopupButtonStatesMaxBet {\n        return this._state;\n    }\n    set state(state: AutoplayPopupButtonStatesMaxBet) {\n        this._state = state;\n        this.cursor = 'normal';\n        switch (state) {\n            case AutoplayPopupButtonStatesMaxBet.Normal:\n                this.buttonBackground.texture = this.textures.normalTexture;\n                break;\n            case AutoplayPopupButtonStatesMaxBet.Over:\n                this.cursor = 'pointer';\n                if (this.textures.overTexture) {\n                    this.buttonBackground.texture = this.textures.overTexture;\n                } else {\n                    this.buttonBackground.texture = this.textures.normalTexture;\n                }\n                break;\n            case AutoplayPopupButtonStatesMaxBet.Selected:\n                this.buttonBackground.texture = this.textures.selectedTexture;\n                break;\n            case AutoplayPopupButtonStatesMaxBet.Disabled:\n                if (this.textures.disabledTexture) {\n                    this.buttonBackground.texture = this.textures.disabledTexture;\n                } else {\n                    this.buttonBackground.texture = this.textures.normalTexture;\n                }\n                break;\n        }\n    }\n}\n","import Core from '@egt/core';\nimport { ButtonShapes, ViewContainer } from '@egt/ui-lib';\nimport { Sprite, Text, TextStyle } from 'pixi.js';\nimport { Subject, fromEvent } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport AutoplayPopupButtonStatesMaxBet from './AutoplayPopupButtonStatesMaxBet';\nimport AutoplayPopupButtonTexturesMaxBet from './AutoplayPopupButtonTexturesMaxBet';\n\nexport default class AutoplayPopupStartButtonMaxBet extends ViewContainer {\n    public readonly CLICK = new Subject();\n\n    protected factor: number;\n    protected buttonBackground: Sprite;\n\n    protected _state: AutoplayPopupButtonStatesMaxBet = AutoplayPopupButtonStatesMaxBet.Normal;\n    protected _shape: ButtonShapes = ButtonShapes.Rectangle;\n\n    protected textures: AutoplayPopupButtonTexturesMaxBet;\n    protected btnText: Text;\n    protected btnTextStyleNormal: TextStyle;\n    protected btnTextStyleDisabled: TextStyle;\n    protected infinitySign: Sprite;\n    protected label: string;\n\n    constructor(\n        label: string,\n        textures: AutoplayPopupButtonTexturesMaxBet,\n        btnTextStyleNormal: TextStyle,\n        btnTextStyleDisabled?: TextStyle,\n    ) {\n        super();\n        this.interactive = true;\n        this.textures = textures;\n        this.btnTextStyleNormal = btnTextStyleNormal;\n        this.btnTextStyleDisabled = btnTextStyleDisabled ? btnTextStyleDisabled : btnTextStyleNormal;\n        this.label = label;\n\n        this.createBtnBackground();\n        this.addBtnText();\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/max-bet/buttons/AutoplayPopupStartButtonMaxBet.ts:41:9\",(this.buttonBackground),\"pointerdown\"]), fromEvent(this.buttonBackground, 'pointerdown'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerDown.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/max-bet/buttons/AutoplayPopupStartButtonMaxBet.ts:45:9\",(this.buttonBackground),\"pointerup\"]), fromEvent(this.buttonBackground, 'pointerup'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerUp.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/max-bet/buttons/AutoplayPopupStartButtonMaxBet.ts:49:9\",(this.buttonBackground),\"pointerupoutside\"]), fromEvent(this.buttonBackground, 'pointerupoutside'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerOut.bind(this));\n\n        fromEvent(this.buttonBackground, 'pointerover')\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerOver.bind(this));\n\n        fromEvent(this.buttonBackground, 'pointerout')\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerOut.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/max-bet/buttons/AutoplayPopupStartButtonMaxBet.ts:61:9\",(this.buttonBackground),\"pointertap\"]), fromEvent(this.buttonBackground, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerTap.bind(this));\n    }\n\n    public destroy(): void {\n        this.removeChildren();\n\n        this.buttonBackground.destroy({ children: true });\n        this.textures.destroy();\n        // @ts-ignore\n        this.textures = null;\n\n        this.btnText.destroy();\n        // @ts-ignore\n        this.btnText = null;\n\n        super.destroy();\n    }\n\n    public fakeClick(): void {\n        this.buttonBackground.emit('pointertap');\n    }\n\n    public onPointerDown(): void {\n        if (\n            this.state === AutoplayPopupButtonStatesMaxBet.Disabled ||\n            this.state === AutoplayPopupButtonStatesMaxBet.Selected\n        ) {\n            return;\n        }\n        this.state = AutoplayPopupButtonStatesMaxBet.Over;\n    }\n\n    /**\n     *\n     */\n    public onPointerOut(): void {\n        if (\n            this.state === AutoplayPopupButtonStatesMaxBet.Disabled ||\n            this.state === AutoplayPopupButtonStatesMaxBet.Selected\n        ) {\n            return;\n        }\n        this.state = AutoplayPopupButtonStatesMaxBet.Normal;\n    }\n\n    public setDisabled(): void {\n        this.state = AutoplayPopupButtonStatesMaxBet.Disabled;\n        this.buttonBackground.texture = this.textures.disabledTexture;\n        this.btnText.style = this.btnTextStyleDisabled;\n        this.scaleTextToFit();\n    }\n\n    public setNormal(): void {\n        this.state = AutoplayPopupButtonStatesMaxBet.Normal;\n        this.buttonBackground.texture = this.textures.normalTexture;\n        this.btnText.style = this.btnTextStyleNormal;\n        this.scaleTextToFit();\n    }\n\n    protected addBtnText(): void {\n        this.btnText = new Text(this.label, this.btnTextStyleNormal);\n        this.btnText.resolution = 2;\n        this.btnText.anchor.set(0.5);\n        this.btnText.x = this.width / 2;\n        this.btnText.y = this.height / 2;\n\n        this.scaleTextToFit();\n\n        this.addChild(this.btnText);\n    }\n\n    protected scaleTextToFit(): void {\n        if (!this.btnText || !this.buttonBackground) return;\n\n        const padding = 10;\n        const bounds = this.buttonBackground.width - padding;\n\n        this.btnText.scale.set(1);\n\n        if (this.btnText.width > bounds) {\n            this.btnText.scale.set(bounds / this.btnText.width);\n        }\n\n        this.btnText.x = this.width / 2;\n        this.btnText.y = this.height / 2;\n    }\n\n    protected createBtnBackground(): void {\n        this.buttonBackground = new Sprite(this.textures.normalTexture);\n        this.buttonBackground.interactive = true;\n        this.addChild(this.buttonBackground);\n    }\n\n    protected onPointerUp(): void {\n        if (\n            this.state === AutoplayPopupButtonStatesMaxBet.Disabled ||\n            this.state === AutoplayPopupButtonStatesMaxBet.Selected\n        ) {\n            return;\n        }\n        this.state = AutoplayPopupButtonStatesMaxBet.Over;\n    }\n\n    protected onPointerOver(): void {\n        if (\n            this.state === AutoplayPopupButtonStatesMaxBet.Disabled ||\n            this.state === AutoplayPopupButtonStatesMaxBet.Selected\n        ) {\n            return;\n        }\n        this.state = AutoplayPopupButtonStatesMaxBet.Over;\n    }\n\n    protected onPointerTap(): void {\n        if (\n            this.state === AutoplayPopupButtonStatesMaxBet.Disabled ||\n            this.state === AutoplayPopupButtonStatesMaxBet.Selected\n        ) {\n            return;\n        }\n        this.CLICK.next(this);\n    }\n\n    protected getTexture(): AutoplayPopupButtonTexturesMaxBet {\n        return this.textures;\n    }\n\n    protected addInfinitySign(): void {\n        this.infinitySign = new Sprite(Core.assets.getAsset('svgInfinity').texture);\n        this.infinitySign.anchor.set(0.5);\n        this.infinitySign.x = this.width / 2;\n        this.infinitySign.y = this.height / 2;\n        this.addChild(this.infinitySign);\n    }\n\n    get state(): AutoplayPopupButtonStatesMaxBet {\n        return this._state;\n    }\n    set state(state: AutoplayPopupButtonStatesMaxBet) {\n        this._state = state;\n        this.buttonBackground.cursor = 'normal';\n        switch (state) {\n            case AutoplayPopupButtonStatesMaxBet.Normal:\n                this.buttonBackground.texture = this.textures.normalTexture;\n                break;\n            case AutoplayPopupButtonStatesMaxBet.Over:\n                this.buttonBackground.cursor = 'pointer';\n                if (this.textures.overTexture) {\n                    this.buttonBackground.texture = this.textures.overTexture;\n                } else {\n                    this.buttonBackground.texture = this.textures.normalTexture;\n                }\n                break;\n            case AutoplayPopupButtonStatesMaxBet.Selected:\n                this.buttonBackground.texture = this.textures.selectedTexture;\n                break;\n            case AutoplayPopupButtonStatesMaxBet.Disabled:\n                if (this.textures.disabledTexture) {\n                    this.buttonBackground.texture = this.textures.disabledTexture;\n                } else {\n                    this.buttonBackground.texture = this.textures.normalTexture;\n                }\n                break;\n        }\n    }\n}\n","import {\n    AssetPriority,\n    AssetsCollection,\n    BaseComponentConfiguration,\n    DefaultAssets,\n    DefaultValue,\n    DynamicPositionObject,\n} from '@egt/core';\nimport {\n    IContainerGraphicsInterfaceMaxBet,\n    IInputFieldObject,\n    IKeyboardButtonTextConfigMaxBet,\n    IKeyboardButtonsContainerPositionMaxBet,\n    IKeyboardContainerPositionMaxBet,\n    IKeyboardScaleConfigMaxBet,\n    IPopUpButtonInterfaceMaxBet,\n} from '@egt/ui-lib';\nimport { TextStyle } from 'pixi.js';\nimport {\n    IAutoPlayArrowPositionsMaxBet,\n    IAutoPlayPositionsMaxBet,\n    IAutoPlaySelectedBtnPositionsMaxBet,\n    IAutoplayBtnTextMaxBet,\n    // ISliderPositionObject,\n    IAutoplayKeyboardButtonPositionMaxBet,\n    IAutoplayPopUpMandatoryTextMaxBet,\n    IAutoplayPopUpShadowMaxBet,\n    IAutoplayPopUpTextMaxBet,\n    IAutoplayPopUpTitleTextMaxBet,\n    IAutoplayPopupConfigurationMaxBet,\n    IAutoplayPositionObjectMaxBet,\n    ICurvePositionObjectMaxBet,\n    IMainContainerPositionMaxBet,\n    ITextContainerMaxBet,\n} from '../interfaces/InterfacesMaxBet';\n\nexport default class AutoplayPopupComponentConfigurationMaxBet extends BaseComponentConfiguration {}\nexport function AutoplayPopupConfigFactoryMaxBet(): any {\n    class AutoplayPopupComponentConfigurationMaxBetInternalClass\n        extends AutoplayPopupComponentConfigurationMaxBet\n        implements IAutoplayPopupConfigurationMaxBet\n    {\n        public buttonsToHide = ['betButtons', 'autoPlayButton'];\n\n        public mainViewComponentsToHide = ['balanceContainer', 'winContainer'];\n\n        @DefaultAssets([\n            {\n                id: 'autoplayResources',\n                url: '../assets/components/slot/autoplay-popup/max-bet/autoplayResources.json',\n                priority: AssetPriority.HIGHEST,\n                type: 'texture',\n            },\n            {\n                id: 'svgAutoplaySelected',\n                url: '../assets/components/slot/autoplay-popup/max-bet/ui-svg/autoplaySelected.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 135, height: 76 },\n                },\n            },\n            {\n                id: 'svgSliderDotActive',\n                url: '../assets/components/slot/autoplay-popup/common/ui-svg/sliderDotActive.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 74, height: 74 },\n                    desktop: { width: 74, height: 74 },\n                },\n            },\n            {\n                id: 'svgSliderDotInactive',\n                url: '../assets/components/slot/autoplay-popup/common/ui-svg/sliderDotInactive.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 74, height: 74 },\n                    desktop: { width: 74, height: 74 },\n                },\n            },\n            {\n                id: 'svgSliderDotPressed',\n                url: '../assets/components/slot/autoplay-popup/common/ui-svg/sliderDotPressed.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 74, height: 74 },\n                    desktop: { width: 74, height: 74 },\n                },\n            },\n            {\n                id: 'svgSliderDotHover',\n                url: '../assets/components/slot/autoplay-popup/common/ui-svg/sliderDotHover.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 74, height: 74 },\n                    desktop: { width: 74, height: 74 },\n                },\n            },\n            {\n                id: 'svgAutoplayPopUpHover',\n                url: '../assets/components/slot/autoplay-popup/max-bet/ui-svg/autoplayPopUpHover.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 104, height: 74 },\n                    desktop: { width: 104, height: 74 },\n                },\n            },\n            {\n                id: 'svgAutoplayPopUpNormal',\n                url: '../assets/components/slot/autoplay-popup/max-bet/ui-svg/autoplayPopUpNormal.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 104, height: 74 },\n                    desktop: { width: 104, height: 74 },\n                },\n            },\n            {\n                id: 'svgAutoplayPopUpSelected',\n                url: '../assets/components/slot/autoplay-popup/max-bet/ui-svg/autoplayPopUpSelected.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 104, height: 74 },\n                    desktop: { width: 104, height: 74 },\n                },\n            },\n            {\n                id: 'svgAutoplayStartDisabled',\n                url: '../assets/components/slot/autoplay-popup/max-bet/ui-svg/autoplayStartDisabled.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 174, height: 70 },\n                    desktop: { width: 174, height: 70 },\n                },\n            },\n            {\n                id: 'svgAutoplayStartHover',\n                url: '../assets/components/slot/autoplay-popup/max-bet/ui-svg/autoplayStartHover.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 174, height: 70 },\n                    desktop: { width: 174, height: 70 },\n                },\n            },\n            {\n                id: 'svgAutoplayStartNormal',\n                url: '../assets/components/slot/autoplay-popup/max-bet/ui-svg/autoplayStartNormal.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 174, height: 70 },\n                    desktop: { width: 174, height: 70 },\n                },\n            },\n            {\n                id: 'infinityIcon',\n                url: '../assets/components/slot/autoplay-popup/max-bet/ui-svg/infinityIcon.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 71, height: 34 },\n                    desktop: { width: 71, height: 34 },\n                },\n            },\n            {\n                id: 'infinityIconSelected',\n                url: '../assets/components/slot/autoplay-popup/max-bet/ui-svg/infinityIconSelected.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 71, height: 34 },\n                    desktop: { width: 71, height: 34 },\n                },\n            },\n            {\n                id: 'svgClose',\n                url: '../assets/components/slot/autoplay-popup/max-bet/ui-svg/keyboardCancelBtn.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 174, height: 70 },\n                    desktop: { width: 174, height: 70 },\n                },\n            },\n            {\n                id: 'svgButtonDone',\n                url: '../assets/components/slot/autoplay-popup/max-bet/ui-svg/keyboardConfirmBtn.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 174, height: 70 },\n                    desktop: { width: 174, height: 70 },\n                },\n            },\n            {\n                id: 'svgButtonStandard',\n                url: '../assets/components/slot/autoplay-popup/max-bet/ui-svg/keyboardBtn.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 224, height: 90 },\n                    desktop: { width: 224, height: 90 },\n                },\n            },\n            {\n                id: 'svgButtonDot',\n                url: '../assets/components/slot/autoplay-popup/max-bet/ui-svg/keyboardDotBnt.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 224, height: 90 },\n                    desktop: { width: 224, height: 90 },\n                },\n            },\n            {\n                id: 'svgButtonClear',\n                url: '../assets/components/slot/autoplay-popup/max-bet/ui-svg/keyboardClearBnt.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 224, height: 90 },\n                    desktop: { width: 224, height: 90 },\n                },\n            },\n        ])\n        public assets: AssetsCollection;\n\n        @DefaultValue<IMainContainerPositionMaxBet>({\n            defaults: {\n                x: 0,\n                y: 0,\n                leftHandX: -276,\n            },\n        })\n        public mainContainerPosition: DynamicPositionObject<IMainContainerPositionMaxBet> &\n            IMainContainerPositionMaxBet;\n\n        @DefaultValue<ICurvePositionObjectMaxBet>({\n            defaults: {\n                x: 146,\n                y: 981,\n            },\n        })\n        public curvePosition: DynamicPositionObject<ICurvePositionObjectMaxBet> & ICurvePositionObjectMaxBet;\n\n        @DefaultValue<IAutoplayPopUpTitleTextMaxBet>({\n            defaults: {\n                yOffset: 30,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    fontSize: 38,\n                    fill: '#FFFFFF',\n                    trim: true,\n                    fontWeight: '800',\n                    align: 'center',\n                }),\n            },\n            portrait: {\n                yOffset: 33,\n            },\n        })\n        public popUpTitle: DynamicPositionObject<IAutoplayPopUpTitleTextMaxBet> & IAutoplayPopUpTitleTextMaxBet;\n\n        // @DefaultValue<IBalanceAndBetTextMaxBet>({\n        //     defaults: {\n        //         x: 466,\n        //         y: 695,\n        //         textStyle: new TextStyle({\n        //             fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n        //             align: 'left',\n        //             fill: '#FFD200',\n        //             fontSize: 24,\n        //             lineJoin: 'round',\n        //             miterLimit: 0,\n        //             textBaseline: 'middle',\n        //             padding: 4,\n        //         }),\n        //         valueStyle: new TextStyle({\n        //             fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n        //             align: 'left',\n        //             fill: '#FFFFFF',\n        //             fontSize: 36,\n        //             lineJoin: 'round',\n        //             miterLimit: 0,\n        //             textBaseline: 'middle',\n        //             padding: 4,\n        //         }),\n        //         currencyStyle: new TextStyle({\n        //             fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n        //             align: 'left',\n        //             fill: '#FFFFFF',\n        //             fontSize: 22,\n        //             lineJoin: 'round',\n        //             miterLimit: 0,\n        //             textBaseline: 'middle',\n        //             padding: 4,\n        //         }),\n        //     },\n        //     portrait: {\n        //         x: 31,\n        //         y: 916,\n        //     },\n        // })\n        // public balanceText: DynamicPositionObject<IBalanceAndBetTextMaxBet> & IBalanceAndBetTextMaxBet;\n\n        // @DefaultValue<IBalanceAndBetTextMaxBet>({\n        //     defaults: {\n        //         x: 1169,\n        //         y: 695,\n        //         textStyle: new TextStyle({\n        //             fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n        //             align: 'left',\n        //             fill: '#FFD200',\n        //             fontSize: 24,\n        //             lineJoin: 'round',\n        //             miterLimit: 0,\n        //             textBaseline: 'middle',\n        //             padding: 4,\n        //         }),\n        //         valueStyle: new TextStyle({\n        //             fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n        //             align: 'left',\n        //             fill: '#FFFFFF',\n        //             fontSize: 36,\n        //             lineJoin: 'round',\n        //             miterLimit: 0,\n        //             textBaseline: 'middle',\n        //             padding: 4,\n        //         }),\n        //         currencyStyle: new TextStyle({\n        //             fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n        //             align: 'left',\n        //             fill: '#FFFFFF',\n        //             fontSize: 22,\n        //             lineJoin: 'round',\n        //             miterLimit: 0,\n        //             textBaseline: 'middle',\n        //             padding: 4,\n        //         }),\n        //     },\n        //     portrait: {\n        //         x: 734,\n        //         y: 916,\n        //     },\n        // })\n        // public betText: DynamicPositionObject<IBalanceAndBetTextMaxBet> & IBalanceAndBetTextMaxBet;\n\n        @DefaultValue<IAutoplayPopUpTextMaxBet>({\n            defaults: {\n                x: 634,\n                y: 79,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    fontSize: 33,\n                    lineHeight: 30,\n                    fill: '#FFD200',\n                    align: 'center',\n                    trim: true,\n                }),\n            },\n            portrait: {\n                x: 382,\n                y: 400,\n            },\n        })\n        public stopOnTitle: DynamicPositionObject<IAutoplayPopUpTextMaxBet> & IAutoplayPopUpTextMaxBet;\n\n        @DefaultValue<IAutoplayPopUpTextMaxBet>({\n            defaults: {\n                x: 634,\n                y: 505,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    fontSize: 33,\n                    fill: '#FFD200',\n                    align: 'center',\n                    trim: true,\n                }),\n            },\n            portrait: {\n                x: 382,\n                y: 836,\n            },\n        })\n        public autoplayTitle: DynamicPositionObject<IAutoplayPopUpTextMaxBet> & IAutoplayPopUpTextMaxBet;\n\n        @DefaultValue<IAutoplayBtnTextMaxBet>({\n            defaults: {\n                xOffset: 2,\n                yOffset: 4,\n                width: 136,\n                height: 72,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    fontSize: 48,\n                    fill: '#C6C5C5',\n                    align: 'center',\n                }),\n                selectedTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    fontSize: 48,\n                    fill: '#FFFFFF',\n                    align: 'center',\n                }),\n            },\n        })\n        public buttonValueText: DynamicPositionObject<IAutoplayBtnTextMaxBet> & IAutoplayBtnTextMaxBet;\n\n        @DefaultValue<IAutoPlayPositionsMaxBet>({\n            defaults: {\n                x: 286,\n                y: 543,\n            },\n            portrait: {\n                x: 34,\n                y: 874,\n            },\n        })\n        public buttonsContainerPositions: DynamicPositionObject<IAutoPlayPositionsMaxBet> & IAutoPlayPositionsMaxBet;\n\n        @DefaultValue<IAutoplayPositionObjectMaxBet>({\n            defaults: {\n                width: 808,\n                height: 730,\n                x: 230,\n                y: 21,\n            },\n            portrait: {\n                width: 748,\n                height: 659,\n                x: 8,\n                y: 325,\n            },\n        })\n        public popUpGraphicsContainer: DynamicPositionObject<IAutoplayPositionObjectMaxBet> &\n            IAutoplayPositionObjectMaxBet;\n\n        @DefaultValue<IAutoplayPositionObjectMaxBet>({\n            defaults: {\n                width: 704,\n                height: 334,\n                x: 466,\n                y: 78,\n            },\n            portrait: {\n                x: 30,\n                y: 300,\n            },\n        })\n        public popUpFirstSectionPosition: DynamicPositionObject<IAutoplayPositionObjectMaxBet> &\n            IAutoplayPositionObjectMaxBet;\n\n        @DefaultValue<IAutoplayPositionObjectMaxBet>({\n            defaults: {\n                width: 704,\n                height: 139,\n                x: 466,\n                y: 423,\n            },\n            portrait: {\n                x: 30,\n                y: 644,\n            },\n        })\n        public popUpSecondSectionPosition: DynamicPositionObject<IAutoplayPositionObjectMaxBet> &\n            IAutoplayPositionObjectMaxBet;\n\n        @DefaultValue<IAutoplayPopUpTextMaxBet>({\n            defaults: {\n                x: 0,\n                y: -20,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                    fontSize: 36,\n                    fill: '#FFFFFF',\n                    align: 'center',\n                }),\n            },\n        })\n        public buttonNormalText: DynamicPositionObject<IAutoplayPopUpTextMaxBet> & IAutoplayPopUpTextMaxBet;\n\n        @DefaultValue<IAutoplayPopUpTextMaxBet>({\n            defaults: {\n                x: 0,\n                y: -20,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                    fontSize: 36,\n                    fill: '#818c86',\n                    align: 'center',\n                }),\n            },\n        })\n        public buttonDisabledText: DynamicPositionObject<IAutoplayPopUpTextMaxBet> & IAutoplayPopUpTextMaxBet;\n\n        @DefaultValue<IAutoPlayPositionsMaxBet>({\n            defaults: {\n                x: 547,\n                y: 647,\n            },\n            portrait: {\n                x: 295,\n                y: 976,\n            },\n        })\n        public startAutoplayBtn: DynamicPositionObject<IAutoPlayPositionsMaxBet> & IAutoPlayPositionsMaxBet;\n\n        @DefaultValue<IPopUpButtonInterfaceMaxBet>({\n            defaults: {\n                x: 532,\n                y: 669,\n            },\n            portrait: {\n                x: 532,\n                y: 669,\n            },\n        })\n        public doneBtn: DynamicPositionObject<IPopUpButtonInterfaceMaxBet> & IPopUpButtonInterfaceMaxBet;\n\n        @DefaultValue<IPopUpButtonInterfaceMaxBet>({\n            defaults: {\n                x: 62,\n                y: 669,\n            },\n        })\n        public cancelBtn: DynamicPositionObject<IPopUpButtonInterfaceMaxBet> & IPopUpButtonInterfaceMaxBet;\n\n        @DefaultValue<IAutoPlayArrowPositionsMaxBet>({\n            defaults: {\n                x: 800,\n                y: 127,\n                angle: 270,\n                leftHandX: 174,\n                leftHandY: 76,\n                leftHandAngle: 90,\n            },\n            portrait: {\n                x: 200,\n                y: 933,\n                angle: 0,\n            },\n            desktop: {\n                y: 228,\n            },\n        })\n        public arrowPosition: DynamicPositionObject<IAutoPlayArrowPositionsMaxBet> & IAutoPlayArrowPositionsMaxBet;\n\n        @DefaultValue<IAutoPlaySelectedBtnPositionsMaxBet>({\n            defaults: {\n                x: 1124,\n                y: 127,\n                leftHandX: -10,\n                scale: 1,\n            },\n            portrait: {\n                x: 206,\n                y: 1226,\n                scale: 1,\n            },\n            desktop: {\n                x: 1124,\n                y: 127,\n                scale: 1,\n            },\n        })\n        selectedButton: DynamicPositionObject<IAutoPlaySelectedBtnPositionsMaxBet> &\n            IAutoPlaySelectedBtnPositionsMaxBet;\n\n        @DefaultValue<IInputFieldObject>({\n            defaults: {\n                containerX: 286,\n                containerY: 115,\n                fieldWidth: 235,\n                fieldHeight: 80,\n                fieldX: 436,\n                fieldY: 0,\n                titleX: 0,\n                titleY: 12,\n                underTitleX: 0,\n                underTitleY: 52,\n                errorFill: '#FF0000',\n                titleTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial',\n                    fontSize: 36,\n                    fill: '#FFFFFF',\n                    fontWeight: '500',\n                    trim: true,\n                }),\n                titleTextMaxWidth: 415,\n                underTitleTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Book, Arial',\n                    fontSize: 24,\n                    fill: '#C6C5C5',\n                    fontWeight: '400',\n                }),\n                fieldNormalTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial',\n                    fontSize: 42,\n                    fontWeight: '800',\n                    fill: '#C6C5C5',\n                    trim: true,\n                }),\n                fieldHilightedTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial',\n                    fontSize: 42,\n                    fontWeight: '800',\n                    fill: '#FFFFFF',\n                    trim: true,\n                }),\n                currencyNormaTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial',\n                    fontWeight: '500',\n                    fontSize: 20,\n                    fill: '#C6C5C5',\n                    trim: true,\n                }),\n                currencyHilightedTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial',\n                    fontWeight: '500',\n                    fontSize: 20,\n                    fill: '#FFFFFF',\n                    trim: true,\n                }),\n            },\n            portrait: {\n                containerX: 34,\n                containerY: 433,\n            },\n        })\n        public maxLossAmountContainerConfig: DynamicPositionObject<IInputFieldObject> & IInputFieldObject;\n\n        @DefaultValue<IInputFieldObject>({\n            defaults: {\n                containerX: 286,\n                containerY: 211,\n                fieldWidth: 235,\n                fieldHeight: 60,\n                fieldX: 436,\n                fieldY: 0,\n                titleX: 0,\n                titleY: 12,\n                underTitleX: 0,\n                underTitleY: 52,\n                errorFill: '#FF0000',\n                titleTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial',\n                    fontSize: 36,\n                    fill: '#FFFFFF',\n                    fontWeight: '500',\n                    trim: true,\n                }),\n                titleTextMaxWidth: 415,\n                underTitleTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Book, Arial',\n                    fontSize: 24,\n                    fill: '#C6C5C5',\n                    fontWeight: '400',\n                }),\n                fieldNormalTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial',\n                    fontSize: 42,\n                    fontWeight: '800',\n                    fill: '#C6C5C5',\n                }),\n                fieldHilightedTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial',\n                    fontSize: 42,\n                    fontWeight: '800',\n                    fill: '#FFFFFF',\n                }),\n                currencyNormaTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial',\n                    fontWeight: '500',\n                    fontSize: 20,\n                    fill: '#C6C5C5',\n                }),\n                currencyHilightedTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial',\n                    fontWeight: '500',\n                    fontSize: 20,\n                    fill: '#FFFFFF',\n                }),\n            },\n            portrait: {\n                containerX: 34,\n                containerY: 529,\n            },\n        })\n        public balanceLessThanContainerConfig: DynamicPositionObject<IInputFieldObject> & IInputFieldObject;\n\n        @DefaultValue<IInputFieldObject>({\n            defaults: {\n                containerX: 286,\n                containerY: 307,\n                fieldWidth: 235,\n                fieldHeight: 60,\n                fieldX: 436,\n                fieldY: 0,\n                titleX: 0,\n                titleY: 12,\n                underTitleX: 0,\n                underTitleY: 52,\n                errorFill: '#FF0000',\n                titleTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial',\n                    fontSize: 36,\n                    fill: '#FFFFFF',\n                    fontWeight: '500',\n                    trim: true,\n                }),\n                titleTextMaxWidth: 415,\n                underTitleTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Book, Arial',\n                    fontSize: 24,\n                    fill: '#C6C5C5',\n                    fontWeight: '400',\n                }),\n                fieldNormalTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial',\n                    fontSize: 42,\n                    fontWeight: '800',\n                    fill: '#C6C5C5',\n                }),\n                fieldHilightedTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial',\n                    fontSize: 42,\n                    fontWeight: '800',\n                    fill: '#FFFFFF',\n                }),\n                currencyNormaTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial',\n                    fontWeight: '500',\n                    fontSize: 20,\n                    fill: '#C6C5C5',\n                }),\n                currencyHilightedTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial',\n                    fontWeight: '500',\n                    fontSize: 20,\n                    fill: '#FFFFFF',\n                }),\n            },\n            portrait: {\n                containerX: 34,\n                containerY: 625,\n            },\n        })\n        public balanceMoreThanContainerConfig: DynamicPositionObject<IInputFieldObject> & IInputFieldObject;\n\n        @DefaultValue<IInputFieldObject>({\n            defaults: {\n                containerX: 286,\n                containerY: 403,\n                fieldWidth: 235,\n                fieldHeight: 60,\n                fieldX: 436,\n                fieldY: 0,\n                titleX: 0,\n                titleY: 12,\n                underTitleX: 0,\n                underTitleY: 52,\n                errorFill: '#FF0000',\n                titleTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial',\n                    fontSize: 36,\n                    fill: '#FFFFFF',\n                    fontWeight: '500',\n                    trim: true,\n                }),\n                titleTextMaxWidth: 415,\n                underTitleTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Book, Arial',\n                    fontSize: 24,\n                    fill: '#C6C5C5',\n                    fontWeight: '400',\n                }),\n                fieldNormalTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial',\n                    fontSize: 42,\n                    fontWeight: '800',\n                    fill: '#C6C5C5',\n                }),\n                fieldHilightedTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial',\n                    fontSize: 42,\n                    fontWeight: '800',\n                    fill: '#FFFFFF',\n                }),\n                currencyNormaTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial',\n                    fontWeight: '500',\n                    fontSize: 20,\n                    fill: '#C6C5C5',\n                }),\n                currencyHilightedTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial',\n                    fontWeight: '500',\n                    fontSize: 20,\n                    fill: '#FFFFFF',\n                }),\n            },\n            portrait: {\n                containerX: 34,\n                containerY: 721,\n            },\n        })\n        public winOverContainerConfig: DynamicPositionObject<IInputFieldObject> & IInputFieldObject;\n\n        @DefaultValue<IInputFieldObject>({\n            defaults: {\n                containerX: 34,\n                containerY: 17,\n                fieldWidth: 235,\n                fieldHeight: 80,\n                errorFill: '#FF0000',\n                fieldX: 435,\n                fieldY: 0,\n                titleX: 0,\n                titleY: 12,\n                underTitleX: 0,\n                underTitleY: 52,\n                titleTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial',\n                    fontSize: 36,\n                    fill: '#FFFFFF',\n                    fontWeight: '500',\n                    trim: true,\n                }),\n                titleTextMaxWidth: 415,\n                underTitleTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Book, Arial',\n                    fontSize: 24,\n                    fill: '#C6C5C5',\n                    fontWeight: '400',\n                    trim: true,\n                }),\n                fieldNormalTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial',\n                    fontSize: 42,\n                    fontWeight: '800',\n                    fill: '#C6C5C5',\n                    trim: true,\n                }),\n                fieldHilightedTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial',\n                    fontSize: 42,\n                    fontWeight: '800',\n                    fill: '#FFFFFF',\n                    trim: true,\n                }),\n                currencyNormaTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial',\n                    fontWeight: '500',\n                    fontSize: 20,\n                    fill: '#C6C5C5',\n                    trim: true,\n                }),\n                currencyHilightedTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial',\n                    fontWeight: '500',\n                    fontSize: 20,\n                    fill: '#FFFFFF',\n                    trim: true,\n                }),\n            },\n        })\n        public keyboardInputContainerConfig: DynamicPositionObject<IInputFieldObject> & IInputFieldObject;\n\n        @DefaultValue<IContainerGraphicsInterfaceMaxBet>({\n            defaults: {\n                backgroundWidth: 765,\n                backgroundHeight: 757,\n                backgroundColor: 0x000000,\n                titleColor: 0x181818,\n                titleHeight: 114,\n            },\n        })\n        public autoplayKeyboardContainerGraphicsConfig: DynamicPositionObject<IContainerGraphicsInterfaceMaxBet> &\n            IContainerGraphicsInterfaceMaxBet;\n\n        // @DefaultValue<IKeyboardShadowBackgroundConfigMaxBet>({\n        //     defaults: {\n        //         x: 0,\n        //         y: 761,\n        //         width: -260,\n        //         height: 619,\n        //     },\n        //     portrait: {\n        //         x: 0,\n        //         y: -260,\n        //         width: 765,\n        //         height: 619,\n        //     },\n        // })\n        // public numericKeyboardShadowBackground: DynamicPositionObject<IKeyboardShadowBackgroundConfigMaxBet> &\n        //     IKeyboardShadowBackgroundConfigMaxBet;\n\n        // @DefaultValue<IBalanceAndBetTextMaxBet>({\n        //     defaults: {\n        //         x: 78,\n        //         y: 347,\n        //         textStyle: new TextStyle({\n        //             fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n        //             align: 'left',\n        //             fill: '#FFD200',\n        //             fontSize: 24,\n        //             lineJoin: 'round',\n        //             miterLimit: 0,\n        //             textBaseline: 'middle',\n        //             padding: 4,\n        //         }),\n        //         valueStyle: new TextStyle({\n        //             fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n        //             align: 'left',\n        //             fill: '#FFFFFF',\n        //             fontSize: 36,\n        //             lineJoin: 'round',\n        //             miterLimit: 0,\n        //             textBaseline: 'middle',\n        //             padding: 4,\n        //         }),\n        //         currencyStyle: new TextStyle({\n        //             fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n        //             align: 'left',\n        //             fill: '#FFFFFF',\n        //             fontSize: 22,\n        //             lineJoin: 'round',\n        //             miterLimit: 0,\n        //             textBaseline: 'middle',\n        //             padding: 4,\n        //         }),\n        //     },\n        //     portrait: {\n        //         x: 30,\n        //         y: 467,\n        //     },\n        // })\n        // public balanceTextKeyboard: IBalanceAndBetTextMaxBet;\n\n        // @DefaultValue<IBalanceAndBetTextMaxBet>({\n        //     defaults: {\n        //         x: 649,\n        //         y: 347,\n        //         textStyle: new TextStyle({\n        //             fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n        //             align: 'left',\n        //             fill: '#FFD200',\n        //             fontSize: 24,\n        //             lineJoin: 'round',\n        //             miterLimit: 0,\n        //             textBaseline: 'middle',\n        //             padding: 4,\n        //         }),\n        //         valueStyle: new TextStyle({\n        //             fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n        //             align: 'left',\n        //             fill: '#FFFFFF',\n        //             fontSize: 36,\n        //             lineJoin: 'round',\n        //             miterLimit: 0,\n        //             textBaseline: 'middle',\n        //             padding: 4,\n        //         }),\n        //         currencyStyle: new TextStyle({\n        //             fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n        //             align: 'left',\n        //             fill: '#FFFFFF',\n        //             fontSize: 22,\n        //             lineJoin: 'round',\n        //             miterLimit: 0,\n        //             textBaseline: 'middle',\n        //             padding: 4,\n        //         }),\n        //     },\n        //     portrait: {\n        //         x: 710,\n        //         y: 463,\n        //     },\n        // })\n        // public betTextKeyboard: IBalanceAndBetTextMaxBet;\n\n        @DefaultValue<IKeyboardButtonsContainerPositionMaxBet>({\n            defaults: {\n                x: 32,\n                y: 144,\n            },\n        })\n        public numericKeyboardButtonsContainerPosition: DynamicPositionObject<IKeyboardButtonsContainerPositionMaxBet> &\n            IKeyboardButtonsContainerPositionMaxBet;\n\n        @DefaultValue<IKeyboardContainerPositionMaxBet>({\n            defaults: {\n                x: 298,\n                y: 4,\n            },\n            portrait: {\n                x: 0,\n                y: 603,\n            },\n        })\n        public numericKeyboardContainerPosition: DynamicPositionObject<IKeyboardContainerPositionMaxBet> &\n            IKeyboardContainerPositionMaxBet;\n\n        @DefaultValue<IKeyboardButtonTextConfigMaxBet>({\n            defaults: {\n                width: 100,\n                height: 51,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Book, RobotoCondensed-Bold, Arial',\n                    fontSize: 60,\n                    fill: '#FFFFFF',\n                    align: 'center',\n                    fontWeight: '400',\n                }),\n            },\n        })\n        public numericKeyboardButtonText: DynamicPositionObject<IKeyboardButtonTextConfigMaxBet> &\n            IKeyboardButtonTextConfigMaxBet;\n\n        public numericKeyboardBtnPositions: Array<DynamicPositionObject<IAutoplayKeyboardButtonPositionMaxBet>> = [\n            new DynamicPositionObject<IAutoplayKeyboardButtonPositionMaxBet>({\n                defaults: { x: 0, y: 0 },\n            }),\n            new DynamicPositionObject<IAutoplayKeyboardButtonPositionMaxBet>({\n                defaults: { x: 236, y: 0 },\n            }),\n            new DynamicPositionObject<IAutoplayKeyboardButtonPositionMaxBet>({\n                defaults: { x: 472, y: 0 },\n            }),\n            new DynamicPositionObject<IAutoplayKeyboardButtonPositionMaxBet>({\n                defaults: { x: 0, y: 102 },\n            }),\n            new DynamicPositionObject<IAutoplayKeyboardButtonPositionMaxBet>({\n                defaults: { x: 236, y: 102 },\n            }),\n            new DynamicPositionObject<IAutoplayKeyboardButtonPositionMaxBet>({\n                defaults: { x: 472, y: 102 },\n            }),\n            new DynamicPositionObject<IAutoplayKeyboardButtonPositionMaxBet>({\n                defaults: { x: 0, y: 204 },\n            }),\n            new DynamicPositionObject<IAutoplayKeyboardButtonPositionMaxBet>({\n                defaults: { x: 236, y: 204 },\n            }),\n            new DynamicPositionObject<IAutoplayKeyboardButtonPositionMaxBet>({\n                defaults: { x: 472, y: 204 },\n            }),\n            new DynamicPositionObject<IAutoplayKeyboardButtonPositionMaxBet>({\n                defaults: { x: 0, y: 306 },\n            }),\n            new DynamicPositionObject<IAutoplayKeyboardButtonPositionMaxBet>({\n                defaults: { x: 236, y: 306 },\n            }),\n            new DynamicPositionObject<IAutoplayKeyboardButtonPositionMaxBet>({\n                defaults: { x: 472, y: 306 },\n            }),\n        ];\n\n        public numericKeyboardButtonValues: string[] = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '0', '<'];\n\n        @DefaultValue<IKeyboardScaleConfigMaxBet>({\n            defaults: { scale: 1 },\n            portrait: { scale: 1.34 },\n        })\n        public numericKeyboardScale: DynamicPositionObject<IKeyboardScaleConfigMaxBet> & IKeyboardScaleConfigMaxBet;\n\n        @DefaultValue<IAutoplayPopUpMandatoryTextMaxBet>({\n            defaults: {\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                    fontSize: 26,\n                    lineHeight: 30,\n                    fill: '#FF0000',\n                    align: 'right',\n                }),\n            },\n        })\n        public mandatoryText: DynamicPositionObject<IAutoplayPopUpMandatoryTextMaxBet> &\n            IAutoplayPopUpMandatoryTextMaxBet;\n\n        @DefaultValue<ITextContainerMaxBet>({\n            defaults: {\n                x: 386,\n                y: 639,\n                maxWidth: 288,\n                currencyTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                    align: 'center',\n                    fill: '#C6C5C5',\n                    fontSize: 22,\n                    lineJoin: 'round',\n                    trim: true,\n                }),\n                valueTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'center',\n                    fill: '#FFFFFF',\n                    fontSize: 48,\n                    stroke: '#FFFFFF',\n                    strokeThickness: 0.07,\n                    trim: true,\n                }),\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'center',\n                    fill: '#FFD200',\n                    fontSize: 33,\n                    lineJoin: 'round',\n                    trim: true,\n                }),\n            },\n            portrait: {\n                x: 110,\n                y: 999,\n                maxWidth: 201,\n            },\n        })\n        balanceContainerStyle: DynamicPositionObject<ITextContainerMaxBet> & ITextContainerMaxBet;\n\n        @DefaultValue<ITextContainerMaxBet>({\n            defaults: {\n                x: 874,\n                y: 639,\n                maxWidth: 288,\n                currencyTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                    align: 'center',\n                    fill: '#C6C5C5',\n                    fontSize: 22,\n                    lineJoin: 'round',\n                    trim: true,\n                }),\n                valueTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'center',\n                    fill: '#FFFFFF',\n                    fontSize: 48,\n                    stroke: '#FFFFFF',\n                    strokeThickness: 0.07,\n                    trim: true,\n                }),\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'center',\n                    fill: '#FFD200',\n                    fontSize: 33,\n                    lineJoin: 'round',\n                    trim: true,\n                }),\n            },\n            portrait: {\n                x: 654,\n                y: 999,\n                maxWidth: 201,\n            },\n        })\n        totalBetContainerStyle: DynamicPositionObject<ITextContainerMaxBet> & ITextContainerMaxBet;\n\n        @DefaultValue<ITextContainerMaxBet>({\n            defaults: {\n                x: 146,\n                y: 552,\n                maxWidth: 286,\n                currencyTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                    align: 'center',\n                    fill: '#C6C5C5',\n                    fontSize: 22,\n                    lineJoin: 'round',\n                    trim: true,\n                }),\n                valueTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'center',\n                    fill: '#FFFFFF',\n                    fontSize: 48,\n                    lineJoin: 'round',\n                    trim: true,\n                }),\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'center',\n                    fill: '#FFD200',\n                    fontSize: 33,\n                    lineJoin: 'round',\n                    trim: true,\n                }),\n            },\n        })\n        keyboardBalanceContainerStyle: DynamicPositionObject<ITextContainerMaxBet> & ITextContainerMaxBet;\n\n        @DefaultValue<ITextContainerMaxBet>({\n            defaults: {\n                x: 619,\n                y: 552,\n                maxWidth: 286,\n                currencyTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                    align: 'center',\n                    fill: '#C6C5C5',\n                    fontSize: 22,\n                    lineJoin: 'round',\n                    trim: true,\n                }),\n                valueTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'center',\n                    fill: '#FFFFFF',\n                    fontSize: 48,\n                    lineJoin: 'round',\n                    trim: true,\n                }),\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'center',\n                    fill: '#FFD200',\n                    fontSize: 33,\n                    lineJoin: 'round',\n                    trim: true,\n                }),\n            },\n        })\n        keyboardTotalBetContainerStyle: DynamicPositionObject<ITextContainerMaxBet> & ITextContainerMaxBet;\n\n        @DefaultValue<IAutoplayPopUpShadowMaxBet>({\n            defaults: {\n                width: 1130,\n                height: 1200,\n                x: 120,\n                y: -200,\n            },\n            portrait: {\n                x: 0,\n                y: 930,\n                width: 765,\n                height: 242,\n            },\n        })\n        public popUpShadow: DynamicPositionObject<IAutoplayPopUpShadowMaxBet> & IAutoplayPopUpShadowMaxBet;\n    }\n    return AutoplayPopupComponentConfigurationMaxBetInternalClass;\n}\n","import Core, { BaseController, ErrorTypes, IErrorData } from '@egt/core';\nimport { FeatureController, InitialSettings, RootStore, SlotComponents, ZOrders } from '@egt/slot';\nimport { fromEvent, merge } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport AutoplayPopupButtonMaxBet from '../buttons/AutoplayPopupSettingButtonMaxBet';\nimport { IAutoplayPopupConfigurationMaxBet } from '../interfaces/InterfacesMaxBet';\nimport AutoplayPopupViewMaxBet from '../views/AutoplayPopupViewMaxBet';\nimport { InputField } from '@egt/ui-lib';\nimport AutoplayPopupShadowViewMaxBet from '../views/AutoplayPopupShadowViewMaxBet';\n\n@injectable()\nexport default class AutoplayPopupControllerMaxBet extends BaseController {\n    private numberOfAutoPlays: number;\n    private activeInputField: InputField | null = null;\n\n    constructor(\n        @inject('AutoplayPopupView') protected view: AutoplayPopupViewMaxBet,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('AutoplayPopupComponentConfiguration')\n        protected componentConfiguration: IAutoplayPopupConfigurationMaxBet,\n        @inject('AutoplayPopupShadowView') protected autoplayPopUpShadowView: AutoplayPopupShadowViewMaxBet,\n        @inject('FeatureController') protected featureController: FeatureController,\n    ) {\n        super(view);\n    }\n\n    public init(): void {\n        if (!this.settings.autoplay) {\n            return;\n        }\n        this.attachEventListeners();\n    }\n\n    public attachEventListeners(): void {\n        this.rootStore.uiStore.BALANCE.pipe(takeUntil(this.DESTROY)).subscribe(this.onBalanceChanged.bind(this));\n        this.rootStore.uiStore.SELECTED_BET.pipe(takeUntil(this.DESTROY)).subscribe(this.onBetChanged.bind(this));\n        Core.SELECTED_DENOMINATION.pipe(takeUntil(this.DESTROY)).subscribe(this.onBetChanged.bind(this));\n        this.rootStore.subjects.TOGGLE_AUTOPLAY_POPUP.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.toggleAutoplayPopup.bind(this),\n        );\n        this.rootStore.subjects.CLOSE_ALL_POPUPS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.forceClosePopup.bind(this),\n        );\n        const closeFlow = merge(this.DESTROY, this.rootStore.subjects.CLOSE_AUTOPLAY_POPUP);\n        closeFlow.pipe(takeUntil(closeFlow)).subscribe(this.closePopup.bind(this, false));\n\n        this.view.CLOSE.pipe(takeUntil(this.DESTROY)).subscribe(this.closePopup.bind(this, true));\n        this.rootStore.subjects.MODAL_PRESSED.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.closePopup(true);\n            this.view.hideNumericKeyboardField(true);\n        });\n\n        this.rootStore.subjects.FACTOR_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(this.onFactorChanged.bind(this));\n\n        this.rootStore.subjects.RESET_AUTOPLAY_RESTRICTIONS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.resetAutoPlayRestrictions.bind(this),\n        );\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/max-bet/controllers/AutoplayPopupControllerMaxBet.ts:61:9\",(this.view.selectedBtn),\"pointerup\"]), fromEvent(this.view.selectedBtn, 'pointerup'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(() => {\n                this.view.hideNumericKeyboardField(true);\n                this.closePopup(true);\n            });\n\n        this.view.startAutoplayButton.CLICK.pipe(takeUntil(this.DESTROY)).subscribe(this.startAutoplay.bind(this));\n\n        for (const btn of this.view.autoplayButtons) {\n            btn.CLICK.pipe(takeUntil(this.DESTROY)).subscribe(this.onChoseAutoPlayBtn.bind(this));\n        }\n\n        this.addInputFieldsEventListeners();\n        if (Core.isDesktopMode) {\n            this.rootStore.subjects.KEY_DOWN.pipe(takeUntil(this.DESTROY)).subscribe(this.onKeyDown.bind(this));\n        }\n    }\n\n    public destroy(): void {\n        super.destroy();\n    }\n\n    private handleInputFieldFocus(selectedField: InputField): void {\n        for (const field of this.view.inputFields) {\n            if (field === selectedField) {\n                field.setActive();\n                this.activeInputField = field;\n            } else {\n                // field.confirmValue();\n                field.setInactive();\n            }\n        }\n    }\n\n    private addInputFieldsEventListeners(): void {\n        for (const field of this.view.inputFields) {\n            field.FOCUS.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n                this.handleInputFieldFocus(field);\n                this.view.showNumericKeyboardField(field);\n            });\n        }\n    }\n\n    private onKeyDown = (e: KeyboardEvent) => {\n        if (e === null || !this.activeInputField) {\n            return;\n        }\n        if (/^[0-9.]$/.test(e.key)) {\n            const newValue = this.activeInputField.getValue() + e.key;\n            this.activeInputField.setValue(newValue);\n        } else if (e.key === 'Backspace') {\n            const value = this.activeInputField.getValue();\n            // const newValue = value.slice(0, -1);\n            this.activeInputField.setValue(value.slice(0, -1));\n\n            // if (newValue.length === 0) {\n            //     this.activeInputField.setInactive();\n            // }\n        }\n    };\n\n    protected startAutoplay(): void {\n        if (this.settings.settings.settings.jurisdiction?.autoplayRestrictions?.confirmationModal) {\n            const modalData = this.rootStore.getModalData(this.numberOfAutoPlays);\n            const messData = {} as IErrorData;\n\n            (messData.code = Core.translator\n                .translate('AUTOPLAY.MODAL.MESSAGE')\n                .replace('<<totalAmount>>', modalData.totalBetAmount.toString().replace(/\\s+/g, '\\u00A0'))\n\n                .replace('<<numberOfSpins>>', this.numberOfAutoPlays.toString())\n                .replace('<<betAmount>>', modalData.betAmount)),\n                (messData.btnText = Core.translator.translate('AUTOPLAY.MODAL.CANCEL_BUTTON')),\n                (messData.type = ErrorTypes.CONFIRMATION),\n                (messData.hasConfirmButton = true),\n                (messData.confirmButtonText = Core.translator.translate('AUTOPLAY.MODAL.CONFIRM_BUTTON')),\n                (messData.callback = this.confirmStartAutoplay.bind(this)),\n                Core.SHOW_ERROR.next(messData);\n            // Reset the button so it doesn't stay stuck on the over texture after the modal is declined.\n            this.view.startAutoplayButton.setNormal();\n            return;\n        }\n        this.confirmStartAutoplay();\n    }\n\n    protected confirmStartAutoplay(): void {\n        this.rootStore.uiStore.balanceIncreaseValue = this.view.balanceMore * 100;\n        this.rootStore.uiStore.balanceDecreaseValue = this.view.balanceLess * 100;\n        this.rootStore.uiStore.winLimitValue = this.view.winOver * 100;\n        if (!this.featureController.isInGiftSpins) {\n            this.rootStore.uiStore.maxTotalLossLimit = this.view.maxLoss * 100;\n        }\n\n        this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.next(this.numberOfAutoPlays);\n        this.forceClosePopup();\n        this.rootStore.subjects.START_AUTOPLAY.next(this.numberOfAutoPlays);\n        // this.autoplayNumericInputPopup.shouldSetUiStoreFieldValues = false;\n        this.view.resetInputFields();\n    }\n\n    protected resetAutoPlayRestrictions(): void {\n        this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.next(0);\n        this.rootStore.uiStore.autoPlayFromSettings = false;\n        // this.autoplayNumericInputPopup.shouldSetUiStoreFieldValues = true;\n        this.view.resetInputFields();\n    }\n\n    protected onFactorChanged(): void {\n        this.view.setBetValue();\n        this.view.updateUnderTitleTexts();\n    }\n\n    private onBalanceChanged(): void {\n        this.view.onBalanceChanged();\n        this.view.updateUnderTitleTexts();\n    }\n\n    private onBetChanged(): void {\n        this.view.setBetValue();\n        this.view.updateUnderTitleTexts();\n    }\n\n    private onChoseAutoPlayBtn(button: AutoplayPopupButtonMaxBet): void {\n        for (const btn of this.view.autoplayButtons) {\n            if (btn === button) {\n                Core.sounds.play('autoplaySelectSound');\n                btn.setSelected();\n                this.numberOfAutoPlays = button.numberOfAutoPlays;\n            } else {\n                btn.setNormal();\n            }\n        }\n    }\n\n    private toggleAutoplayPopup(): void {\n        if (this.view.isOpened) {\n            this.closePopup();\n        } else {\n            this.openPopup();\n        }\n    }\n\n    private closePopup(animation: boolean = true): void {\n        if (this.view.isOpened) {\n            Core.sounds.play('hideDenominationsSound');\n            this.toggleCustomButtons(true);\n            this.view.close(animation);\n            this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(false);\n            this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_OUTSIDE_BETS_VISIBLE.next(true);\n            this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_BTN_VISIBLE.next(true);\n            this.rootStore.subjects.BUY_BONUS_AND_DOUBLE_CHANCE_VISIBLE.next(ZOrders.MESSAGES_LEVEL + 3);\n            this.view.hideNumericKeyboardField(true);\n            this.autoplayPopUpShadowView.visible = false;\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'spinButton',\n                actions: ['enabled'],\n                values: true,\n            });\n            this.rootStore.subjects.ACTIVE_COMPONENT.next(\n                this.rootStore.subjects.ACTIVE_COMPONENT.value.filter(\n                    (component) => component !== SlotComponents.AUTOPLAY_POPUP,\n                ),\n            );\n            this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(false);\n        }\n    }\n\n    private forceClosePopup(): void {\n        if (this.view.isOpened) {\n            this.toggleCustomButtons(true);\n            this.view.forceClose();\n            this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(false);\n            this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_OUTSIDE_BETS_VISIBLE.next(true);\n            this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_BTN_VISIBLE.next(true);\n            this.rootStore.subjects.BUY_BONUS_AND_DOUBLE_CHANCE_VISIBLE.next(ZOrders.MESSAGES_LEVEL + 3);\n            this.view.hideNumericKeyboardField(true);\n            this.autoplayPopUpShadowView.visible = false;\n            this.rootStore.subjects.ACTIVE_COMPONENT.next(\n                this.rootStore.subjects.ACTIVE_COMPONENT.value.filter(\n                    (component) => component !== SlotComponents.AUTOPLAY_POPUP,\n                ),\n            );\n\n            // const activeComponents = this.rootStore.subjects.ACTIVE_COMPONENT.value;\n            // const denomIsOpen = activeComponents.includes(SlotComponents.DENOMINATION_POPUP);\n            // // const homeButtonIsClicked = activeComponents.includes(SlotComponents.HOME_BUTTON);\n            // if (denomIsOpen) return;\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'spinButton',\n                actions: ['enabled'],\n                values: true,\n            });\n            this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(false);\n        }\n    }\n\n    private openPopup(animation: boolean = true): void {\n        if (!this.view.isOpened) {\n            Core.sounds.play('showDenominationsSound');\n            this.rootStore.subjects.CLOSE_ALL_POPUPS.next();\n            this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(true);\n            this.view.open(animation);\n            this.numberOfAutoPlays = this.view.autoplayButtons[0].numberOfAutoPlays;\n            this.toggleCustomButtons(false);\n            this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(false);\n            this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_OUTSIDE_BETS_VISIBLE.next(false);\n            this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_BTN_VISIBLE.next(false);\n            this.rootStore.subjects.BUY_BONUS_AND_DOUBLE_CHANCE_VISIBLE.next(0);\n            this.autoplayPopUpShadowView.visible = true;\n            // this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            //     name: 'spinButton',\n            //     actions: ['enabled'],\n            //     values: false,\n            // });\n            const activeComponents = this.rootStore.subjects.ACTIVE_COMPONENT.value.concat([\n                SlotComponents.AUTOPLAY_POPUP,\n            ]);\n            this.rootStore.subjects.ACTIVE_COMPONENT.next(activeComponents);\n        }\n    }\n\n    protected toggleCustomButtons(visible: boolean): void {\n        this.componentConfiguration.buttonsToHide.forEach((btnName) => {\n            if (btnName === 'betButtons') {\n                this.rootStore.uiStore.SHOW_HIDE_BET_BUTTONS.next(visible);\n                if (this.featureController.isInGiftSpins) {\n                    this.rootStore.uiStore.SHOW_HIDE_GIFT_SPINS_VIEW.next(visible);\n                }\n            } else {\n                this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                    name: btnName,\n                    actions: 'visible',\n                    values: visible,\n                });\n            }\n        });\n\n        this.componentConfiguration.mainViewComponentsToHide.forEach((mainViewComponent) => {\n            this.rootStore.subjects.SHOW_HIDE_MAIN_VIEW_COMPONENTS.next({\n                name: mainViewComponent,\n                actions: 'visible',\n                values: visible,\n            });\n        });\n    }\n}\n\nexport enum MandatoryValues {\n    BALANCE_LES = 'lossLimits',\n    BALANCE_MORE = 'winLimits',\n    WIN_OVER = 'singleWinLimit',\n    MAX_LOSS = 'maxLoss',\n}\n","import Core from '@egt/core';\nimport { ViewContainer } from '@egt/ui-lib';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { Sprite } from 'pixi.js';\nimport { IAutoplayPopupConfigurationMaxBet } from '../interfaces/InterfacesMaxBet';\n\n@injectable()\nexport default class AutoplayPopupShadowViewMaxBet extends ViewContainer {\n    protected shadow: Sprite;\n\n    constructor(\n        @inject('AutoplayPopupComponentConfiguration')\n        protected componentConfiguration: IAutoplayPopupConfigurationMaxBet,\n    ) {\n        super();\n    }\n\n    public init(): void {\n        this.visible = false;\n        this.shadow = new Sprite(Core.assets.getTextureFromSpriteSheet('autoplayResources', 'shadow.png'));\n        this.shadow.name = 'shadow';\n        this.shadow.y = 930;\n        this.addChild(this.shadow);\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n    }\n\n    protected setOrientation(): void {\n        this.shadow.x = this.componentConfiguration.popUpShadow.x;\n        this.shadow.y = this.componentConfiguration.popUpShadow.y;\n        this.shadow.width = this.componentConfiguration.popUpShadow.width;\n        this.shadow.height = this.componentConfiguration.popUpShadow.height;\n    }\n\n    public destroy(): void {\n        super.destroy();\n    }\n}\n","import Core, { MoneyFormatter } from '@egt/core';\nimport { InitialSettings, RootStore } from '@egt/slot';\nimport { Button, ButtonShapes, IInputFieldObject, InputField, ViewContainer } from '@egt/ui-lib';\nimport { gsap } from 'gsap';\nimport { Container, NineSlicePlane, Sprite, Text, TextStyle } from 'pixi.js';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport AutoplayNumericInputPopupStartButtonTextures from '../buttons/AutoplayPopupButtonTexturesMaxBet';\nimport AutoplayNumericInputPopupButton from '../buttons/AutoplayPopupStartButtonMaxBet';\nimport AutoplayPopupButtonMaxBet from '../buttons/AutoplayPopupSettingButtonMaxBet';\nimport { MandatoryValues } from '../controllers/AutoplayPopupControllerMaxBet';\nimport { IAutoplayPopupConfigurationMaxBet } from '../interfaces/InterfacesMaxBet';\nimport { KeyboardMaxBet } from './KeyboardMaxBet';\n\n@injectable()\nexport default class AutoplayPopupViewMaxBet extends ViewContainer {\n    public CLOSE = new Subject();\n    // Main containers\n    public mainContainer: Container;\n    public graphicsContainer: Container;\n\n    // Popup buttons and actions\n    public autoplayButtons: AutoplayPopupButtonMaxBet[] = [];\n    public startAutoplayButton: AutoplayNumericInputPopupButton;\n    public buttonValues: number[];\n    public selectedBtn: Button;\n\n    // Popup values and limits\n    public maxLoss: number;\n    public balanceLess: number;\n    public balanceMore: number;\n    public winOver: number;\n\n    // Popup graphics and texts\n    private autoplayButtonsContainer: Sprite;\n    private popUpBackground: NineSlicePlane;\n    // private popUpShadow: NineSlicePlane;\n    // private popUpFirstSection: NineSlicePlane;\n    // private popUpSecondSection: NineSlicePlane;\n    private popUpTitleText: Text;\n    private stopOn: Text;\n    private autoplay: Text;\n    private curve: Sprite;\n\n    // Inputfields containers and fields\n    private mandatory: MandatoryValues[];\n    private maxLossAmountFieldContainer: ViewContainer;\n    private maxLossAmountField: InputField;\n    private balanceLessThanFieldContainer: ViewContainer;\n    private balanceLessThanField: InputField;\n    private balanceMoreThanFieldContainer: ViewContainer;\n    private balanceMoreThanField: InputField;\n    private winOverFieldContainer: ViewContainer;\n    private winOverField: InputField;\n    public inputFields: InputField[] = [];\n\n    private balanceTextContainer: Sprite;\n    private balanceCurrencyText: Text;\n    private balanceValueText: Text;\n    private balanceText: Text;\n\n    private totalBetTextContainer: Sprite;\n    private totalBetCurrencyText: Text;\n    private totalBetValueText: Text;\n    private totalBetText: Text;\n\n    // Balance and Bet text and containers\n    // private balanceContainer: Sprite;\n    // private balanceText: Text;\n    // private balanceTextValue: Text;\n    // private balanceTextCurrency: Text;\n    // private betContainer: Sprite;\n    // private betText: Text;\n    // private betTextValue: Text;\n    // private betTextCurrency: Text;\n    // private balanceMoneyFormatter: Money;\n    // private betMoneyFormatter: Money;\n    // private wordSpacing: number = 6;\n    private minBet: number = 0;\n\n    // Arrow\n    // private arrow: Sprite;\n    private _isOpened: boolean = false;\n    private animationTween: any;\n    private startingPoint: number = 250;\n    private bounceOffset: number = 15;\n\n    // Inpufields under titles\n    private maxLossUnderTitle: Text;\n    private balanceLessUnderTitle: Text;\n    private balanceMoreUnderTitle: Text;\n    private winOverUnderTitle: Text;\n    private titleTextsByFields: Map<string, { titleText: string; underTitleText: string }> = new Map();\n\n    // Keyboard\n    private numericKeyboard: KeyboardMaxBet;\n    private currentField: InputField;\n\n    //utility\n    // public shouldSetUiStoreFieldValues = true;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('AutoplayPopupComponentConfiguration')\n        protected componentConfiguration: IAutoplayPopupConfigurationMaxBet,\n    ) {\n        super();\n    }\n\n    public init(): void {\n        if (!this.settings.autoplay) {\n            return;\n        }\n        this.buttonValues = this.settings.settings.settings.jurisdiction.autoplayRestrictions.autoPlays;\n        this.mandatory = this.settings.autoplayRestrictions.mandatory;\n        this.createGraphicsContainer();\n        this.createMainContainer();\n        this.createSelectedBtn();\n        this.crateAutoplayPopUp();\n        this.close(false);\n        this.createBalanceText();\n        this.createTotalBetText();\n\n        Core.LEFT_HAND_MODE.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n\n        // Core.stage.stage.on('pointertap', this.onPopUpClick, this);\n    }\n\n    public destroy(): void {\n        this.killAllAnimations();\n        if (this.numericKeyboard) {\n            this.numericKeyboard.killNumericKeyboardTween();\n        }\n        this.destroyObject(this.mainContainer);\n        this.destroyObject(this.graphicsContainer);\n        this.destroyObject(this.startAutoplayButton);\n        this.destroyObject(this.selectedBtn);\n        this.destroyObject(this.autoplayButtonsContainer);\n        this.destroyObject(this.popUpBackground);\n        // this.destroyObject(this.popUpShadow);\n        // this.destroyObject(this.popUpFirstSection);\n        // this.destroyObject(this.popUpSecondSection);\n        this.destroyObject(this.popUpTitleText);\n        this.destroyObject(this.stopOn);\n        this.destroyObject(this.autoplay);\n        this.destroyObject(this.maxLossAmountFieldContainer);\n        this.destroyObject(this.balanceLessThanFieldContainer);\n        this.destroyObject(this.balanceMoreThanFieldContainer);\n        this.destroyObject(this.winOverFieldContainer);\n        this.destroyObject(this.maxLossAmountField);\n        this.destroyObject(this.balanceLessThanField);\n        this.destroyObject(this.balanceMoreThanField);\n        this.destroyObject(this.winOverField);\n        this.destroyObject(this.maxLossUnderTitle);\n        this.destroyObject(this.balanceLessUnderTitle);\n        this.destroyObject(this.balanceMoreUnderTitle);\n        this.destroyObject(this.winOverUnderTitle);\n        // this.destroyObject(this.balanceContainer);\n        // this.destroyObject(this.balanceText);\n        // this.destroyObject(this.balanceTextValue);\n        // this.destroyObject(this.balanceTextCurrency);\n        // this.destroyObject(this.betContainer);\n        // this.destroyObject(this.betText);\n        // this.destroyObject(this.betTextValue);\n        // this.destroyObject(this.betTextCurrency);\n        // this.destroyObject(this.balanceMoneyFormatter);\n        // this.destroyObject(this.betMoneyFormatter);\n        // this.destroyObject(this.arrow);\n        this.destroyArray(this.autoplayButtons);\n        this.destroyArray(this.buttonValues);\n        this.destroyArray(this.mandatory);\n        this.titleTextsByFields.clear();\n\n        this.removeChildren();\n        super.destroy();\n    }\n\n    public get isOpened(): boolean {\n        return this._isOpened;\n    }\n\n    public set isOpened(value: boolean) {\n        this._isOpened = value;\n    }\n\n    public setBetValue(): void {\n        if (this.totalBetValueText) {\n            const totalBet =\n                this.rootStore.uiStore.SELECTED_BET.value *\n                Core.SELECTED_DENOMINATION.value *\n                this.rootStore.settings.factor;\n            this.totalBetValueText.text = new MoneyFormatter(totalBet).stringMoney;\n            this.syncBalanceAndTotalBetTextScales();\n        }\n    }\n\n    public onBalanceChanged(): void {\n        if (this.balanceValueText) {\n            const balance = this.rootStore.uiStore.BALANCE.value;\n            this.balanceValueText.text = new MoneyFormatter(balance).stringMoney;\n            this.syncBalanceAndTotalBetTextScales();\n        }\n    }\n\n    private syncBalanceAndTotalBetTextScales(): void {\n        if (!this.balanceValueText || !this.totalBetValueText) return;\n        this.balanceValueText.scale.set(1);\n        this.totalBetValueText.scale.set(1);\n\n        const balanceTextMaxWidth = this.componentConfiguration.balanceContainerStyle.maxWidth;\n        const totalBetMaxWidth = this.componentConfiguration.totalBetContainerStyle.maxWidth;\n\n        const balanceValueTextWidth = this.balanceValueText.width;\n        const balanceValueTextScale = Math.min(1, balanceTextMaxWidth / balanceValueTextWidth);\n\n        const totalBetValueTextWidth = this.totalBetValueText.width;\n        const totalBetValueTextScale = Math.min(1, totalBetMaxWidth / totalBetValueTextWidth);\n\n        const finalScale = Math.min(balanceValueTextScale, totalBetValueTextScale);\n\n        this.balanceValueText.scale.set(finalScale);\n        this.totalBetValueText.scale.set(finalScale);\n    }\n\n    public hideNumericKeyboardField(animate: boolean = false): void {\n        if (this.numericKeyboard) {\n            this.numericKeyboard.hideNumericKeyboardField(animate);\n        }\n    }\n\n    public open(animation: boolean): void {\n        this.isOpened = true;\n        this.killAllAnimations();\n        this.resetButtons();\n\n        for (const field of this.inputFields) {\n            field.setInactive();\n        }\n        this.checkForMandatory();\n\n        this.mainContainer.alpha = 0;\n        this.mainContainer.y = this.componentConfiguration.mainContainerPosition.y + this.startingPoint;\n        this.mainContainer.visible = true;\n\n        // const arrowY =\n        //     Core.LEFT_HAND_MODE.value && Core.ORIENTATION.value.isLandscape\n        //         ? this.componentConfiguration.arrowPosition.leftHandY\n        //         : this.componentConfiguration.arrowPosition.y;\n        // this.arrow.alpha = 0;\n        // this.arrow.y = arrowY + this.startingPoint;\n        // this.arrow.visible = true;\n\n        this.selectedBtn.visible = true;\n        this.selectedBtn.alpha = 1;\n\n        if (animation) {\n            this.animationTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/autoplay-popup/src/egt/modes/max-bet/views/AutoplayPopupViewMaxBet.ts:260:35\",null]), gsap.timeline());\n\n            const animateAlpha = (alpha: number, duration: number) => ({\n                alpha,\n                duration,\n            });\n            const animateBounce = (y: number, duration: number, ease: string) => ({\n                y,\n                duration,\n                ease,\n            });\n\n            const mainContainerY = this.componentConfiguration.mainContainerPosition.y;\n\n            const onComplete = () => {\n                this.graphicsContainer.alpha = 1;\n                this.graphicsContainer.visible = true;\n            };\n\n            this.animationTween\n                .to(this.mainContainer, animateAlpha(1, 0.3), 0)\n                // .to(this.arrow, animateAlpha(1, 0.3), '<')\n                .to(this.mainContainer, animateBounce(mainContainerY - this.bounceOffset, 0.25, 'power1.out'), 0)\n                // .to(this.arrow, animateBounce(arrowY - this.bounceOffset, 0.25, 'power1.out'), '<')\n                .to(this.mainContainer, { ...animateBounce(mainContainerY, 0.2, 'power1.in'), onComplete }, 0.25);\n            // .to(\n            //     this.arrow,\n            //     {\n            //         ...animateBounce(arrowY, 0.2, 'power1.in'),\n            //         onComplete,\n            //     },\n            //     '<',\n            // );\n        } else {\n            this.mainContainer.alpha = 1;\n            // this.arrow.alpha = 1;\n            this.graphicsContainer.alpha = 1;\n            this.graphicsContainer.visible = true;\n        }\n    }\n\n    public forceClose(): void {\n        this.isOpened = false;\n        this.killAllAnimations();\n        this.noVisibility();\n        this.graphicsContainer.alpha = 0;\n        this.graphicsContainer.visible = false;\n        this.selectedBtn.alpha = 0;\n        this.selectedBtn.visible = false;\n        this.resetInputFields();\n    }\n\n    public close(animation: boolean): void {\n        this.isOpened = false;\n        this.killAllAnimations();\n\n        for (const field of this.inputFields) {\n            field.setInactive();\n        }\n        this.graphicsContainer.alpha = 0;\n        this.graphicsContainer.visible = false;\n        this.mainContainer.alpha = 1;\n        this.mainContainer.visible = true;\n        // this.arrow.alpha = 1;\n        // this.arrow.visible = true;\n        this.selectedBtn.alpha = 0;\n        this.selectedBtn.visible = false;\n        this.resetInputFields();\n        // const arrowY =\n        //     Core.LEFT_HAND_MODE.value && Core.ORIENTATION.value.isLandscape\n        //         ? this.componentConfiguration.arrowPosition.leftHandY\n        //         : this.componentConfiguration.arrowPosition.y;\n\n        if (animation) {\n            this.animationTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/autoplay-popup/src/egt/modes/max-bet/views/AutoplayPopupViewMaxBet.ts:334:35\",null]), gsap.timeline());\n\n            const animateBounce = (alpha: number, y: number, duration: number) => ({\n                alpha,\n                y,\n                duration,\n            });\n\n            const mainContainerY = this.componentConfiguration.mainContainerPosition.y;\n\n            const onComplete = () => {\n                this.noVisibility();\n            };\n\n            this.animationTween.to(this.mainContainer, {\n                ...animateBounce(0, mainContainerY + this.startingPoint, 0.3),\n                onComplete,\n            });\n            // .to(this.arrow, { ...animateBounce(0, arrowY + this.startingPoint, 0.3), onComplete }, '<');\n        } else {\n            this.noVisibility();\n        }\n    }\n\n    public noVisibility() {\n        this.mainContainer.alpha = 0;\n        this.mainContainer.visible = false;\n        // this.arrow.alpha = 0;\n        // this.arrow.visible = false;\n    }\n\n    public resetInputFields(): void {\n        this.maxLossAmountField.resetToInitial();\n        this.balanceLessThanField.resetToInitial();\n        this.balanceMoreThanField.resetToInitial();\n        this.winOverField.resetToInitial();\n    }\n\n    // public updateBetValue(): void {\n    //     this.betMoneyFormatter.amountMoney = this.getTotalBet();\n    //     this.betTextValue.text = this.betMoneyFormatter.stringMoney;\n    //     this.positionBetBalance();\n    //     this.fitBetBalanceInBounds();\n    //     if (this.numericKeyboard) {\n    //         this.numericKeyboard.updateKeyboardBetValue(this.betTextValue.text);\n    //     }\n    // }\n\n    // public updateBalance(): void {\n    //     this.balanceMoneyFormatter.amountMoney = this.rootStore.uiStore.BALANCE.value;\n    //     this.balanceTextValue.text = this.balanceMoneyFormatter.stringMoney;\n    //     this.positionBetBalance();\n    //     this.fitBetBalanceInBounds();\n    //     if (this.numericKeyboard) {\n    //         this.numericKeyboard.updateKeyboardBalanceValue(this.balanceTextValue.text);\n    //     }\n    // }\n\n    public updateUnderTitleTexts(): void {\n        const currency = this.rootStore.settings.currency;\n        if (this.maxLossUnderTitle) {\n            this.maxLossUnderTitle.text = this.getRangeText(\n                this.getTotalBet(),\n                this.rootStore.uiStore.BALANCE.value,\n                currency,\n            );\n            const texts = this.titleTextsByFields.get(this.maxLossAmountField.name) as {\n                titleText: string;\n                underTitleText: string;\n            };\n            this.titleTextsByFields.set(this.maxLossAmountField.name, {\n                titleText: texts.titleText,\n                underTitleText: this.maxLossUnderTitle.text,\n            });\n        }\n        if (this.balanceLessUnderTitle) {\n            this.balanceLessUnderTitle.text = this.getRangeText(this.minBet, this.getLessBalance(), currency);\n            const texts = this.titleTextsByFields.get(this.balanceLessThanField.name) as {\n                titleText: string;\n                underTitleText: string;\n            };\n            this.titleTextsByFields.set(this.balanceLessThanField.name, {\n                titleText: texts.titleText,\n                underTitleText: this.balanceLessUnderTitle.text,\n            });\n        }\n        if (this.balanceMoreUnderTitle) {\n            this.balanceMoreUnderTitle.text = this.getRangeText(this.minBet, this.getMoreBalance(), currency);\n            const texts = this.titleTextsByFields.get(this.balanceMoreThanField.name) as {\n                titleText: string;\n                underTitleText: string;\n            };\n            this.titleTextsByFields.set(this.balanceMoreThanField.name, {\n                titleText: texts.titleText,\n                underTitleText: this.balanceMoreUnderTitle.text,\n            });\n        }\n        if (this.winOverUnderTitle) {\n            this.winOverUnderTitle.text = this.getRangeText(this.minBet, this.getWinOver(), currency);\n            const texts = this.titleTextsByFields.get(this.winOverField.name) as {\n                titleText: string;\n                underTitleText: string;\n            };\n            this.titleTextsByFields.set(this.winOverField.name, {\n                titleText: texts.titleText,\n                underTitleText: this.winOverUnderTitle.text,\n            });\n        }\n\n        this.maxLossAmountField.setMaxValue(this.rootStore.uiStore.BALANCE.value);\n        this.maxLossAmountField.setMinValue(this.getTotalBet());\n        this.balanceLessThanField.setMaxValue(this.getLessBalance());\n        this.balanceMoreThanField.setMaxValue(this.getMoreBalance());\n        this.winOverField.setMaxValue(this.getWinOver());\n    }\n\n    // public fitBetBalanceInBounds(): void {\n    //     const maxWidth = this.betContainer.x - this.balanceContainer.x;\n    //     const balanceWidth =\n    //         this.balanceText.width +\n    //         this.balanceTextValue.width +\n    //         this.balanceTextCurrency.width +\n    //         2 * this.wordSpacing;\n    //     const betWidth =\n    //         this.betText.width + this.betTextValue.width + this.betTextCurrency.width + 2 * this.wordSpacing;\n    //     const actualWidth = balanceWidth + this.wordSpacing + betWidth;\n    //     this.betContainer.scale.set(1);\n    //     this.balanceContainer.scale.set(1);\n    //     if (actualWidth > maxWidth) {\n    //         const scaleFactor = maxWidth / actualWidth;\n    //         this.betContainer.scale.set(scaleFactor);\n    //         this.balanceContainer.scale.set(scaleFactor);\n    //         this.positionBetBalance();\n    //     }\n    // }\n\n    // public positionBetBalance(): void {\n    //     this.balanceTextCurrency.x = this.balanceTextValue.x + this.balanceTextValue.width + this.wordSpacing;\n    //     this.betTextCurrency.x = this.betTextValue.x + this.betTextValue.width + this.wordSpacing;\n    //     this.betContainer.pivot.set(\n    //         this.betText.width + this.betTextValue.width + this.betTextCurrency.width + 2 * this.wordSpacing,\n    //         0,\n    //     );\n    // }\n\n    // protected onPopUpClick(e): void {\n    //     if (!this.isOpened) {\n    //         return;\n    //     }\n    //     if (\n    //         !(\n    //             e.target.parent instanceof InputField ||\n    //             e.target.parent instanceof AutoplayKeyboardActionButtonMaxBet ||\n    //             e.target.parent instanceof AutoplayKeyboardButtonMaxBet ||\n    //             (e.target.parent.parent instanceof KeyboardMaxBet && e.target.name !== 'shadowBackground') ||\n    //             e.target.parent instanceof AutoplayKeyboardActionButtonMaxBet\n    //         )\n    //     ) {\n    //         this.deselectInput();\n    //         if (this.numericKeyboard && this.numericKeyboard.visible) {\n    //             this.hideNumericKeyboardField(true);\n    //         }\n    //     }\n    // }\n\n    protected onShadowClicked(): void {\n        this.CLOSE.next();\n    }\n\n    protected deselectInput(): void {\n        for (const inputField of this.inputFields) {\n            inputField.setInactive();\n        }\n    }\n\n    private resetButtons(): void {\n        for (let i: number = 0; i < this.autoplayButtons.length; i++) {\n            if (i === 0) {\n                this.autoplayButtons[i].setSelected();\n            } else {\n                this.autoplayButtons[i].setNormal();\n            }\n        }\n    }\n\n    private createTotalBetText(): void {\n        this.totalBetTextContainer = new Sprite();\n        this.totalBetTextContainer.anchor.set(0.5);\n        this.mainContainer.addChild(this.totalBetTextContainer);\n\n        this.totalBetCurrencyText = new Text(\n            this.rootStore.uiStore.currency,\n            this.componentConfiguration.totalBetContainerStyle.currencyTextStyle,\n        );\n        this.totalBetCurrencyText.anchor.set(0.5, 0);\n        this.totalBetTextContainer.addChild(this.totalBetCurrencyText);\n\n        this.totalBetValueText = new Text('', this.componentConfiguration.totalBetContainerStyle.valueTextStyle);\n        this.totalBetValueText.anchor.set(0.5, 0);\n        this.totalBetValueText.y = 23;\n        this.totalBetTextContainer.addChild(this.totalBetValueText);\n\n        this.totalBetText = new Text(\n            Core.translator.translate('TOTAL BET'),\n            this.componentConfiguration.totalBetContainerStyle.textStyle,\n        );\n        this.totalBetText.anchor.set(0.5, 0);\n        this.totalBetText.y = 63;\n        this.totalBetTextContainer.addChild(this.totalBetText);\n        this.fitBalanceTextTotalBetTextInBounds();\n    }\n\n    private createBalanceText(): void {\n        this.balanceTextContainer = new Sprite();\n        this.balanceTextContainer.anchor.set(0.5, 1);\n        this.mainContainer.addChild(this.balanceTextContainer);\n\n        this.balanceCurrencyText = new Text(\n            this.rootStore.uiStore.currency,\n            this.componentConfiguration.balanceContainerStyle.currencyTextStyle,\n        );\n        this.balanceCurrencyText.anchor.set(0.5, 0);\n        this.balanceTextContainer.addChild(this.balanceCurrencyText);\n\n        this.balanceValueText = new Text('', this.componentConfiguration.balanceContainerStyle.valueTextStyle);\n        this.balanceValueText.anchor.set(0.5, 0);\n        this.balanceValueText.y = 23;\n        this.balanceTextContainer.addChild(this.balanceValueText);\n\n        this.balanceText = new Text(\n            Core.translator.translate('BALANCE'),\n            this.componentConfiguration.balanceContainerStyle.textStyle,\n        );\n        this.balanceText.anchor.set(0.5, 0);\n        this.balanceText.y = 63;\n        this.balanceTextContainer.addChild(this.balanceText);\n        this.fitBalanceTextTotalBetTextInBounds();\n    }\n\n    private fitBalanceTextTotalBetTextInBounds(): void {\n        if (!this.balanceText || !this.totalBetText) return;\n        this.balanceText.scale.set(1);\n        this.totalBetText.scale.set(1);\n\n        const maxBalanceTextWidth = this.componentConfiguration.balanceContainerStyle.maxWidth;\n        const maxTotalBetTextWidth = this.componentConfiguration.totalBetContainerStyle.maxWidth;\n\n        const scaleBalanceText = maxBalanceTextWidth / this.balanceText.width;\n        const scaleTotalBetText = maxTotalBetTextWidth / this.totalBetText.width;\n\n        const scale = Math.min(1, scaleBalanceText, scaleTotalBetText);\n\n        if (this.balanceText.scale.x !== scale) {\n            this.balanceText.scale.set(scale);\n        }\n        this.totalBetText.scale.set(scale);\n    }\n\n    private crateAutoplayPopUp(): void {\n        this.createPopupGraphics();\n        this.createCurve();\n        this.createPopUpTexts();\n        this.createStartBtn();\n        // this.createArrow();\n        this.crateInputFieldsContainers();\n        this.autoplayButtonsContainer = new Sprite(\n            Core.assets.getTextureFromSpriteSheet('autoplayResources', 'autoplayOptions.png'),\n        );\n        this.mainContainer.addChild(this.autoplayButtonsContainer);\n        for (let i: number = 0; i < this.buttonValues.length; i++) {\n            this.createAutoplayValueButtons(this.buttonValues[i], i);\n        }\n    }\n\n    private createPopupGraphics(): void {\n        // this.popUpShadow = new NineSlicePlane(\n        //     Core.assets.getTextureFromSpriteSheet('autoplayResources', 'shadow.png'),\n        //     45,\n        //     45,\n        //     45,\n        //     45,\n        // );\n        // this.popUpShadow.name = 'popUpShadow';\n        // this.mainContainer.addChild(this.popUpShadow);\n\n        this.popUpBackground = new NineSlicePlane(\n            Core.assets.getTextureFromSpriteSheet('autoplayResources', 'popup.png'),\n            60,\n            60,\n            60,\n            60,\n        );\n        this.popUpBackground.interactive = true;\n        this.mainContainer.addChild(this.popUpBackground);\n\n        // this.popUpFirstSection = new NineSlicePlane(\n        //     Core.assets.getTextureFromSpriteSheet('autoplayResources', 'popupFill.png'),\n        //     15,\n        //     15,\n        //     15,\n        //     15,\n        // );\n        // this.mainContainer.addChild(this.popUpFirstSection);\n\n        // this.popUpSecondSection = new NineSlicePlane(\n        //     Core.assets.getTextureFromSpriteSheet('autoplayResources', 'popupFill.png'),\n        //     15,\n        //     15,\n        //     15,\n        //     15,\n        // );\n        // this.mainContainer.addChild(this.popUpSecondSection);\n    }\n\n    private createPopUpTexts(): void {\n        this.popUpTitleText = new Text(\n            Core.translator.translate('AUTOPLAY SETTINGS'),\n            this.componentConfiguration.popUpTitle.textStyle,\n        );\n        this.popUpTitleText.resolution = 2;\n        this.popUpTitleText.anchor.set(0.5);\n        this.mainContainer.addChild(this.popUpTitleText);\n\n        this.stopOn = new Text(\n            Core.translator.translate('STOP ON').toUpperCase(),\n            this.componentConfiguration.stopOnTitle.textStyle,\n        );\n        this.stopOn.resolution = 2;\n        this.stopOn.anchor.set(0.5, 0);\n        this.mainContainer.addChild(this.stopOn);\n\n        this.autoplay = new Text(\n            Core.translator.translate('Autoplay').toUpperCase(),\n            this.componentConfiguration.autoplayTitle.textStyle,\n        );\n        this.autoplay.resolution = 2;\n        this.autoplay.anchor.set(0.5, 0);\n        this.mainContainer.addChild(this.autoplay);\n    }\n\n    // private createArrow(): void {\n    //     this.arrow = new Sprite(Core.assets.getTextureFromSpriteSheet('autoplayResources', 'arrow.png'));\n    //     this.addChild(this.arrow);\n    // }\n\n    protected getTotalBet(): number {\n        return Core.SELECTED_DENOMINATION.value * this.rootStore.uiStore.SELECTED_BET.value * this.settings.factor;\n    }\n\n    private getLessBalance(): number {\n        return (this.rootStore.uiStore.BALANCE.value * this.settings.autoplayRestrictions.lossLimits) / 100;\n    }\n\n    private getMoreBalance(): number {\n        return (this.rootStore.uiStore.BALANCE.value * this.settings.autoplayRestrictions.winLimits) / 100;\n    }\n\n    private getWinOver(): number {\n        return this.getTotalBet() * this.settings.autoplayRestrictions.singleWinLimit;\n    }\n\n    private crateInputFieldsContainers(): void {\n        this.maxLossAmountFieldContainer = new ViewContainer();\n        this.maxLossAmountFieldContainer.pivot.set(0, 0);\n        this.maxLossAmountField = this.createInputField(\n            this.maxLossAmountFieldContainer,\n            this.componentConfiguration.maxLossAmountContainerConfig,\n        );\n\n        this.balanceLessThanFieldContainer = new ViewContainer();\n        this.balanceLessThanFieldContainer.pivot.set(0, 0);\n        this.balanceLessThanField = this.createInputField(\n            this.balanceLessThanFieldContainer,\n            this.componentConfiguration.balanceLessThanContainerConfig,\n        );\n\n        this.balanceMoreThanFieldContainer = new ViewContainer();\n        this.balanceMoreThanFieldContainer.pivot.set(0, 0);\n        this.balanceMoreThanField = this.createInputField(\n            this.balanceMoreThanFieldContainer,\n            this.componentConfiguration.balanceMoreThanContainerConfig,\n        );\n\n        this.winOverFieldContainer = new ViewContainer();\n        this.winOverFieldContainer.pivot.set(0, 0);\n        this.winOverField = this.createInputField(\n            this.winOverFieldContainer,\n            this.componentConfiguration.winOverContainerConfig,\n        );\n\n        this.maxLossAmountField.setMaxValue(this.rootStore.uiStore.BALANCE.value);\n        this.maxLossAmountField.name = 'maxLossAmountField';\n        this.balanceLessThanField.setMaxValue(this.getLessBalance());\n        this.balanceLessThanField.name = 'balanceLessThanField';\n        this.balanceMoreThanField.setMaxValue(this.getMoreBalance());\n        this.balanceMoreThanField.name = 'balanceMoreThanField';\n        this.winOverField.setMaxValue(this.getWinOver());\n        this.winOverField.name = 'winOverField';\n\n        this.crateInputsTexts();\n        const maxLosOriginalText = Core.translator.translate('MAX LOSS');\n        const maxLosTitle = maxLosOriginalText[0].toUpperCase() + maxLosOriginalText.slice(1);\n        this.titleTextsByFields.set(this.maxLossAmountField.name, {\n            titleText: maxLosTitle,\n            underTitleText: this.maxLossUnderTitle.text,\n        });\n\n        this.maxLossAmountField.INPUT.pipe(takeUntil(this.DESTROY)).subscribe((value: string) => {\n            this.maxLoss = Number(value);\n            // if (this.shouldSetUiStoreFieldValues) {\n            //     this.rootStore.uiStore.maxTotalLossLimit = this.maxLoss * 100;\n            // }\n            this.checkForMandatory();\n            if (this.numericKeyboard) {\n                const titles = this.titleTextsByFields.get(this.maxLossAmountField.name) as {\n                    titleText;\n                    underTitleText;\n                };\n                this.numericKeyboard.updateInput(\n                    titles.titleText,\n                    this.componentConfiguration.keyboardInputContainerConfig.titleTextMaxWidth,\n                    titles.underTitleText,\n                    this.maxLossAmountField.getValue(),\n                    this.maxLossAmountField.getMaxValue(),\n                    this.maxLossAmountField.getMinValue(),\n                );\n            }\n        });\n\n        const lossLimitOriginalText = Core.translator.translate('LOSS LIMIT');\n        const lossLimitTitle = lossLimitOriginalText[0].toUpperCase() + lossLimitOriginalText.slice(1);\n        this.titleTextsByFields.set(this.balanceLessThanField.name, {\n            titleText: lossLimitTitle,\n            underTitleText: this.balanceLessUnderTitle.text,\n        });\n        this.balanceLessThanField.INPUT.pipe(takeUntil(this.DESTROY)).subscribe((value: string) => {\n            this.balanceLess = Number(value);\n            // if (this.shouldSetUiStoreFieldValues) {\n            //     this.rootStore.uiStore.balanceDecreaseValue = this.balanceLess * 100;\n            // }\n            this.checkForMandatory();\n            if (this.numericKeyboard) {\n                const titles = this.titleTextsByFields.get(this.balanceLessThanField.name) as {\n                    titleText;\n                    underTitleText;\n                };\n                this.numericKeyboard.updateInput(\n                    titles.titleText,\n                    this.componentConfiguration.keyboardInputContainerConfig.titleTextMaxWidth,\n                    titles.underTitleText,\n                    this.balanceLessThanField.getValue(),\n                    this.balanceLessThanField.getMaxValue(),\n                    this.balanceLessThanField.getMinValue(),\n                );\n            }\n        });\n\n        const balanceMoreOriginalText = Core.translator.translate('WINS LIMIT');\n        const balanceMoreTitle = balanceMoreOriginalText[0].toUpperCase() + balanceMoreOriginalText.slice(1);\n        this.titleTextsByFields.set(this.balanceMoreThanField.name, {\n            titleText: balanceMoreTitle,\n            underTitleText: this.balanceMoreUnderTitle.text,\n        });\n        this.balanceMoreThanField.INPUT.pipe(takeUntil(this.DESTROY)).subscribe((value: string) => {\n            this.balanceMore = Number(value);\n            // if (this.shouldSetUiStoreFieldValues) {\n            //     this.rootStore.uiStore.balanceIncreaseValue = this.balanceMore * 100;\n            // }\n            this.checkForMandatory();\n            if (this.numericKeyboard) {\n                const titles = this.titleTextsByFields.get(this.balanceMoreThanField.name) as {\n                    titleText;\n                    underTitleText;\n                };\n                this.numericKeyboard.updateInput(\n                    titles.titleText,\n                    this.componentConfiguration.keyboardInputContainerConfig.titleTextMaxWidth,\n                    titles.underTitleText,\n                    this.balanceMoreThanField.getValue(),\n                    this.balanceMoreThanField.getMaxValue(),\n                    this.balanceMoreThanField.getMinValue(),\n                );\n            }\n        });\n\n        const winOverOriginalText = Core.translator.translate('STOP ON WIN');\n        const winOverTitle = winOverOriginalText[0].toUpperCase() + winOverOriginalText.slice(1);\n        this.titleTextsByFields.set(this.winOverField.name, {\n            titleText: winOverTitle,\n            underTitleText: this.winOverUnderTitle.text,\n        });\n        this.winOverField.INPUT.pipe(takeUntil(this.DESTROY)).subscribe((value: string) => {\n            this.winOver = Number(value);\n            // if (this.shouldSetUiStoreFieldValues) {\n            //     this.rootStore.uiStore.winLimitValue = this.winOver * 100;\n            // }\n            this.checkForMandatory();\n            if (this.numericKeyboard) {\n                const titles = this.titleTextsByFields.get(this.winOverField.name) as { titleText; underTitleText };\n                this.numericKeyboard.updateInput(\n                    titles.titleText,\n                    this.componentConfiguration.keyboardInputContainerConfig.titleTextMaxWidth,\n                    titles.underTitleText,\n                    this.winOverField.getValue(),\n                    this.winOverField.getMaxValue(),\n                    this.winOverField.getMinValue(),\n                );\n            }\n        });\n\n        this.maxLossAmountField.ERROR.subscribe((isError) => {\n            this.maxLossUnderTitle.style = isError\n                ? new TextStyle({ ...this.maxLossUnderTitle.style, fill: '#FF0000' })\n                : this.componentConfiguration.maxLossAmountContainerConfig.underTitleTextStyle;\n            this.checkForMandatory();\n        });\n        this.balanceLessThanField.ERROR.subscribe((isError) => {\n            this.balanceLessUnderTitle.style = isError\n                ? new TextStyle({ ...this.balanceLessUnderTitle.style, fill: '#FF0000' })\n                : this.componentConfiguration.balanceLessThanContainerConfig.underTitleTextStyle;\n            this.checkForMandatory();\n        });\n        this.balanceMoreThanField.ERROR.subscribe((isError) => {\n            this.balanceMoreUnderTitle.style = isError\n                ? new TextStyle({ ...this.balanceMoreUnderTitle.style, fill: '#FF0000' })\n                : this.componentConfiguration.balanceMoreThanContainerConfig.underTitleTextStyle;\n            this.checkForMandatory();\n        });\n        this.winOverField.ERROR.subscribe((isError) => {\n            this.winOverUnderTitle.style = isError\n                ? new TextStyle({ ...this.winOverUnderTitle.style, fill: '#FF0000' })\n                : this.componentConfiguration.winOverContainerConfig.underTitleTextStyle;\n            this.checkForMandatory();\n        });\n    }\n\n    private createInputField(container: Container, config: IInputFieldObject): InputField {\n        this.mainContainer.addChild(container);\n        const inputField = new InputField({\n            containerX: config.containerX,\n            containerY: config.containerY,\n            fieldX: config.fieldX,\n            fieldY: config.fieldY,\n            fieldWidth: config.fieldWidth,\n            fieldHeight: config.fieldHeight,\n            fieldNormalTextStyle: config.fieldNormalTextStyle,\n            fieldHilightedTextStyle: config.fieldHilightedTextStyle,\n            currencyHilightedTextStyle: config.currencyHilightedTextStyle,\n            currencyNormaTextStyle: config.currencyNormaTextStyle,\n            normalTexture: Core.assets.getTextureFromSpriteSheet('autoplayResources', 'inputNormal.png'),\n            hilightedTexture: Core.assets.getTextureFromSpriteSheet('autoplayResources', 'inputSelected.png'),\n            inputErrorTexture: Core.assets.getTextureFromSpriteSheet('autoplayResources', 'inputError.png'),\n            currency: this.rootStore.settings.currency,\n        });\n        container.addChild(inputField);\n\n        this.inputFields.push(inputField);\n\n        return inputField;\n    }\n\n    private setTextProps(\n        text: Text,\n        textMaxWidth: number,\n        textValue: string,\n        style: TextStyle,\n        x: number,\n        y: number,\n    ): void {\n        text.text = textValue;\n        text.style = style;\n        text.resolution = 2;\n        text.x = x;\n        text.y = y;\n        if (text.width > textMaxWidth) {\n            text.width = textMaxWidth;\n        }\n    }\n\n    private crateInputsTexts(): void {\n        const currency = this.rootStore.settings.currency;\n\n        // MAX LOSS\n        const maxLossTitle = new Text();\n        this.setTextProps(\n            maxLossTitle,\n            this.componentConfiguration.maxLossAmountContainerConfig.titleTextMaxWidth,\n            this.toSentenceCase(Core.translator.translate('MAX LOSS')),\n            this.componentConfiguration.maxLossAmountContainerConfig.titleTextStyle,\n            this.componentConfiguration.maxLossAmountContainerConfig.titleX,\n            this.componentConfiguration.maxLossAmountContainerConfig.titleY,\n        );\n        this.maxLossAmountFieldContainer.addChild(maxLossTitle);\n\n        this.maxLossUnderTitle = this.createUnderTitleText(\n            this.maxLossAmountFieldContainer,\n            this.getRangeText(this.minBet, this.rootStore.uiStore.BALANCE.value, currency),\n            this.componentConfiguration.maxLossAmountContainerConfig.underTitleTextStyle,\n            this.componentConfiguration.maxLossAmountContainerConfig.underTitleX,\n            this.componentConfiguration.maxLossAmountContainerConfig.underTitleY,\n        );\n\n        this.createMandatorySign(\n            maxLossTitle,\n            '*',\n            this.componentConfiguration.mandatoryText.textStyle,\n            MandatoryValues.MAX_LOSS,\n        );\n\n        // BALANCE LESS THAN\n        const balanceLessTitle = new Text();\n        this.setTextProps(\n            balanceLessTitle,\n            this.componentConfiguration.balanceLessThanContainerConfig.titleTextMaxWidth,\n            this.toSentenceCase(Core.translator.translate('LOSS LIMIT')),\n            this.componentConfiguration.balanceLessThanContainerConfig.titleTextStyle,\n            this.componentConfiguration.balanceLessThanContainerConfig.titleX,\n            this.componentConfiguration.balanceLessThanContainerConfig.titleY,\n        );\n        this.balanceLessThanFieldContainer.addChild(balanceLessTitle);\n        this.balanceLessUnderTitle = this.createUnderTitleText(\n            this.balanceLessThanFieldContainer,\n            this.getRangeText(this.minBet, this.getLessBalance(), currency),\n            this.componentConfiguration.balanceLessThanContainerConfig.underTitleTextStyle,\n            this.componentConfiguration.balanceLessThanContainerConfig.underTitleX,\n            this.componentConfiguration.balanceLessThanContainerConfig.underTitleY,\n        );\n\n        this.createMandatorySign(\n            balanceLessTitle,\n            '*',\n            this.componentConfiguration.mandatoryText.textStyle,\n            MandatoryValues.BALANCE_LES,\n        );\n\n        // BALANCE MORE THAN\n        const balanceMoreTitle = new Text();\n        this.setTextProps(\n            balanceMoreTitle,\n            this.componentConfiguration.balanceMoreThanContainerConfig.titleTextMaxWidth,\n            this.toSentenceCase(Core.translator.translate('WINS LIMIT')),\n            this.componentConfiguration.balanceMoreThanContainerConfig.titleTextStyle,\n            this.componentConfiguration.balanceMoreThanContainerConfig.titleX,\n            this.componentConfiguration.balanceMoreThanContainerConfig.titleY,\n        );\n        this.balanceMoreThanFieldContainer.addChild(balanceMoreTitle);\n\n        this.balanceMoreUnderTitle = this.createUnderTitleText(\n            this.balanceMoreThanFieldContainer,\n            this.getRangeText(this.minBet, this.getMoreBalance(), currency),\n            this.componentConfiguration.balanceMoreThanContainerConfig.underTitleTextStyle,\n            this.componentConfiguration.balanceMoreThanContainerConfig.underTitleX,\n            this.componentConfiguration.balanceMoreThanContainerConfig.underTitleY,\n        );\n\n        this.createMandatorySign(\n            balanceMoreTitle,\n            '*',\n            this.componentConfiguration.mandatoryText.textStyle,\n            MandatoryValues.BALANCE_MORE,\n        );\n\n        // WIN OVER\n        const winOverTitle = new Text();\n        this.setTextProps(\n            winOverTitle,\n            this.componentConfiguration.winOverContainerConfig.titleTextMaxWidth,\n            this.toSentenceCase(Core.translator.translate('STOP ON WIN')),\n            this.componentConfiguration.winOverContainerConfig.titleTextStyle,\n            this.componentConfiguration.winOverContainerConfig.titleX,\n            this.componentConfiguration.winOverContainerConfig.titleY,\n        );\n        this.winOverFieldContainer.addChild(winOverTitle);\n\n        this.winOverUnderTitle = this.createUnderTitleText(\n            this.winOverFieldContainer,\n            this.getRangeText(this.minBet, this.getWinOver(), currency),\n            this.componentConfiguration.winOverContainerConfig.underTitleTextStyle,\n            this.componentConfiguration.winOverContainerConfig.underTitleX,\n            this.componentConfiguration.winOverContainerConfig.underTitleY,\n        );\n\n        this.createMandatorySign(\n            winOverTitle,\n            '*',\n            this.componentConfiguration.mandatoryText.textStyle,\n            MandatoryValues.WIN_OVER,\n        );\n    }\n\n    private createMandatorySign(title: Text, textValue: string, style: TextStyle, mandatoryValue: string): void {\n        const mandatorySign = new Text(textValue, style);\n        mandatorySign.x = title.getLocalBounds().width + mandatorySign.width / 2;\n\n        title.addChild(mandatorySign);\n\n        if (this.settings.autoplayRestrictions.mandatory.indexOf(mandatoryValue) === -1) {\n            mandatorySign.visible = false;\n        }\n    }\n\n    private createUnderTitleText(\n        container: ViewContainer,\n        textValue: string,\n        style: TextStyle,\n        x: number,\n        y: number,\n    ): Text {\n        const underTitle = new Text(textValue, style);\n        underTitle.x = x;\n        underTitle.y = y;\n        container.addChild(underTitle);\n        return underTitle;\n    }\n\n    private getRangeText(min: number, max: number, currency: string): string {\n        const minStr = new MoneyFormatter(min).stringMoney;\n        const maxStr = new MoneyFormatter(Math.ceil(max)).stringMoney;\n        return `min. ${minStr} - max. ${maxStr} ${currency}`;\n    }\n\n    private createStartBtn(): void {\n        const btnTextures: AutoplayNumericInputPopupStartButtonTextures =\n            new AutoplayNumericInputPopupStartButtonTextures(\n                Core.assets.getAsset('svgAutoplayStartNormal').texture,\n                Core.assets.getAsset('svgAutoplayStartNormal').texture,\n                Core.assets.getAsset('svgAutoplayStartDisabled').texture,\n                Core.assets.getAsset('svgAutoplayStartHover').texture,\n            );\n        this.startAutoplayButton = new AutoplayNumericInputPopupButton(\n            Core.translator.translate('START AUTOPLAY'),\n            btnTextures,\n            this.componentConfiguration.buttonNormalText.textStyle,\n            this.componentConfiguration.buttonDisabledText.textStyle,\n        );\n        this.mainContainer.addChild(this.startAutoplayButton);\n    }\n\n    private createAutoplayValueButtons(value: number, _buttonIndex: number): void {\n        const btnTextures: AutoplayNumericInputPopupStartButtonTextures =\n            new AutoplayNumericInputPopupStartButtonTextures(\n                Core.assets.getAsset('svgAutoplayPopUpNormal').texture,\n                Core.assets.getAsset('svgAutoplayPopUpSelected').texture,\n                Core.assets.getAsset('svgAutoplayPopUpNormal').texture,\n                Core.assets.getAsset('svgAutoplayPopUpHover').texture,\n            );\n        const button: AutoplayPopupButtonMaxBet = new AutoplayPopupButtonMaxBet(\n            value,\n            btnTextures,\n            this.componentConfiguration.buttonValueText.textStyle,\n            this.componentConfiguration.buttonValueText.selectedTextStyle,\n            this.componentConfiguration.buttonValueText.width,\n            this.componentConfiguration.buttonValueText.height,\n        );\n\n        this.autoplayButtonsContainer.addChild(button);\n        this.autoplayButtons.push(button);\n    }\n\n    private setOrientation(): void {\n        this.killAllAnimations();\n        if (this.isOpened) {\n            this.mainContainer.alpha = 1;\n            // this.arrow.alpha = 1;\n            this.graphicsContainer.alpha = 1;\n            this.graphicsContainer.visible = true;\n        } else {\n            this.noVisibility();\n            this.graphicsContainer.alpha = 0;\n            this.graphicsContainer.visible = false;\n        }\n        this.mainContainer.x = this.componentConfiguration.mainContainerPosition.x;\n        this.mainContainer.y = this.componentConfiguration.mainContainerPosition.y;\n\n        this.popUpBackground.x = this.componentConfiguration.popUpGraphicsContainer.x;\n        this.popUpBackground.y = this.componentConfiguration.popUpGraphicsContainer.y;\n        this.popUpBackground.width = this.componentConfiguration.popUpGraphicsContainer.width;\n        this.popUpBackground.height = this.componentConfiguration.popUpGraphicsContainer.height;\n\n        this.popUpTitleText.x =\n            this.componentConfiguration.popUpGraphicsContainer.x +\n            this.componentConfiguration.popUpGraphicsContainer.width / 2;\n        this.popUpTitleText.y = this.popUpBackground.y + this.componentConfiguration.popUpTitle.yOffset;\n\n        this.stopOn.x = this.componentConfiguration.stopOnTitle.x;\n        this.stopOn.y = this.componentConfiguration.stopOnTitle.y;\n\n        this.curve.visible = Core.ORIENTATION.value.isPortrait;\n        this.curve.x = this.componentConfiguration.curvePosition.x;\n        this.curve.y = this.componentConfiguration.curvePosition.y;\n\n        this.autoplay.x = this.componentConfiguration.autoplayTitle.x;\n        this.autoplay.y = this.componentConfiguration.autoplayTitle.y;\n\n        this.maxLossAmountFieldContainer.x = this.componentConfiguration.maxLossAmountContainerConfig.containerX;\n        this.maxLossAmountFieldContainer.y = this.componentConfiguration.maxLossAmountContainerConfig.containerY;\n\n        this.balanceLessThanFieldContainer.x = this.componentConfiguration.balanceLessThanContainerConfig.containerX;\n        this.balanceLessThanFieldContainer.y = this.componentConfiguration.balanceLessThanContainerConfig.containerY;\n\n        this.balanceMoreThanFieldContainer.x = this.componentConfiguration.balanceMoreThanContainerConfig.containerX;\n        this.balanceMoreThanFieldContainer.y = this.componentConfiguration.balanceMoreThanContainerConfig.containerY;\n\n        this.winOverFieldContainer.x = this.componentConfiguration.winOverContainerConfig.containerX;\n        this.winOverFieldContainer.y = this.componentConfiguration.winOverContainerConfig.containerY;\n\n        // this.popUpShadow.x = this.componentConfiguration.popUpGraphicsContainer.x - 40;\n        // this.popUpShadow.y = this.componentConfiguration.popUpGraphicsContainer.y;\n        // this.popUpShadow.width = this.componentConfiguration.popUpGraphicsContainer.width + 80;\n        // this.popUpShadow.height = this.componentConfiguration.popUpGraphicsContainer.height + 40;\n\n        this.balanceTextContainer.x = this.componentConfiguration.balanceContainerStyle.x;\n        this.balanceTextContainer.y = this.componentConfiguration.balanceContainerStyle.y;\n\n        this.totalBetTextContainer.x = this.componentConfiguration.totalBetContainerStyle.x;\n        this.totalBetTextContainer.y = this.componentConfiguration.totalBetContainerStyle.y;\n\n        // this.popUpFirstSection.x = this.componentConfiguration.popUpFirstSectionPosition.x;\n        // this.popUpFirstSection.y = this.componentConfiguration.popUpFirstSectionPosition.y;\n        // this.popUpFirstSection.width = this.componentConfiguration.popUpFirstSectionPosition.width;\n        // this.popUpFirstSection.height = this.componentConfiguration.popUpFirstSectionPosition.height;\n\n        // this.popUpSecondSection.x = this.componentConfiguration.popUpSecondSectionPosition.x;\n        // this.popUpSecondSection.y = this.componentConfiguration.popUpSecondSectionPosition.y;\n        // this.popUpSecondSection.width = this.componentConfiguration.popUpSecondSectionPosition.width;\n        // this.popUpSecondSection.height = this.componentConfiguration.popUpSecondSectionPosition.height;\n\n        for (let i: number = 0; i < this.autoplayButtons.length; i++) {\n            const firstBtnOffset: number = 4;\n            this.autoplayButtons[i].x =\n                (this.componentConfiguration.buttonValueText.xOffset +\n                    this.componentConfiguration.buttonValueText.width) *\n                    i +\n                firstBtnOffset;\n            this.autoplayButtons[i].y = this.componentConfiguration.buttonValueText.yOffset;\n        }\n\n        // this.autoplayButtonsContainer.x =\n        //     this.popUpSecondSection.x +\n        //     (this.popUpSecondSection.width -\n        //         (114 * (this.autoplayButtons.length - 1) + this.autoplayButtons[0].width)) /\n        //         2;\n        this.autoplayButtonsContainer.x = this.componentConfiguration.buttonsContainerPositions.x;\n        this.autoplayButtonsContainer.y = this.componentConfiguration.buttonsContainerPositions.y;\n\n        // this.arrow.x = this.componentConfiguration.arrowPosition.x;\n        // this.arrow.y = this.componentConfiguration.arrowPosition.y;\n        // this.arrow.angle = this.componentConfiguration.arrowPosition.angle;\n\n        // this.balanceContainer.x = this.componentConfiguration.balanceText.x;\n        // this.balanceContainer.y = this.componentConfiguration.balanceText.y;\n\n        // this.betContainer.x = this.componentConfiguration.betText.x;\n        // this.betContainer.y = this.componentConfiguration.betText.y;\n\n        this.startAutoplayButton.x = this.componentConfiguration.startAutoplayBtn.x;\n        this.startAutoplayButton.y = this.componentConfiguration.startAutoplayBtn.y;\n\n        this.selectedBtn.x = this.componentConfiguration.selectedButton.x;\n        this.selectedBtn.y = this.componentConfiguration.selectedButton.y;\n        this.selectedBtn.scale.set(this.componentConfiguration.selectedButton.scale);\n\n        if (this.numericKeyboard) {\n            this.numericKeyboard.setOrientation();\n        }\n\n        this.setLeftHand();\n        this.syncBalanceAndTotalBetTextScales();\n        this.fitBalanceTextTotalBetTextInBounds();\n    }\n\n    private setLeftHand(): void {\n        if (Core.LEFT_HAND_MODE.value && Core.ORIENTATION.value.isLandscape) {\n            this.mainContainer.x = this.componentConfiguration.mainContainerPosition.leftHandX;\n\n            // this.arrow.x = this.componentConfiguration.arrowPosition.leftHandX;\n            // this.arrow.y = this.componentConfiguration.arrowPosition.leftHandY;\n            // this.arrow.angle = this.componentConfiguration.arrowPosition.leftHandAngle;\n\n            this.selectedBtn.x = this.componentConfiguration.selectedButton.leftHandX;\n            if (this.numericKeyboard) {\n                this.numericKeyboard.setOrientation();\n            }\n        }\n    }\n\n    private checkForMandatory() {\n        let mandatoryChecked: boolean = true;\n        for (const mandatory of this.mandatory) {\n            if (mandatory === MandatoryValues.BALANCE_LES && this.balanceLess === 0) {\n                mandatoryChecked = false;\n            } else if (mandatory === MandatoryValues.BALANCE_MORE && this.balanceMore === 0) {\n                mandatoryChecked = false;\n            } else if (mandatory === MandatoryValues.WIN_OVER && this.winOver === 0) {\n                mandatoryChecked = false;\n            } else if (mandatory === MandatoryValues.MAX_LOSS && this.maxLoss === 0) {\n                mandatoryChecked = false;\n            }\n        }\n\n        let fieldValueOutOfRange: boolean = false;\n        for (const field of this.inputFields) {\n            if (field.hasError && field.getValue() !== '') {\n                mandatoryChecked = false;\n                fieldValueOutOfRange = true;\n                break;\n            }\n        }\n\n        if (mandatoryChecked) {\n            this.startAutoplayButton.setNormal();\n        } else {\n            this.startAutoplayButton.setDisabled();\n        }\n\n        if (this.numericKeyboard && this.numericKeyboard.doneButton) {\n            if (fieldValueOutOfRange) {\n                this.numericKeyboard.doneButton.tintBtn();\n            } else {\n                this.numericKeyboard.doneButton.untintBtn();\n            }\n        }\n    }\n\n    private createSelectedBtn(): void {\n        this.selectedBtn = new Button(\n            [Core.assets.getAsset('svgAutoplaySelected').texture],\n            undefined,\n            ButtonShapes.Rectangle,\n        );\n        this.selectedBtn.pivot.set(this.selectedBtn.width / 2, this.selectedBtn.height / 2);\n        this.selectedBtn.interactive = true;\n        this.addChild(this.selectedBtn);\n    }\n\n    private createGraphicsContainer(): void {\n        this.graphicsContainer = new Container();\n        this.graphicsContainer.visible = false;\n        this.graphicsContainer.alpha = 0;\n        this.addChild(this.graphicsContainer);\n    }\n\n    private createMainContainer(): void {\n        this.mainContainer = new Container();\n        this.mainContainer.visible = false;\n        this.mainContainer.alpha = 0;\n        this.addChild(this.mainContainer);\n    }\n\n    private createCurve(): void {\n        this.curve = new Sprite(Core.assets.getTextureFromSpriteSheet('autoplayResources', 'curve.png'));\n        this.curve.name = 'curve';\n        this.mainContainer.addChild(this.curve);\n    }\n\n    private killAllAnimations(): void {\n        if (this.animationTween) {\n            this.animationTween.kill();\n            this.animationTween = null;\n        }\n    }\n\n    public showNumericKeyboardField(field: InputField): void {\n        if (Core.isDesktopMode) return;\n        if (this.numericKeyboard && this.numericKeyboard.isKeyboardVisible) {\n            this.currentField = field;\n            if (this.currentField && this.currentField !== field) {\n                this.currentField.setInactive();\n            }\n\n            this.numericKeyboard.setCurrentField(field);\n            return;\n        }\n\n        if (!this.numericKeyboard) {\n            this.numericKeyboard = new KeyboardMaxBet(this.componentConfiguration, this.rootStore.settings.currency);\n            this.addChild(this.numericKeyboard);\n\n            this.numericKeyboard.ON_DONE.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n                this.numericKeyboard.hideNumericKeyboardField(true);\n            });\n            this.numericKeyboard.ON_CANCEL.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n                this.numericKeyboard.hideNumericKeyboardField(true);\n            });\n            this.numericKeyboard.ON_INPUT.pipe(takeUntil(this.DESTROY)).subscribe((value: string) => {\n                if (this.currentField) {\n                    this.currentField.setValue(value);\n                }\n            });\n        }\n\n        this.numericKeyboard.updateKeyboardBalanceValue(this.balanceValueText.text);\n        this.numericKeyboard.updateKeyboardBetValue(this.totalBetValueText.text);\n        // this.numericKeyboard.updateCurrency(this.rootStore.settings.currency);\n        const titles = this.titleTextsByFields.get(field.name) as { titleText; underTitleText };\n        this.numericKeyboard.updateInput(\n            titles.titleText,\n            this.componentConfiguration.keyboardInputContainerConfig.titleTextMaxWidth,\n            titles.underTitleText,\n            field.getValue(),\n            field.getMaxValue(),\n            field.getMinValue(),\n        );\n\n        this.currentField = field;\n        this.numericKeyboard.setCurrentField(field);\n\n        this.numericKeyboard.visible = true;\n\n        // if (this.numericKeyboard) {\n        //     this.numericKeyboard.showShadowBackground();\n        // }\n\n        this.numericKeyboard.animateShowKeyboard();\n        this.setOrientation();\n    }\n\n    // private setInputFieldsInteractive(interactive: boolean = true): void {\n    //     for (const field of this.inputFields) {\n    //         field.setInteractive(interactive);\n    //     }\n    // }\n\n    private toSentenceCase(str: string): string {\n        return str.charAt(0).toUpperCase() + str.substring(1).toLowerCase();\n    }\n\n    private destroyArray(arr: any[]) {\n        if (!arr) {\n            return;\n        }\n        arr.forEach((child) => {\n            this.destroyObject(child);\n        });\n        // @ts-ignore\n        arr = null;\n    }\n\n    private destroyObject(obj: any) {\n        obj?.destroy?.();\n        // @ts-ignore\n        obj = null;\n    }\n}\n","import { IContainerGraphicsInterfaceMaxBet, InputField, ViewContainer } from '@egt/ui-lib';\nimport { Graphics, Container, TextStyle, Texture, Text, Sprite } from 'pixi.js';\nimport { gsap } from 'gsap';\nimport { Subject } from 'rxjs';\nimport Core from '@egt/core';\nimport { takeUntil } from 'rxjs/operators';\nimport AutoplayKeyboardButtonMaxBet, {\n    AutoplayKeyboardButtonTexturesMaxBet,\n} from '../buttons/AutoplayKeyboardButtonMaxBet';\nimport AutoplayKeyboardActionButtonMaxBet, {\n    AutoplayKeyboardActionButtonTexturesMaxBet,\n} from '../buttons/AutoplayKeyboardActionButtonMaxBet';\n\nexport class KeyboardMaxBet extends ViewContainer {\n    private keyboardContainer: Sprite;\n    //UI containers and graphics\n    private background: Graphics;\n    private titleLine: Graphics;\n    private shadowBackground: Graphics;\n    private buttonsContainer: Container;\n    private numericKeyboardTween: any;\n    public isKeyboardVisible: boolean = false;\n\n    //Keyboard buttons\n    private buttons: AutoplayKeyboardButtonMaxBet[] = [];\n    public doneButton: AutoplayKeyboardActionButtonMaxBet;\n    private cancelButton: AutoplayKeyboardActionButtonMaxBet;\n\n    //Input field reference\n    private currentField: InputField;\n\n    private balanceTextContainer: Sprite;\n    private balanceCurrencyText: Text;\n    private balanceValueText: Text;\n    private balanceText: Text;\n\n    private totalBetTextContainer: Sprite;\n    private totalBetCurrencyText: Text;\n    private totalBetValueText: Text;\n    private totalBetText: Text;\n\n    // input\n    private inputContainer: ViewContainer;\n    private inputField: InputField;\n    private inputTitleText: Text;\n    private inputUnderTitle: Text;\n\n    //Configuration and layout\n    private componentConfiguration: any;\n\n    private currency: string;\n\n    //Events\n    public readonly ON_DONE = new Subject<void>();\n    public readonly ON_CANCEL = new Subject<void>();\n    public readonly ON_INPUT = new Subject<string>();\n\n    constructor(componentConfiguration: any, currency: string) {\n        super();\n        this.componentConfiguration = componentConfiguration;\n        this.currency = currency;\n\n        this.createShadowBackground();\n        this.createKeyboardContainer();\n        this.createBackground(this.componentConfiguration.autoplayKeyboardContainerGraphicsConfig);\n        this.createNumericKeyboardActionButtons();\n        this.createBalanceText();\n        this.createTotalBetText();\n        this.crateInputFieldsContainer();\n    }\n\n    public hideNumericKeyboardField(animate: boolean = false): void {\n        this.killNumericKeyboardTween();\n        if (!this.isKeyboardVisible && !this.numericKeyboardTween) {\n            return;\n        }\n        if (animate) {\n            this.animateHideKeyboard();\n        } else {\n            this.visible = false;\n            this.keyboardContainer.alpha = 0;\n            this.keyboardContainer.y = Core.display.stage.height;\n            this.shadowBackground.alpha = 0;\n            this.isKeyboardVisible = false;\n            Core.sounds.play('hideDenominationsSound');\n            // this.numericKeyboard.hideShadowBackground();\n        }\n    }\n\n    public animateShowKeyboard(): void {\n        // this.setInputFieldsInteractive(false);\n        this.keyboardContainer.alpha = 0;\n        this.keyboardContainer.y = Core.display.stage.height;\n        this.shadowBackground.alpha = 0;\n        Core.sounds.play('showDenominationsSound');\n        this.numericKeyboardTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/autoplay-popup/src/egt/modes/max-bet/views/KeyboardMaxBet.ts:96:37\",null]), gsap.timeline({\n            onComplete: () => {\n                this.isKeyboardVisible = true;\n            },\n        }));\n        this.numericKeyboardTween\n            .to(this.keyboardContainer, { alpha: 1, duration: 0.1 }, 0)\n            .to(\n                this.keyboardContainer,\n                {\n                    y: this.componentConfiguration.numericKeyboardContainerPosition.y,\n                    duration: 0.25,\n                    ease: 'power1.out',\n                },\n                0,\n            )\n            .to(this.shadowBackground, { alpha: 0.9, duration: 0.25 }, 0);\n    }\n\n    public animateHideKeyboard(): void {\n        // this.setInputFieldsInteractive(false);\n        Core.sounds.play('hideDenominationsSound');\n        this.numericKeyboardTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/autoplay-popup/src/egt/modes/max-bet/views/KeyboardMaxBet.ts:118:37\",null]), gsap.timeline({\n            onComplete: () => {\n                // this.setInputFieldsInteractive(true);\n                this.visible = false;\n                this.isKeyboardVisible = false;\n            },\n        }));\n        this.numericKeyboardTween\n            .to(this.keyboardContainer, { alpha: 0, duration: 0.2 }, 0)\n            .to(this.keyboardContainer, { y: Core.display.stage.height, duration: 0.25, ease: 'power1.in' }, 0)\n            .to(this.shadowBackground, { alpha: 0, duration: 0.25 }, 0);\n    }\n\n    public killNumericKeyboardTween(): void {\n        if (this.numericKeyboardTween) {\n            this.numericKeyboardTween.kill();\n            this.numericKeyboardTween = null;\n        }\n    }\n\n    public updateInput(\n        titleText: string,\n        titleTextMaxWidth: number,\n        underTitleText: string,\n        inputValue: string,\n        maxValue: number,\n        minValue: number,\n    ): void {\n        this.inputTitleText.text = titleText;\n        this.inputUnderTitle.text = underTitleText;\n        this.inputField.setActive();\n        this.inputField.setValue(inputValue);\n        this.inputField.setMaxValue(maxValue);\n        this.inputField.setMinValue(minValue);\n        this.inputTitleText.scale.set(1);\n        if (this.inputTitleText.width > titleTextMaxWidth) {\n            this.inputTitleText.scale.set(titleTextMaxWidth / this.inputTitleText.width);\n        }\n    }\n\n    private createKeyboardContainer(): void {\n        this.keyboardContainer = new Sprite();\n        this.keyboardContainer.name = 'keyboardContainer';\n        this.addChild(this.keyboardContainer);\n    }\n\n    //UI creation methods\n\n    private createBackground(config: IContainerGraphicsInterfaceMaxBet): void {\n        this.background = new Graphics();\n        this.background.beginFill(config.backgroundColor);\n        this.background.drawRect(0, 0, config.backgroundWidth, config.backgroundHeight);\n        this.background.endFill();\n        this.background.interactive = true;\n        this.background.buttonMode = false;\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/max-bet/views/KeyboardMaxBet.ts:173:9\",(this.background),\"pointerdown\"]), this.background.on('pointerdown', (e) => {\n            e.stopPropagation();\n        }));\n        this.keyboardContainer.addChild(this.background);\n\n        this.titleLine = new Graphics();\n        this.titleLine.beginFill(config.titleColor);\n        this.titleLine.drawRect(0, 0, config.backgroundWidth, config.titleHeight);\n        this.titleLine.endFill();\n        this.keyboardContainer.addChild(this.titleLine);\n    }\n\n    private createShadowBackground(): void {\n        this.shadowBackground = new Graphics();\n        this.shadowBackground.beginFill(0x000000);\n        this.shadowBackground.drawRect(0, 0, Core.display.stage.width, Core.display.stage.height);\n        this.shadowBackground.endFill();\n        // this.shadowBackground.visible = false;\n        this.shadowBackground.alpha = 0.9;\n        this.shadowBackground.name = 'shadowBackground';\n        this.shadowBackground.interactive = true;\n        this.addChild(this.shadowBackground);\n    }\n\n    private createNumericKeyboardActionButtons(): void {\n        const saveBtnTextures = new AutoplayKeyboardActionButtonTexturesMaxBet(\n            Core.assets.getAsset('svgButtonDone').texture,\n        );\n        const cancelBtnTextures = new AutoplayKeyboardActionButtonTexturesMaxBet(\n            Core.assets.getAsset('svgClose').texture,\n        );\n\n        this.cancelButton = this.createActionBtn(\n            cancelBtnTextures,\n            this.componentConfiguration.doneBtn.textStyle,\n            this.componentConfiguration.cancelBtn.x,\n            this.componentConfiguration.cancelBtn.y,\n        );\n        this.cancelButton.CLICK.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            if (this.currentField) {\n                this.currentField.restoreLastConfirmedValue();\n                this.currentField.setInactive();\n            }\n            this.ON_CANCEL.next();\n        });\n\n        this.doneButton = this.createActionBtn(\n            saveBtnTextures,\n            this.componentConfiguration.doneBtn.textStyle,\n            this.componentConfiguration.doneBtn.x,\n            this.componentConfiguration.doneBtn.y,\n        );\n\n        this.doneButton.CLICK.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            if (this.currentField) {\n                this.currentField.setInactive();\n                this.ON_DONE.next();\n            }\n        });\n\n        this.keyboardContainer.addChild(this.cancelButton);\n        this.keyboardContainer.addChild(this.doneButton);\n\n        this.createNumericKeyboardButtons();\n        this.positionNumericKeyboardButtons();\n    }\n\n    private createActionBtn(\n        textures: AutoplayKeyboardActionButtonTexturesMaxBet,\n        btnTextStyle: TextStyle,\n        x: number,\n        y: number,\n    ): AutoplayKeyboardActionButtonMaxBet {\n        const button = new AutoplayKeyboardActionButtonMaxBet(textures, btnTextStyle);\n        button.x = x;\n        button.y = y;\n        return button;\n    }\n\n    private createNumericKeyboardButtons(): void {\n        for (const btn of this.buttons) {\n            btn.destroy();\n        }\n        this.buttons = [];\n\n        if (!this.buttonsContainer) {\n            this.buttonsContainer = new ViewContainer();\n            this.keyboardContainer.addChild(this.buttonsContainer);\n        } else {\n            this.buttonsContainer.removeChildren();\n        }\n\n        const buttonValues: string[] = this.componentConfiguration.numericKeyboardButtonValues;\n\n        for (let i = 0; i < buttonValues.length; i++) {\n            const value = buttonValues[i];\n            const texture = this.getNumericKeyboardButtonTexture(value);\n\n            const showText = value !== '.' && value !== '<';\n            const textures = new AutoplayKeyboardButtonTexturesMaxBet(texture);\n            const button = new AutoplayKeyboardButtonMaxBet(\n                textures,\n                this.componentConfiguration.numericKeyboardButtonText.textStyle,\n                showText ? value : '',\n            );\n            button.value = value;\n\n            this.buttons.push(button);\n\n            this.buttonsContainer.addChild(button);\n\n            button.CLICK.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n                this.onNumericKeyboardButtonClick(value);\n            });\n        }\n    }\n\n    private positionNumericKeyboardButtons(): void {\n        for (let i = 0; i < this.buttons.length; i++) {\n            const button = this.buttons[i];\n\n            button.x = this.componentConfiguration.numericKeyboardBtnPositions[i].x;\n            button.y = this.componentConfiguration.numericKeyboardBtnPositions[i].y;\n            // }\n        }\n    }\n\n    private createBalanceText(): void {\n        this.balanceTextContainer = new Sprite();\n        this.balanceTextContainer.anchor.set(0.5, 1);\n        this.keyboardContainer.addChild(this.balanceTextContainer);\n\n        this.balanceCurrencyText = new Text(\n            this.currency,\n            this.componentConfiguration.balanceContainerStyle.currencyTextStyle,\n        );\n        this.balanceCurrencyText.anchor.set(0.5, 0);\n        this.balanceTextContainer.addChild(this.balanceCurrencyText);\n\n        this.balanceValueText = new Text('', this.componentConfiguration.balanceContainerStyle.valueTextStyle);\n        this.balanceValueText.anchor.set(0.5, 0);\n        this.balanceValueText.y = 23;\n        this.balanceTextContainer.addChild(this.balanceValueText);\n\n        this.balanceText = new Text(\n            Core.translator.translate('BALANCE'),\n            this.componentConfiguration.balanceContainerStyle.textStyle,\n        );\n        this.balanceText.anchor.set(0.5, 0);\n        this.balanceText.y = 63;\n        this.balanceTextContainer.addChild(this.balanceText);\n    }\n\n    private createTotalBetText(): void {\n        this.totalBetTextContainer = new Sprite();\n        this.totalBetTextContainer.anchor.set(0.5);\n        this.keyboardContainer.addChild(this.totalBetTextContainer);\n\n        this.totalBetCurrencyText = new Text(\n            this.currency,\n            this.componentConfiguration.totalBetContainerStyle.currencyTextStyle,\n        );\n        this.totalBetCurrencyText.anchor.set(0.5, 0);\n        this.totalBetTextContainer.addChild(this.totalBetCurrencyText);\n\n        this.totalBetValueText = new Text('', this.componentConfiguration.totalBetContainerStyle.valueTextStyle);\n        this.totalBetValueText.anchor.set(0.5, 0);\n        this.totalBetValueText.y = 23;\n        this.totalBetTextContainer.addChild(this.totalBetValueText);\n\n        this.totalBetText = new Text(\n            Core.translator.translate('TOTAL BET'),\n            this.componentConfiguration.totalBetContainerStyle.textStyle,\n        );\n        this.totalBetText.anchor.set(0.5, 0);\n        this.totalBetText.y = 63;\n        this.totalBetTextContainer.addChild(this.totalBetText);\n    }\n    public setOrientation(): void {\n        this.positionNumericKeyboardButtons();\n\n        const config: IContainerGraphicsInterfaceMaxBet =\n            this.componentConfiguration.autoplayKeyboardContainerGraphicsConfig;\n\n        // Background\n        if (this.background) {\n            this.background.width = config.backgroundWidth;\n            this.background.height = config.backgroundHeight;\n        }\n\n        // Title\n        this.titleLine.width = config.backgroundWidth;\n        this.titleLine.height = config.titleHeight;\n\n        this.balanceTextContainer.x = this.componentConfiguration.keyboardBalanceContainerStyle.x;\n        this.balanceTextContainer.y = this.componentConfiguration.keyboardBalanceContainerStyle.y;\n\n        this.totalBetTextContainer.x = this.componentConfiguration.keyboardTotalBetContainerStyle.x;\n        this.totalBetTextContainer.y = this.componentConfiguration.keyboardTotalBetContainerStyle.y;\n\n        // Cancel and Done\n        this.cancelButton.x = this.componentConfiguration.cancelBtn.x;\n        this.cancelButton.y = this.componentConfiguration.cancelBtn.y;\n\n        this.doneButton.x = this.componentConfiguration.doneBtn.x;\n        this.doneButton.y = this.componentConfiguration.doneBtn.y;\n\n        // Keyboard buttons container\n        this.buttonsContainer.x = this.componentConfiguration.numericKeyboardButtonsContainerPosition.x;\n        this.buttonsContainer.y = this.componentConfiguration.numericKeyboardButtonsContainerPosition.y;\n\n        this.keyboardContainer.x = this.componentConfiguration.numericKeyboardContainerPosition.x;\n        if (this.isKeyboardVisible) {\n            this.keyboardContainer.y = this.componentConfiguration.numericKeyboardContainerPosition.y;\n        }\n\n        // this.showShadowBackground();\n        this.shadowBackground.width = Core.display.stage.width;\n        this.shadowBackground.height = Core.display.stage.height;\n\n        this.inputContainer.x = this.componentConfiguration.keyboardInputContainerConfig.containerX;\n        this.inputContainer.y = this.componentConfiguration.keyboardInputContainerConfig.containerY;\n        this.syncBalanceAndTotalBetTextScales();\n    }\n\n    private getNumericKeyboardButtonTexture(value: string): Texture {\n        switch (value) {\n            case '.':\n                return Core.assets.getAsset('svgButtonDot').texture;\n            case '<':\n                return Core.assets.getAsset('svgButtonClear').texture;\n            default:\n                return Core.assets.getAsset('svgButtonStandard').texture;\n        }\n    }\n\n    private onNumericKeyboardButtonClick(value: string): void {\n        if (!this.currentField) return;\n\n        if (value === '<') {\n            const current = this.currentField.getValue();\n            const newValue = current.slice(0, -1);\n\n            this.currentField.setValue(newValue);\n        } else {\n            const current = this.currentField.getValue();\n            this.currentField.setValue(current + value);\n        }\n        Core.sounds.play('autoplaySelectSound');\n    }\n\n    private crateInputFieldsContainer(): void {\n        this.inputContainer = new ViewContainer();\n        this.inputContainer.pivot.set(0, 0);\n        this.keyboardContainer.addChild(this.inputContainer);\n\n        this.inputField = new InputField({\n            containerX: this.componentConfiguration.keyboardInputContainerConfig.containerX,\n            containerY: this.componentConfiguration.keyboardInputContainerConfig.containerY,\n            fieldX: this.componentConfiguration.keyboardInputContainerConfig.fieldX,\n            fieldY: this.componentConfiguration.keyboardInputContainerConfig.fieldY,\n            fieldWidth: this.componentConfiguration.keyboardInputContainerConfig.fieldWidth,\n            fieldHeight: this.componentConfiguration.keyboardInputContainerConfig.fieldHeight,\n            fieldNormalTextStyle: this.componentConfiguration.keyboardInputContainerConfig.fieldNormalTextStyle,\n            fieldHilightedTextStyle: this.componentConfiguration.keyboardInputContainerConfig.fieldHilightedTextStyle,\n            currencyHilightedTextStyle:\n                this.componentConfiguration.keyboardInputContainerConfig.currencyHilightedTextStyle,\n            currencyNormaTextStyle: this.componentConfiguration.keyboardInputContainerConfig.currencyNormaTextStyle,\n            normalTexture: Core.assets.getTextureFromSpriteSheet('autoplayResources', 'inputNormal.png'),\n            hilightedTexture: Core.assets.getTextureFromSpriteSheet('autoplayResources', 'inputSelected.png'),\n            inputErrorTexture: Core.assets.getTextureFromSpriteSheet('autoplayResources', 'inputError.png'),\n            currency: this.currency,\n        });\n\n        this.inputContainer.addChild(this.inputField);\n\n        this.inputField.setMaxValue(1500000);\n\n        this.inputTitleText = new Text(\n            'titleText',\n            this.componentConfiguration.keyboardInputContainerConfig.titleTextStyle,\n        );\n        this.inputTitleText.x = this.componentConfiguration.keyboardInputContainerConfig.titleX;\n        this.inputTitleText.y = this.componentConfiguration.keyboardInputContainerConfig.titleY;\n        this.inputContainer.addChild(this.inputTitleText);\n\n        this.inputUnderTitle = new Text(\n            'underTitleText',\n            this.componentConfiguration.keyboardInputContainerConfig.underTitleTextStyle,\n        );\n        this.inputUnderTitle.x = this.componentConfiguration.keyboardInputContainerConfig.underTitleX;\n        this.inputUnderTitle.y = this.componentConfiguration.keyboardInputContainerConfig.underTitleY;\n        this.inputContainer.addChild(this.inputUnderTitle);\n\n        this.inputField.ERROR.subscribe((isError) => {\n            this.inputUnderTitle.style = isError\n                ? new TextStyle({\n                      ...this.inputUnderTitle.style,\n                      fill: this.componentConfiguration.keyboardInputContainerConfig.errorFill,\n                  })\n                : this.componentConfiguration.winOverContainerConfig.underTitleTextStyle;\n        });\n    }\n\n    public setCurrentField(field: InputField) {\n        this.currentField = field;\n    }\n\n    //Public update methods for external use\n\n    public updateKeyboardBalanceValue(value: string): void {\n        this.balanceValueText.text = value;\n        this.syncBalanceAndTotalBetTextScales();\n    }\n\n    public updateKeyboardBetValue(value: string): void {\n        this.totalBetValueText.text = value;\n        this.syncBalanceAndTotalBetTextScales();\n    }\n    private syncBalanceAndTotalBetTextScales(): void {\n        if (!this.balanceValueText || !this.totalBetValueText) return;\n        this.balanceValueText.scale.set(1);\n        this.totalBetValueText.scale.set(1);\n\n        const balanceTextMaxWidth = this.componentConfiguration.keyboardBalanceContainerStyle.maxWidth;\n        const totalBetMaxWidth = this.componentConfiguration.keyboardTotalBetContainerStyle.maxWidth;\n\n        const balanceValueTextWidth = this.balanceValueText.width;\n        const balanceValueTextScale = Math.min(1, balanceTextMaxWidth / balanceValueTextWidth);\n\n        const totalBetValueTextWidth = this.totalBetValueText.width;\n        const totalBetValueTextScale = Math.min(1, totalBetMaxWidth / totalBetValueTextWidth);\n\n        const finalScale = Math.min(balanceValueTextScale, totalBetValueTextScale);\n\n        this.balanceValueText.scale.set(finalScale);\n        this.totalBetValueText.scale.set(finalScale);\n    }\n}\n","const enum AutoplayPopupButtonStatesNumeric {\n    Normal,\n    Over,\n    Selected,\n    Disabled,\n}\n\nexport default AutoplayPopupButtonStatesNumeric;\n","import { Texture } from 'pixi.js';\n\nexport default class AutoplayPopupButtonTexturesNumeric {\n    constructor(\n        public normalTexture: Texture,\n        public selectedTexture: Texture,\n        public disabledTexture: Texture,\n        public overTexture: Texture,\n    ) {\n        //\n    }\n\n    public destroy() {\n        this.normalTexture.destroy();\n        // @ts-ignore\n        this.normalTexture = null;\n\n        this.selectedTexture.destroy();\n        // @ts-ignore\n        this.selectedTexture = null;\n\n        if (this.disabledTexture) {\n            this.disabledTexture.destroy();\n            // @ts-ignore\n            this.disabledTexture = null;\n        }\n\n        if (this.overTexture) {\n            this.overTexture.destroy();\n            // @ts-ignore\n            this.overTexture = null;\n        }\n    }\n}\n","import Core from '@egt/core';\nimport { ButtonShapes, ViewContainer } from '@egt/ui-lib';\nimport { Sprite, Text, TextStyle } from 'pixi.js';\nimport { Subject, fromEvent } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport AutoplayPopupButtonStatesNumeric from './AutoplayPopupButtonStatesNumeric';\nimport AutoplayNumericInputPopupStartButtonTextures from './AutoplayPopupButtonTexturesNumeric';\n\nexport default class AutoplayPopupComponentSettingButtonNumeric extends ViewContainer {\n    public readonly CLICK = new Subject();\n\n    public numberOfAutoPlays: number;\n    protected factor: number;\n    protected buttonBackground: Sprite;\n\n    protected _state: AutoplayPopupButtonStatesNumeric = AutoplayPopupButtonStatesNumeric.Normal;\n    protected _shape: ButtonShapes = ButtonShapes.Rectangle;\n\n    protected textures: AutoplayNumericInputPopupStartButtonTextures;\n    protected btnText: Text;\n    protected btnTextStyleNormal: TextStyle;\n    protected btnTextStyleSelected: TextStyle;\n    protected infinitySign: Sprite;\n\n    constructor(\n        numberOfAutoPlays: number,\n        textures: AutoplayNumericInputPopupStartButtonTextures,\n        btnTextStyleNormal: TextStyle,\n        btnTextStyleSelected: TextStyle,\n        width?: number,\n        height?: number,\n    ) {\n        super();\n        this.interactive = true;\n        this.numberOfAutoPlays = numberOfAutoPlays;\n        this.textures = textures;\n        this.btnTextStyleNormal = btnTextStyleNormal;\n        this.btnTextStyleSelected = btnTextStyleSelected;\n\n        this.createBtnBackground(width, height);\n        if (numberOfAutoPlays > 0) {\n            this.addBtnText();\n        } else {\n            this.addInfinitySign();\n        }\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/numeric/buttons/AutoplayPopupSettingButtonNumeric.ts:47:9\",(this.buttonBackground),\"pointerdown\"]), fromEvent(this.buttonBackground, 'pointerdown'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerDown.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/numeric/buttons/AutoplayPopupSettingButtonNumeric.ts:51:9\",(this.buttonBackground),\"pointerup\"]), fromEvent(this.buttonBackground, 'pointerup'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerUp.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/numeric/buttons/AutoplayPopupSettingButtonNumeric.ts:55:9\",(this.buttonBackground),\"pointerupoutside\"]), fromEvent(this.buttonBackground, 'pointerupoutside'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerOut.bind(this));\n\n        fromEvent(this.buttonBackground, 'pointerover')\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerOver.bind(this));\n\n        fromEvent(this.buttonBackground, 'pointerout')\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerOut.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/numeric/buttons/AutoplayPopupSettingButtonNumeric.ts:67:9\",(this.buttonBackground),\"pointertap\"]), fromEvent(this.buttonBackground, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerTap.bind(this));\n    }\n\n    public destroy(): void {\n        this.removeChildren();\n\n        this.buttonBackground.destroy({ children: true });\n        this.textures.destroy();\n        // @ts-ignore\n        this.textures = null;\n\n        if (this.btnText) {\n            this.btnText.destroy();\n            // @ts-ignore\n            this.btnText = null;\n        }\n\n        super.destroy();\n    }\n\n    public fakeClick(): void {\n        this.buttonBackground.emit('pointertap');\n    }\n\n    public onPointerDown(): void {\n        if (\n            this.state === AutoplayPopupButtonStatesNumeric.Disabled ||\n            this.state === AutoplayPopupButtonStatesNumeric.Selected\n        ) {\n            return;\n        }\n        this.state = AutoplayPopupButtonStatesNumeric.Over;\n    }\n\n    /**\n     *\n     */\n    public onPointerOut(): void {\n        if (\n            this.state === AutoplayPopupButtonStatesNumeric.Disabled ||\n            this.state === AutoplayPopupButtonStatesNumeric.Selected\n        ) {\n            return;\n        }\n        this.state = AutoplayPopupButtonStatesNumeric.Normal;\n    }\n\n    public setSelected(): void {\n        this.state = AutoplayPopupButtonStatesNumeric.Selected;\n        this.buttonBackground.texture = this.textures.selectedTexture;\n        if (this.btnText) {\n            this.btnText.style = this.btnTextStyleSelected;\n        }\n        if (this.infinitySign) {\n            this.infinitySign.texture = Core.assets.getAsset('infinityIconSelected').texture;\n        }\n    }\n\n    public setNormal(): void {\n        this.state = AutoplayPopupButtonStatesNumeric.Normal;\n        this.buttonBackground.texture = this.textures.normalTexture;\n        if (this.btnText) {\n            this.btnText.style = this.btnTextStyleNormal;\n        }\n        if (this.infinitySign) {\n            this.infinitySign.texture = Core.assets.getAsset('infinityIcon').texture;\n        }\n    }\n\n    protected addBtnText(): void {\n        this.btnText = new Text(this.numberOfAutoPlays, this.btnTextStyleNormal);\n        this.btnText.resolution = 2;\n        this.btnText.anchor.set(0.5);\n        this.btnText.x = this.width / 2;\n        this.btnText.y = this.height / 2;\n        this.addChild(this.btnText);\n    }\n\n    protected createBtnBackground(width?: number, height?: number): void {\n        this.buttonBackground = new Sprite(this.textures.normalTexture);\n        this.buttonBackground.interactive = true;\n        if (width) {\n            this.buttonBackground.width = width;\n        }\n        if (height) {\n            this.buttonBackground.height = height;\n        }\n        this.addChild(this.buttonBackground);\n    }\n\n    protected onPointerUp(): void {\n        if (\n            this.state === AutoplayPopupButtonStatesNumeric.Disabled ||\n            this.state === AutoplayPopupButtonStatesNumeric.Selected\n        ) {\n            return;\n        }\n        this.state = AutoplayPopupButtonStatesNumeric.Normal;\n    }\n\n    protected onPointerOver(): void {\n        if (\n            this.state === AutoplayPopupButtonStatesNumeric.Disabled ||\n            this.state === AutoplayPopupButtonStatesNumeric.Selected\n        ) {\n            return;\n        }\n        this.state = AutoplayPopupButtonStatesNumeric.Over;\n    }\n\n    protected onPointerTap(): void {\n        if (\n            this.state === AutoplayPopupButtonStatesNumeric.Disabled ||\n            this.state === AutoplayPopupButtonStatesNumeric.Selected\n        ) {\n            return;\n        }\n        this.CLICK.next(this);\n    }\n\n    protected getTexture(): AutoplayNumericInputPopupStartButtonTextures {\n        return this.textures;\n    }\n\n    protected addInfinitySign(): void {\n        this.infinitySign = new Sprite(Core.assets.getAsset('infinityIcon').texture);\n        this.infinitySign.anchor.set(0.5);\n        this.infinitySign.x = this.width / 2;\n        this.infinitySign.y = this.height / 2;\n        this.addChild(this.infinitySign);\n    }\n\n    get state(): AutoplayPopupButtonStatesNumeric {\n        return this._state;\n    }\n    set state(state: AutoplayPopupButtonStatesNumeric) {\n        this._state = state;\n        this.cursor = 'normal';\n        switch (state) {\n            case AutoplayPopupButtonStatesNumeric.Normal:\n                this.buttonBackground.texture = this.textures.normalTexture;\n                break;\n            case AutoplayPopupButtonStatesNumeric.Over:\n                this.cursor = 'pointer';\n                if (this.textures.overTexture) {\n                    this.buttonBackground.texture = this.textures.overTexture;\n                } else {\n                    this.buttonBackground.texture = this.textures.normalTexture;\n                }\n                break;\n            case AutoplayPopupButtonStatesNumeric.Selected:\n                this.buttonBackground.texture = this.textures.selectedTexture;\n                break;\n            case AutoplayPopupButtonStatesNumeric.Disabled:\n                if (this.textures.disabledTexture) {\n                    this.buttonBackground.texture = this.textures.disabledTexture;\n                } else {\n                    this.buttonBackground.texture = this.textures.normalTexture;\n                }\n                break;\n        }\n    }\n}\n","import Core from '@egt/core';\nimport { ButtonShapes, ViewContainer } from '@egt/ui-lib';\nimport { Sprite, Text, TextStyle } from 'pixi.js';\nimport { Subject, fromEvent } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport AutoplayPopupButtonStatesNumeric from './AutoplayPopupButtonStatesNumeric';\nimport AutoplayPopupButtonTexturesNumeric from './AutoplayPopupButtonTexturesNumeric';\n\nexport default class AutoplayPopupStartButtonNumeric extends ViewContainer {\n    public readonly CLICK = new Subject();\n\n    protected factor: number;\n    protected buttonBackground: Sprite;\n\n    protected _state: AutoplayPopupButtonStatesNumeric = AutoplayPopupButtonStatesNumeric.Normal;\n    protected _shape: ButtonShapes = ButtonShapes.Rectangle;\n\n    protected textures: AutoplayPopupButtonTexturesNumeric;\n    protected btnText: Text;\n    protected btnTextStyleNormal: TextStyle;\n    protected btnTextStyleDisabled: TextStyle;\n    protected infinitySign: Sprite;\n    protected label: string;\n    protected boundsBtnTextOffset: number = 20;\n\n    constructor(\n        label: string,\n        textures: AutoplayPopupButtonTexturesNumeric,\n        btnTextStyleNormal: TextStyle,\n        btnTextStyleDisabled?: TextStyle,\n    ) {\n        super();\n        this.interactive = true;\n        this.textures = textures;\n        this.btnTextStyleNormal = btnTextStyleNormal;\n        this.btnTextStyleDisabled = btnTextStyleDisabled ? btnTextStyleDisabled : btnTextStyleNormal;\n        this.label = label;\n\n        this.createBtnBackground();\n        this.addBtnText();\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/numeric/buttons/AutoplayPopupStartButtonNumeric.ts:42:9\",(this.buttonBackground),\"pointerdown\"]), fromEvent(this.buttonBackground, 'pointerdown'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerDown.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/numeric/buttons/AutoplayPopupStartButtonNumeric.ts:46:9\",(this.buttonBackground),\"pointerup\"]), fromEvent(this.buttonBackground, 'pointerup'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerUp.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/numeric/buttons/AutoplayPopupStartButtonNumeric.ts:50:9\",(this.buttonBackground),\"pointerupoutside\"]), fromEvent(this.buttonBackground, 'pointerupoutside'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerOut.bind(this));\n\n        fromEvent(this.buttonBackground, 'pointerover')\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerOver.bind(this));\n\n        fromEvent(this.buttonBackground, 'pointerout')\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerOut.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/numeric/buttons/AutoplayPopupStartButtonNumeric.ts:62:9\",(this.buttonBackground),\"pointertap\"]), fromEvent(this.buttonBackground, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerTap.bind(this));\n    }\n\n    public destroy(): void {\n        this.removeChildren();\n\n        this.buttonBackground.destroy({ children: true });\n        this.textures.destroy();\n        // @ts-ignore\n        this.textures = null;\n\n        this.btnText.destroy();\n        // @ts-ignore\n        this.btnText = null;\n\n        super.destroy();\n    }\n\n    public fakeClick(): void {\n        this.buttonBackground.emit('pointertap');\n    }\n\n    public onPointerDown(): void {\n        if (\n            this.state === AutoplayPopupButtonStatesNumeric.Disabled ||\n            this.state === AutoplayPopupButtonStatesNumeric.Selected\n        ) {\n            return;\n        }\n        this.state = AutoplayPopupButtonStatesNumeric.Over;\n    }\n\n    /**\n     *\n     */\n    public onPointerOut(): void {\n        if (\n            this.state === AutoplayPopupButtonStatesNumeric.Disabled ||\n            this.state === AutoplayPopupButtonStatesNumeric.Selected\n        ) {\n            return;\n        }\n        this.state = AutoplayPopupButtonStatesNumeric.Normal;\n    }\n\n    public setDisabled(): void {\n        this.state = AutoplayPopupButtonStatesNumeric.Disabled;\n        this.buttonBackground.texture = this.textures.disabledTexture;\n        this.btnText.style = this.btnTextStyleDisabled;\n        this.fitBtnTextInBounds();\n    }\n\n    public setNormal(): void {\n        this.state = AutoplayPopupButtonStatesNumeric.Normal;\n        this.buttonBackground.texture = this.textures.normalTexture;\n        this.btnText.style = this.btnTextStyleNormal;\n    }\n\n    protected addBtnText(): void {\n        this.btnText = new Text(this.label, this.btnTextStyleNormal);\n        this.btnText.resolution = 2;\n        this.btnText.anchor.set(0.5);\n        this.btnText.x = this.width / 2;\n        this.btnText.y = this.height / 2;\n        this.fitBtnTextInBounds();\n        this.addChild(this.btnText);\n    }\n\n    protected fitBtnTextInBounds(): void {\n        if (!this.btnText || !this.buttonBackground) return;\n\n        this.btnText.scale.set(1);\n\n        const maxWidth = this.buttonBackground.width - this.boundsBtnTextOffset;\n        const scale = Math.min(1, maxWidth / this.btnText.width);\n\n        if (this.btnText.scale.x !== scale) {\n            this.btnText.scale.set(scale);\n        }\n    }\n\n    protected createBtnBackground(): void {\n        this.buttonBackground = new Sprite(this.textures.normalTexture);\n        this.buttonBackground.interactive = true;\n        this.addChild(this.buttonBackground);\n    }\n\n    protected onPointerUp(): void {\n        if (\n            this.state === AutoplayPopupButtonStatesNumeric.Disabled ||\n            this.state === AutoplayPopupButtonStatesNumeric.Selected\n        ) {\n            return;\n        }\n        this.state = AutoplayPopupButtonStatesNumeric.Over;\n    }\n\n    protected onPointerOver(): void {\n        if (\n            this.state === AutoplayPopupButtonStatesNumeric.Disabled ||\n            this.state === AutoplayPopupButtonStatesNumeric.Selected\n        ) {\n            return;\n        }\n        this.state = AutoplayPopupButtonStatesNumeric.Over;\n    }\n\n    protected onPointerTap(): void {\n        if (\n            this.state === AutoplayPopupButtonStatesNumeric.Disabled ||\n            this.state === AutoplayPopupButtonStatesNumeric.Selected\n        ) {\n            return;\n        }\n        this.CLICK.next(this);\n    }\n\n    protected getTexture(): AutoplayPopupButtonTexturesNumeric {\n        return this.textures;\n    }\n\n    protected addInfinitySign(): void {\n        this.infinitySign = new Sprite(Core.assets.getAsset('svgInfinity').texture);\n        this.infinitySign.anchor.set(0.5);\n        this.infinitySign.x = this.width / 2;\n        this.infinitySign.y = this.height / 2;\n        this.addChild(this.infinitySign);\n    }\n\n    get state(): AutoplayPopupButtonStatesNumeric {\n        return this._state;\n    }\n    set state(state: AutoplayPopupButtonStatesNumeric) {\n        this._state = state;\n        this.buttonBackground.cursor = 'normal';\n        switch (state) {\n            case AutoplayPopupButtonStatesNumeric.Normal:\n                this.buttonBackground.texture = this.textures.normalTexture;\n                break;\n            case AutoplayPopupButtonStatesNumeric.Over:\n                this.buttonBackground.cursor = 'pointer';\n                if (this.textures.overTexture) {\n                    this.buttonBackground.texture = this.textures.overTexture;\n                } else {\n                    this.buttonBackground.texture = this.textures.normalTexture;\n                }\n                break;\n            case AutoplayPopupButtonStatesNumeric.Selected:\n                this.buttonBackground.texture = this.textures.selectedTexture;\n                break;\n            case AutoplayPopupButtonStatesNumeric.Disabled:\n                if (this.textures.disabledTexture) {\n                    this.buttonBackground.texture = this.textures.disabledTexture;\n                } else {\n                    this.buttonBackground.texture = this.textures.normalTexture;\n                }\n                break;\n        }\n    }\n}\n","import {\n    AssetPriority,\n    AssetsCollection,\n    BaseComponentConfiguration,\n    DefaultAssets,\n    DefaultValue,\n    DynamicPositionObject,\n} from '@egt/core';\nimport { TextStyle } from 'pixi.js';\nimport {\n    IAutoPlayArrowPositionsNumeric,\n    IAutoPlayPositionsNumeric,\n    IAutoPlaySelectedBtnPositionsNumeric,\n    IAutoplayBtnTextNumeric,\n    IAutoplayPopUpTextNumeric,\n    IAutoplayPopUpTitleTextNumeric,\n    IAutoplayPositionObjectNumeric,\n    IBalanceAndBetTextNumeric,\n    IMainContainerPositionNumeric,\n    // ISliderPositionObject,\n\n    IAutoplayKeyboardButtonPositionNumeric,\n    IAutoplayPopUpMandatoryTextNumeric,\n    IAutoplayPopupConfigurationNumeric,\n} from '../interfaces/InterfacesNumeric';\nimport {\n    IInputFieldObject,\n    IContainerGraphicsInterfaceNumeric,\n    IKeyboardButtonsContainerPositionNumeric,\n    IKeyboardButtonTextConfigNumeric,\n    IKeyboardContainerPositionNumeric,\n    IKeyboardRowPositionNumeric,\n    IKeyboardScaleConfigNumeric,\n    IKeyboardShadowBackgroundConfigNumeric,\n    IPopUpCancelButtonInterface,\n    IPopUpDoneButtonInterface,\n} from '@egt/ui-lib';\n\nexport default class AutoplayPopupComponentConfigurationNumeric extends BaseComponentConfiguration {}\nexport function AutoplayPopupConfigFactoryNumeric(): any {\n    class AutoplayPopupComponentConfigurationNumericInternalClass\n        extends AutoplayPopupComponentConfigurationNumeric\n        implements IAutoplayPopupConfigurationNumeric\n    {\n        public buttonsToHide = ['betButtons', 'autoPlayButton'];\n\n        public mainViewComponentsToHide = ['balanceContainer', 'winContainer'];\n\n        @DefaultAssets([\n            {\n                id: 'autoplayResources',\n                url: '../assets/components/slot/autoplay-popup/common/autoplayResources.json',\n                priority: AssetPriority.HIGHEST,\n                type: 'texture',\n            },\n            {\n                id: 'numericInput',\n                url: '../assets/components/slot/autoplay-popup/numeric/numericInput.json',\n                priority: AssetPriority.HIGHEST,\n                type: 'texture',\n            },\n            {\n                id: 'svgClose',\n                url: '../assets/components/slot/autoplay-popup/numeric/ui-svg/close.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 60, height: 60 },\n                },\n            },\n            {\n                id: 'svgButtonDone',\n                url: '../assets/components/slot/autoplay-popup/numeric/ui-svg/buttonDone.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 108, height: 60 },\n                },\n            },\n            {\n                id: 'svgButtonStandard',\n                url: '../assets/components/slot/autoplay-popup/numeric/ui-svg/buttonStandard.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 100, height: 51 },\n                },\n            },\n            {\n                id: 'svgButtonDot',\n                url: '../assets/components/slot/autoplay-popup/numeric/ui-svg/buttonDot.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 100, height: 51 },\n                },\n            },\n            {\n                id: 'svgButtonClear',\n                url: '../assets/components/slot/autoplay-popup/numeric/ui-svg/buttonClear.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 100, height: 51 },\n                },\n            },\n            {\n                id: 'svgAutoplaySelected',\n                url: '../assets/components/slot/autoplay-popup/numeric/ui-svg/autoplaySelected.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 132, height: 132 },\n                    desktop: { width: 99, height: 99 },\n                },\n            },\n            {\n                id: 'svgAutoplayPopUpHover',\n                url: '../assets/components/slot/autoplay-popup/numeric/ui-svg/autoplayPopUpHover.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 104, height: 74 },\n                    desktop: { width: 104, height: 74 },\n                },\n            },\n            {\n                id: 'svgAutoplayPopUpNormal',\n                url: '../assets/components/slot/autoplay-popup/numeric/ui-svg/autoplayPopUpNormal.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 104, height: 74 },\n                    desktop: { width: 104, height: 74 },\n                },\n            },\n            {\n                id: 'svgAutoplayPopUpSelected',\n                url: '../assets/components/slot/autoplay-popup/numeric/ui-svg/autoplayPopUpSelected.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 104, height: 74 },\n                    desktop: { width: 104, height: 74 },\n                },\n            },\n            {\n                id: 'svgAutoplayStartDisabled',\n                url: '../assets/components/slot/autoplay-popup/numeric/ui-svg/autoplayStartDisabled.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 222, height: 78 },\n                    desktop: { width: 222, height: 78 },\n                },\n            },\n            {\n                id: 'svgAutoplayStartHover',\n                url: '../assets/components/slot/autoplay-popup/numeric/ui-svg/autoplayStartHover.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 222, height: 78 },\n                    desktop: { width: 222, height: 78 },\n                },\n            },\n            {\n                id: 'svgAutoplayStartNormal',\n                url: '../assets/components/slot/autoplay-popup/numeric/ui-svg/autoplayStartNormal.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 222, height: 78 },\n                    desktop: { width: 222, height: 78 },\n                },\n            },\n            {\n                id: 'infinityIcon',\n                url: '../assets/components/slot/autoplay-popup/common/ui-svg/infinityIcon.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 46, height: 45 },\n                    desktop: { width: 46, height: 45 },\n                },\n            },\n            {\n                id: 'infinityIconSelected',\n                url: '../assets/components/slot/autoplay-popup/common/ui-svg/infinityIconSelected.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 46, height: 45 },\n                    desktop: { width: 46, height: 45 },\n                },\n            },\n        ])\n        public assets: AssetsCollection;\n\n        @DefaultValue<IMainContainerPositionNumeric>({\n            defaults: {\n                x: 0,\n                y: 0,\n                leftHandX: -276,\n            },\n        })\n        public mainContainerPosition: DynamicPositionObject<IMainContainerPositionNumeric> &\n            IMainContainerPositionNumeric;\n\n        @DefaultValue<IAutoplayPopUpTitleTextNumeric>({\n            defaults: {\n                yOffset: 30,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                    fontSize: 36,\n                    fill: '#FFFFFF',\n                    align: 'center',\n                }),\n            },\n        })\n        public popUpTitle: DynamicPositionObject<IAutoplayPopUpTitleTextNumeric> & IAutoplayPopUpTitleTextNumeric;\n\n        @DefaultValue<IBalanceAndBetTextNumeric>({\n            defaults: {\n                x: 466,\n                y: 695,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFD200',\n                    fontSize: 24,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                valueStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 36,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                currencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 22,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n            },\n            portrait: {\n                x: 31,\n                y: 916,\n            },\n        })\n        public balanceText: DynamicPositionObject<IBalanceAndBetTextNumeric> & IBalanceAndBetTextNumeric;\n\n        @DefaultValue<IBalanceAndBetTextNumeric>({\n            defaults: {\n                x: 1169,\n                y: 695,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFD200',\n                    fontSize: 24,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                valueStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 36,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                currencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 22,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n            },\n            portrait: {\n                x: 734,\n                y: 916,\n            },\n        })\n        public betText: DynamicPositionObject<IBalanceAndBetTextNumeric> & IBalanceAndBetTextNumeric;\n\n        @DefaultValue<IAutoplayPopUpTextNumeric>({\n            defaults: {\n                x: 818,\n                y: 91,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                    fontSize: 28,\n                    lineHeight: 30,\n                    fill: '#FFFFFF',\n                    align: 'center',\n                }),\n            },\n            portrait: {\n                x: 383,\n                y: 310,\n            },\n        })\n        public stopOnTitle: DynamicPositionObject<IAutoplayPopUpTextNumeric> & IAutoplayPopUpTextNumeric;\n\n        @DefaultValue<IAutoplayPopUpTextNumeric>({\n            defaults: {\n                x: 818,\n                y: 435,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                    fontSize: 28,\n                    fill: '#FFFFFF',\n                    align: 'center',\n                }),\n            },\n            portrait: {\n                x: 382,\n                y: 656,\n            },\n        })\n        public autoplayTitle: DynamicPositionObject<IAutoplayPopUpTextNumeric> & IAutoplayPopUpTextNumeric;\n\n        @DefaultValue<IAutoplayBtnTextNumeric>({\n            defaults: {\n                xOffset: 6,\n                width: 108,\n                height: 78,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    fontSize: 42,\n                    fill: '#C6C5C5',\n                    align: 'center',\n                }),\n                selectedTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    fontSize: 42,\n                    fill: '#FFFFFF',\n                    align: 'center',\n                }),\n            },\n        })\n        public buttonValueText: DynamicPositionObject<IAutoplayBtnTextNumeric> & IAutoplayBtnTextNumeric;\n\n        @DefaultValue<IAutoPlayPositionsNumeric>({\n            defaults: {\n                x: 536,\n                y: 473,\n            },\n            portrait: {\n                y: 694,\n            },\n        })\n        public buttonsContainerPositions: DynamicPositionObject<IAutoPlayPositionsNumeric> & IAutoPlayPositionsNumeric;\n\n        @DefaultValue<IAutoplayPositionObjectNumeric>({\n            defaults: {\n                width: 744,\n                height: 715,\n                x: 446,\n                y: 2,\n            },\n            portrait: {\n                x: 10,\n                y: 224,\n            },\n        })\n        public popUpGraphicsContainer: DynamicPositionObject<IAutoplayPositionObjectNumeric> &\n            IAutoplayPositionObjectNumeric;\n\n        @DefaultValue<IAutoplayPositionObjectNumeric>({\n            defaults: {\n                width: 704,\n                height: 334,\n                x: 466,\n                y: 78,\n            },\n            portrait: {\n                x: 30,\n                y: 300,\n            },\n        })\n        public popUpFirstSectionPosition: DynamicPositionObject<IAutoplayPositionObjectNumeric> &\n            IAutoplayPositionObjectNumeric;\n\n        @DefaultValue<IAutoplayPositionObjectNumeric>({\n            defaults: {\n                width: 704,\n                height: 139,\n                x: 466,\n                y: 423,\n            },\n            portrait: {\n                x: 30,\n                y: 644,\n            },\n        })\n        public popUpSecondSectionPosition: DynamicPositionObject<IAutoplayPositionObjectNumeric> &\n            IAutoplayPositionObjectNumeric;\n\n        @DefaultValue<IAutoplayPopUpTextNumeric>({\n            defaults: {\n                x: 0,\n                y: -20,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                    fontSize: 36,\n                    fill: '#FFFFFF',\n                    align: 'center',\n                }),\n            },\n        })\n        public buttonNormalText: DynamicPositionObject<IAutoplayPopUpTextNumeric> & IAutoplayPopUpTextNumeric;\n\n        @DefaultValue<IAutoplayPopUpTextNumeric>({\n            defaults: {\n                x: 0,\n                y: -20,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                    fontSize: 36,\n                    fill: '#818c86',\n                    align: 'center',\n                }),\n            },\n        })\n        public buttonDisabledText: DynamicPositionObject<IAutoplayPopUpTextNumeric> & IAutoplayPopUpTextNumeric;\n\n        @DefaultValue<IAutoPlayPositionsNumeric>({\n            defaults: {\n                x: 707,\n                y: 571,\n            },\n            portrait: {\n                x: 271,\n                y: 792,\n            },\n        })\n        public startAutoplayBtn: DynamicPositionObject<IAutoPlayPositionsNumeric> & IAutoPlayPositionsNumeric;\n\n        @DefaultValue<IPopUpDoneButtonInterface>({\n            defaults: {\n                x: 614,\n                y: 7,\n                width: 108,\n                height: 60,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                    fontSize: 25.5,\n                    fill: '#FFFFFF',\n                    align: 'center',\n                }),\n                scale: 1,\n            },\n            portrait: {\n                scale: 1.334,\n                x: 592,\n                y: 10,\n            },\n        })\n        public doneBtn: DynamicPositionObject<IPopUpDoneButtonInterface> & IPopUpDoneButtonInterface;\n\n        @DefaultValue<IPopUpCancelButtonInterface>({\n            defaults: {\n                x: 536,\n                y: 7,\n                width: 60,\n                height: 60,\n                scale: 1,\n            },\n            portrait: {\n                scale: 1.334,\n                x: 488,\n                y: 10,\n            },\n        })\n        public cancelBtn: DynamicPositionObject<IPopUpCancelButtonInterface> & IPopUpCancelButtonInterface;\n\n        @DefaultValue<IAutoPlayArrowPositionsNumeric>({\n            defaults: {\n                x: 1186,\n                y: 127,\n                angle: 270,\n                leftHandX: 174,\n                leftHandY: 76,\n                leftHandAngle: 90,\n            },\n            portrait: {\n                x: 200,\n                y: 933,\n                angle: 0,\n            },\n            desktop: {\n                y: 228,\n            },\n        })\n        public arrowPosition: DynamicPositionObject<IAutoPlayArrowPositionsNumeric> & IAutoPlayArrowPositionsNumeric;\n\n        @DefaultValue<IAutoPlaySelectedBtnPositionsNumeric>({\n            defaults: {\n                x: 1285,\n                y: 99,\n                leftHandX: 75,\n                scale: 1,\n            },\n            portrait: {\n                x: 187,\n                y: 1060,\n            },\n            desktop: {\n                x: 1271,\n                y: 203,\n            },\n        })\n        selectedButton: DynamicPositionObject<IAutoPlaySelectedBtnPositionsNumeric> &\n            IAutoPlaySelectedBtnPositionsNumeric;\n\n        @DefaultValue<IInputFieldObject>({\n            defaults: {\n                containerX: 488,\n                containerY: 126,\n                fieldWidth: 235,\n                fieldHeight: 60,\n                fieldX: 428,\n                fieldY: 2,\n                titleX: 0,\n                titleY: 10,\n                underTitleX: -1,\n                underTitleY: -6,\n                errorFill: '#FF0000',\n                titleTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Book, RobotoCondensed-Bold, Arial',\n                    fontSize: 30,\n                    fill: '#FFFFFF',\n                    trim: true,\n                }),\n                titleTextMaxWidth: 425,\n                underTitleTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Book, RobotoCondensed-Bold, Arial',\n                    fontSize: 20,\n                    fill: '#8A8A8A',\n                    trim: true,\n                }),\n                fieldNormalTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                    fontSize: 28,\n                    fill: '#FFFFFF',\n                }),\n                fieldHilightedTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                    fontSize: 28,\n                    fill: '#FFD200',\n                }),\n                currencyNormaTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                    fontSize: 20,\n                    fill: '#FFFFFF',\n                }),\n                currencyHilightedTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                    fontSize: 20,\n                    fill: '#FFD200',\n                }),\n            },\n            portrait: {\n                containerX: 52,\n                containerY: 346,\n            },\n        })\n        public maxLossAmountContainerConfig: DynamicPositionObject<IInputFieldObject> & IInputFieldObject;\n\n        @DefaultValue<IInputFieldObject>({\n            defaults: {\n                containerX: 488,\n                containerY: 198,\n                fieldWidth: 235,\n                fieldHeight: 60,\n                fieldX: 428,\n                fieldY: 2,\n                titleX: 0,\n                titleY: 10,\n                underTitleX: -1,\n                underTitleY: -6,\n                errorFill: '#FF0000',\n                titleTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Book, RobotoCondensed-Bold, Arial',\n                    fontSize: 30,\n                    fill: '#FFFFFF',\n                    trim: true,\n                }),\n                titleTextMaxWidth: 425,\n                underTitleTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Book, RobotoCondensed-Bold, Arial',\n                    fontSize: 20,\n                    fill: '#8A8A8A',\n                    trim: true,\n                }),\n                fieldNormalTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                    fontSize: 28,\n                    fill: '#FFFFFF',\n                }),\n                fieldHilightedTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                    fontSize: 28,\n                    fill: '#FFD200',\n                }),\n                currencyNormaTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                    fontSize: 20,\n                    fill: '#FFFFFF',\n                }),\n                currencyHilightedTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                    fontSize: 20,\n                    fill: '#FFD200',\n                }),\n            },\n            portrait: {\n                containerX: 52,\n                containerY: 418,\n            },\n        })\n        public balanceLessThanContainerConfig: DynamicPositionObject<IInputFieldObject> & IInputFieldObject;\n\n        @DefaultValue<IInputFieldObject>({\n            defaults: {\n                containerX: 488,\n                containerY: 270,\n                fieldWidth: 235,\n                fieldHeight: 60,\n                fieldX: 428,\n                fieldY: 2,\n                titleX: 0,\n                titleY: 10,\n                underTitleX: -1,\n                underTitleY: -6,\n                errorFill: '#FF0000',\n                titleTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Book, RobotoCondensed-Bold, Arial',\n                    fontSize: 30,\n                    fill: '#FFFFFF',\n                    trim: true,\n                }),\n                titleTextMaxWidth: 425,\n                underTitleTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Book, RobotoCondensed-Bold, Arial',\n                    fontSize: 20,\n                    fill: '#8A8A8A',\n                    trim: true,\n                }),\n                fieldNormalTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                    fontSize: 28,\n                    fill: '#FFFFFF',\n                }),\n                fieldHilightedTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                    fontSize: 28,\n                    fill: '#FFD200',\n                }),\n                currencyNormaTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                    fontSize: 20,\n                    fill: '#FFFFFF',\n                }),\n                currencyHilightedTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                    fontSize: 20,\n                    fill: '#FFD200',\n                }),\n            },\n            portrait: {\n                containerX: 52,\n                containerY: 490,\n            },\n        })\n        public balanceMoreThanContainerConfig: DynamicPositionObject<IInputFieldObject> & IInputFieldObject;\n\n        @DefaultValue<IInputFieldObject>({\n            defaults: {\n                containerX: 488,\n                containerY: 342,\n                fieldWidth: 235,\n                fieldHeight: 60,\n                fieldX: 428,\n                fieldY: 2,\n                titleX: 0,\n                titleY: 10,\n                underTitleX: -1,\n                underTitleY: -6,\n                errorFill: '#FF0000',\n                titleTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Book, RobotoCondensed-Bold, Arial',\n                    fontSize: 30,\n                    fill: '#FFFFFF',\n                    trim: true,\n                }),\n                titleTextMaxWidth: 425,\n                underTitleTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Book, RobotoCondensed-Bold, Arial',\n                    fontSize: 20,\n                    fill: '#8A8A8A',\n                    trim: true,\n                }),\n                fieldNormalTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                    fontSize: 28,\n                    fill: '#FFFFFF',\n                }),\n                fieldHilightedTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                    fontSize: 28,\n                    fill: '#FFD200',\n                }),\n                currencyNormaTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                    fontSize: 20,\n                    fill: '#FFFFFF',\n                }),\n                currencyHilightedTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                    fontSize: 20,\n                    fill: '#FFD200',\n                }),\n            },\n            portrait: {\n                containerX: 52,\n                containerY: 562,\n            },\n        })\n        public winOverContainerConfig: DynamicPositionObject<IInputFieldObject> & IInputFieldObject;\n\n        @DefaultValue<IContainerGraphicsInterfaceNumeric>({\n            defaults: {\n                width: 745,\n                height: 361,\n                x: 0,\n                y: 0,\n                lineHeight: 1,\n                topLineX: 0,\n                topLineY: 0,\n                separatorLineX: 0,\n                separatorLineY: 73,\n            },\n            portrait: {\n                height: 495,\n                x: 0,\n                y: 0,\n                topLineX: 0,\n                topLineY: 0,\n                lineHeight: 1,\n                separatorLineX: 0,\n                separatorLineY: 99,\n            },\n        })\n        public autoPlayNumericContainerGraphicsConfig: DynamicPositionObject<IContainerGraphicsInterfaceNumeric> &\n            IContainerGraphicsInterfaceNumeric;\n\n        @DefaultValue<IKeyboardShadowBackgroundConfigNumeric>({\n            defaults: {\n                x: 0,\n                y: 761,\n                width: -260,\n                height: 619,\n            },\n            portrait: {\n                x: 0,\n                y: -260,\n                width: 765,\n                height: 619,\n            },\n        })\n        public numericKeyboardShadowBackground: DynamicPositionObject<IKeyboardShadowBackgroundConfigNumeric> &\n            IKeyboardShadowBackgroundConfigNumeric;\n\n        @DefaultValue<IBalanceAndBetTextNumeric>({\n            defaults: {\n                x: 78,\n                y: 347,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFD200',\n                    fontSize: 24,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                valueStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 36,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                currencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 22,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n            },\n            portrait: {\n                x: 30,\n                y: 467,\n            },\n        })\n        public balanceTextKeyboard: IBalanceAndBetTextNumeric;\n\n        @DefaultValue<IBalanceAndBetTextNumeric>({\n            defaults: {\n                x: 649,\n                y: 347,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFD200',\n                    fontSize: 24,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                valueStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 36,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                currencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 22,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n            },\n            portrait: {\n                x: 710,\n                y: 463,\n            },\n        })\n        public betTextKeyboard: IBalanceAndBetTextNumeric;\n\n        @DefaultValue<IKeyboardButtonsContainerPositionNumeric>({\n            defaults: {\n                x: 215,\n                y: 82,\n            },\n            portrait: {\n                x: 193,\n                y: 124,\n            },\n        })\n        public numericKeyboardButtonsContainerPosition: DynamicPositionObject<IKeyboardButtonsContainerPositionNumeric> &\n            IKeyboardButtonsContainerPositionNumeric;\n\n        @DefaultValue<IKeyboardContainerPositionNumeric>({\n            defaults: {\n                x: 444,\n                y: 404,\n                leftHandX: 170,\n            },\n            portrait: {\n                x: 0,\n                y: 876,\n            },\n        })\n        public numericKeyboardContainerPosition: DynamicPositionObject<IKeyboardContainerPositionNumeric> &\n            IKeyboardContainerPositionNumeric;\n\n        @DefaultValue<IKeyboardButtonTextConfigNumeric>({\n            defaults: {\n                width: 100,\n                height: 51,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    fontSize: 36,\n                    fill: '#FFFFFF',\n                    align: 'center',\n                }),\n            },\n        })\n        public numericKeyboardButtonText: DynamicPositionObject<IKeyboardButtonTextConfigNumeric> &\n            IKeyboardButtonTextConfigNumeric;\n\n        public numericKeyboardRowPositions: Array<DynamicPositionObject<IKeyboardRowPositionNumeric>> = [\n            new DynamicPositionObject<IKeyboardRowPositionNumeric>({\n                defaults: { x: 0, y: 0, width: 300, height: 51 },\n                portrait: { x: 0, y: 0, width: 300, height: 51 },\n            }),\n            new DynamicPositionObject<IKeyboardRowPositionNumeric>({\n                defaults: { x: 0, y: 60, width: 300, height: 51 },\n                portrait: { x: 0, y: 80, width: 300, height: 51 },\n            }),\n            new DynamicPositionObject<IKeyboardRowPositionNumeric>({\n                defaults: { x: 0, y: 120, width: 300, height: 51 },\n                portrait: { x: 0, y: 160, width: 300, height: 51 },\n            }),\n            new DynamicPositionObject<IKeyboardRowPositionNumeric>({\n                defaults: { x: 0, y: 183, width: 300, height: 51 },\n                portrait: { x: 0, y: 246, width: 300, height: 51 },\n            }),\n        ];\n\n        public numericKeyboardBtnPositions: Array<DynamicPositionObject<IAutoplayKeyboardButtonPositionNumeric>> = [\n            new DynamicPositionObject<IAutoplayKeyboardButtonPositionNumeric>({\n                defaults: { x: 0 },\n                portrait: { x: 0 },\n            }),\n            new DynamicPositionObject<IAutoplayKeyboardButtonPositionNumeric>({\n                defaults: { x: 109 },\n                portrait: { x: 146 },\n            }),\n            new DynamicPositionObject<IAutoplayKeyboardButtonPositionNumeric>({\n                defaults: { x: 218 },\n                portrait: { x: 292 },\n            }),\n        ];\n\n        public numericKeyboardButtonValues: string[][] = [\n            ['1', '2', '3'],\n            ['4', '5', '6'],\n            ['7', '8', '9'],\n            ['.', '0', '<'],\n        ];\n\n        @DefaultValue<IKeyboardScaleConfigNumeric>({\n            defaults: { scale: 1 },\n            portrait: { scale: 1.34 },\n        })\n        public numericKeyboardScale: DynamicPositionObject<IKeyboardScaleConfigNumeric> & IKeyboardScaleConfigNumeric;\n\n        @DefaultValue<IAutoplayPopUpMandatoryTextNumeric>({\n            defaults: {\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                    fontSize: 26,\n                    lineHeight: 30,\n                    fill: '#FF0000',\n                    align: 'right',\n                }),\n            },\n        })\n        public mandatoryText: DynamicPositionObject<IAutoplayPopUpMandatoryTextNumeric> &\n            IAutoplayPopUpMandatoryTextNumeric;\n    }\n\n    return AutoplayPopupComponentConfigurationNumericInternalClass;\n}\n","import Core, { BaseController } from '@egt/core';\nimport { FeatureController, InitialSettings, RootStore } from '@egt/slot';\nimport { fromEvent, merge } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport AutoplayPopupComponentSettingButtonNumeric from '../buttons/AutoplayPopupSettingButtonNumeric';\nimport { IAutoplayPopupConfigurationNumeric } from '../interfaces/InterfacesNumeric';\nimport AutoplayPopupViewNumeric from '../views/AutoplayPopupViewNumeric';\nimport { InputField } from '@egt/ui-lib';\n\n@injectable()\nexport default class AutoplayPopupControllerNumeric extends BaseController {\n    private numberOfAutoPlays: number;\n    private activeInputField: InputField | null = null;\n    constructor(\n        @inject('AutoplayPopupView') protected autoplayNumericInputPopup: AutoplayPopupViewNumeric,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('AutoplayPopupComponentConfiguration')\n        protected componentConfiguration: IAutoplayPopupConfigurationNumeric,\n        @inject('FeatureController') protected featureController: FeatureController,\n    ) {\n        super(autoplayNumericInputPopup);\n    }\n\n    public init(): void {\n        if (!this.settings.autoplay) {\n            return;\n        }\n        this.attachEventListeners();\n    }\n\n    public attachEventListeners(): void {\n        this.rootStore.uiStore.BALANCE.pipe(takeUntil(this.DESTROY)).subscribe(this.onBalanceChanged.bind(this));\n        this.rootStore.uiStore.SELECTED_BET.pipe(takeUntil(this.DESTROY)).subscribe(this.onBetChanged.bind(this));\n        Core.SELECTED_DENOMINATION.pipe(takeUntil(this.DESTROY)).subscribe(this.onBetChanged.bind(this));\n        this.rootStore.subjects.TOGGLE_AUTOPLAY_POPUP.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.toggleAutoplayPopup.bind(this),\n        );\n        this.rootStore.subjects.CLOSE_ALL_POPUPS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.forceClosePopup.bind(this),\n        );\n        const closeFlow = merge(this.DESTROY, this.rootStore.subjects.CLOSE_AUTOPLAY_POPUP);\n        closeFlow.pipe(takeUntil(closeFlow)).subscribe(this.closePopup.bind(this, false));\n\n        this.autoplayNumericInputPopup.CLOSE.pipe(takeUntil(this.DESTROY)).subscribe(this.closePopup.bind(this, true));\n        this.rootStore.subjects.MODAL_PRESSED.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.closePopup(true);\n            this.autoplayNumericInputPopup.hideNumericKeyboardField(true);\n        });\n\n        this.rootStore.subjects.FACTOR_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(this.onFactorChanged.bind(this));\n\n        this.rootStore.subjects.RESET_AUTOPLAY_RESTRICTIONS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.resetAutoPlayRestrictions.bind(this),\n        );\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/numeric/controllers/AutoplayPopupControllerNumeric.ts:58:9\",(this.autoplayNumericInputPopup.selectedBtn),\"pointerup\"]), fromEvent(this.autoplayNumericInputPopup.selectedBtn, 'pointerup'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(() => {\n                this.autoplayNumericInputPopup.hideNumericKeyboardField(true);\n                this.closePopup(true);\n            });\n\n        this.autoplayNumericInputPopup.startAutoplayButton.CLICK.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.startAutoplay.bind(this),\n        );\n\n        for (const btn of this.autoplayNumericInputPopup.autoplayButtons) {\n            btn.CLICK.pipe(takeUntil(this.DESTROY)).subscribe(this.onChoseAutoPlayBtn.bind(this));\n        }\n\n        this.addInputFieldsEventListeners();\n        if (Core.isDesktopMode) {\n            this.rootStore.subjects.KEY_DOWN.pipe(takeUntil(this.DESTROY)).subscribe(this.onKeyDown.bind(this));\n        }\n    }\n\n    public destroy(): void {\n        super.destroy();\n    }\n\n    private handleInputFieldFocus(selectedField: InputField): void {\n        for (const field of this.autoplayNumericInputPopup.inputFields) {\n            if (field === selectedField) {\n                field.setActive();\n                this.activeInputField = field;\n            } else {\n                // field.confirmValue();\n                field.setInactive();\n            }\n        }\n    }\n\n    private addInputFieldsEventListeners(): void {\n        for (const field of this.autoplayNumericInputPopup.inputFields) {\n            field.FOCUS.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n                this.handleInputFieldFocus(field);\n                this.autoplayNumericInputPopup.showNumericKeyboardField(field);\n            });\n        }\n    }\n\n    private onKeyDown = (e: KeyboardEvent) => {\n        if (e === null || !this.activeInputField) {\n            return;\n        }\n        if (/^[0-9.]$/.test(e.key)) {\n            const newValue = this.activeInputField.getValue() + e.key;\n            this.activeInputField.setValue(newValue);\n        } else if (e.key === 'Backspace') {\n            const value = this.activeInputField.getValue();\n            // const newValue = value.slice(0, -1);\n            this.activeInputField.setValue(value.slice(0, -1));\n\n            // if (newValue.length === 0) {\n            //     this.activeInputField.setInactive();\n            // }\n        }\n    };\n\n    protected startAutoplay(): void {\n        this.rootStore.uiStore.balanceIncreaseValue = this.autoplayNumericInputPopup.balanceMore * 100;\n        this.rootStore.uiStore.balanceDecreaseValue = this.autoplayNumericInputPopup.balanceLess * 100;\n        this.rootStore.uiStore.winLimitValue = this.autoplayNumericInputPopup.winOver * 100;\n        if (!this.featureController.isInGiftSpins) {\n            this.rootStore.uiStore.maxTotalLossLimit = this.autoplayNumericInputPopup.maxLoss * 100;\n        }\n\n        this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.next(this.numberOfAutoPlays);\n        this.forceClosePopup();\n        this.rootStore.subjects.START_AUTOPLAY.next(this.numberOfAutoPlays);\n        // this.autoplayNumericInputPopup.shouldSetUiStoreFieldValues = false;\n        this.autoplayNumericInputPopup.resetInputFields();\n    }\n\n    protected resetAutoPlayRestrictions(): void {\n        this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.next(0);\n        this.rootStore.uiStore.autoPlayFromSettings = false;\n        // this.autoplayNumericInputPopup.shouldSetUiStoreFieldValues = true;\n        this.autoplayNumericInputPopup.resetInputFields();\n    }\n\n    protected onFactorChanged(): void {\n        this.autoplayNumericInputPopup.updateBetValue();\n        this.autoplayNumericInputPopup.updateUnderTitleTexts();\n    }\n\n    private onBalanceChanged(): void {\n        this.autoplayNumericInputPopup.updateBalance();\n        this.autoplayNumericInputPopup.updateUnderTitleTexts();\n    }\n\n    private onBetChanged(): void {\n        this.autoplayNumericInputPopup.updateBetValue();\n        this.autoplayNumericInputPopup.updateUnderTitleTexts();\n    }\n\n    private onChoseAutoPlayBtn(button: AutoplayPopupComponentSettingButtonNumeric): void {\n        for (const btn of this.autoplayNumericInputPopup.autoplayButtons) {\n            if (btn === button) {\n                Core.sounds.play('autoplaySelectSound');\n                btn.setSelected();\n                this.numberOfAutoPlays = button.numberOfAutoPlays;\n            } else {\n                btn.setNormal();\n            }\n        }\n    }\n\n    private toggleAutoplayPopup(): void {\n        if (this.autoplayNumericInputPopup.isOpened) {\n            this.closePopup();\n        } else {\n            this.openPopup();\n        }\n    }\n\n    private closePopup(animation: boolean = true): void {\n        if (this.autoplayNumericInputPopup.isOpened) {\n            Core.sounds.play('hideDenominationsSound');\n            this.toggleCustomButtons(true);\n            this.autoplayNumericInputPopup.close(animation);\n            this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(false);\n            this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_OUTSIDE_BETS_VISIBLE.next(true);\n            this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(false);\n        }\n    }\n\n    private forceClosePopup(): void {\n        if (this.autoplayNumericInputPopup.isOpened) {\n            this.toggleCustomButtons(true);\n            this.autoplayNumericInputPopup.forceClose();\n            this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(false);\n            this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_OUTSIDE_BETS_VISIBLE.next(true);\n            this.autoplayNumericInputPopup.hideNumericKeyboardField(true);\n            this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(false);\n        }\n    }\n\n    private openPopup(animation: boolean = true): void {\n        if (!this.autoplayNumericInputPopup.isOpened) {\n            Core.sounds.play('showDenominationsSound');\n            this.rootStore.subjects.CLOSE_ALL_POPUPS.next();\n            this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(true);\n            this.autoplayNumericInputPopup.open(animation);\n            this.numberOfAutoPlays = this.autoplayNumericInputPopup.autoplayButtons[0].numberOfAutoPlays;\n            this.toggleCustomButtons(false);\n            this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(false);\n            this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_OUTSIDE_BETS_VISIBLE.next(false);\n        }\n    }\n\n    protected toggleCustomButtons(visible: boolean): void {\n        this.componentConfiguration.buttonsToHide.forEach((btnName) => {\n            if (btnName === 'betButtons') {\n                this.rootStore.uiStore.SHOW_HIDE_BET_BUTTONS.next(visible);\n                if (this.featureController.isInGiftSpins) {\n                    this.rootStore.uiStore.SHOW_HIDE_GIFT_SPINS_VIEW.next(visible);\n                }\n            } else {\n                this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                    name: btnName,\n                    actions: 'visible',\n                    values: visible,\n                });\n            }\n        });\n\n        this.componentConfiguration.mainViewComponentsToHide.forEach((mainViewComponent) => {\n            this.rootStore.subjects.SHOW_HIDE_MAIN_VIEW_COMPONENTS.next({\n                name: mainViewComponent,\n                actions: 'visible',\n                values: visible,\n            });\n        });\n    }\n}\n\nexport enum MandatoryValuesNumeric {\n    BALANCE_LES = 'lossLimits',\n    BALANCE_MORE = 'winLimits',\n    WIN_OVER = 'singleWinLimit',\n    MAX_LOSS = 'maxLoss',\n}\n","import Core, { Money, MoneyFormatter } from '@egt/core';\nimport { InitialSettings, RootStore } from '@egt/slot';\nimport {\n    Button,\n    ButtonShapes,\n    IInputFieldObject,\n    InputField,\n    KeyboardActionButtonNumeric,\n    KeyboardButtonNumeric,\n    KeyboardNumeric,\n    ViewContainer,\n} from '@egt/ui-lib';\nimport { gsap } from 'gsap';\nimport { Container, NineSlicePlane, Sprite, Text, TextStyle } from 'pixi.js';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport AutoplayNumericInputPopupStartButtonTextures from '../buttons/AutoplayPopupButtonTexturesNumeric';\nimport AutoplayPopupComponentSettingButtonNumeric from '../buttons/AutoplayPopupSettingButtonNumeric';\nimport AutoplayNumericInputPopupButton from '../buttons/AutoplayPopupStartButtonNumeric';\nimport { MandatoryValuesNumeric } from '../controllers/AutoplayPopupControllerNumeric';\nimport { IAutoplayPopupConfigurationNumeric } from '../interfaces/InterfacesNumeric';\n\n@injectable()\nexport default class AutoplayPopupViewNumeric extends ViewContainer {\n    public CLOSE = new Subject();\n    // Main containers\n    public mainContainer: Container;\n    public graphicsContainer: Container;\n\n    // Popup buttons and actions\n    public autoplayButtons: AutoplayPopupComponentSettingButtonNumeric[] = [];\n    public startAutoplayButton: AutoplayNumericInputPopupButton;\n    public buttonValues: number[];\n    public selectedBtn: Button;\n\n    // Popup values and limits\n    public maxLoss: number;\n    public balanceLess: number;\n    public balanceMore: number;\n    public winOver: number;\n\n    // Popup graphics and texts\n    private autoplayButtonsContainer: Sprite;\n    private popUpBackground: NineSlicePlane;\n    private popUpShadow: NineSlicePlane;\n    private popUpFirstSection: NineSlicePlane;\n    private popUpSecondSection: NineSlicePlane;\n    private popUpTitleText: Text;\n    private stopOn: Text;\n    private autoplay: Text;\n\n    // Inputfields containers and fields\n    private mandatory: MandatoryValuesNumeric[];\n    private maxLossAmountFieldContainer: ViewContainer;\n    private maxLossAmountField: InputField;\n    private balanceLessThanFieldContainer: ViewContainer;\n    private balanceLessThanField: InputField;\n    private balanceMoreThanFieldContainer: ViewContainer;\n    private balanceMoreThanField: InputField;\n    private winOverFieldContainer: ViewContainer;\n    private winOverField: InputField;\n    public inputFields: InputField[] = [];\n\n    // Balance and Bet text and containers\n    private balanceContainer: Sprite;\n    private balanceText: Text;\n    private balanceTextValue: Text;\n    private balanceTextCurrency: Text;\n    private betContainer: Sprite;\n    private betText: Text;\n    private betTextValue: Text;\n    private betTextCurrency: Text;\n    private balanceMoneyFormatter: Money;\n    private betMoneyFormatter: Money;\n    private wordSpacing: number = 6;\n    private minBet: number = 0;\n\n    // Arrow\n    private arrow: Sprite;\n    private _isOpened: boolean = false;\n    private animationTween: any;\n    private startingPoint: number = 250;\n    private bounceOffset: number = 15;\n\n    // Inpufields under titles\n    private maxLossUnderTitle: Text;\n    private balanceLessUnderTitle: Text;\n    private balanceMoreUnderTitle: Text;\n    private winOverUnderTitle: Text;\n    private underTitleTexts: Map<InputField, Text> = new Map();\n\n    // Keyboard\n    private numericKeyboard: KeyboardNumeric;\n    private currentField: InputField;\n    private numericKeyboardTween: any;\n    private isKeyboardVisible: boolean = false;\n\n    //utility\n    // public shouldSetUiStoreFieldValues = true;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('AutoplayPopupComponentConfiguration')\n        protected componentConfiguration: IAutoplayPopupConfigurationNumeric,\n    ) {\n        super();\n    }\n\n    public init(): void {\n        if (!this.settings.autoplay) {\n            return;\n        }\n        this.buttonValues = this.settings.settings.settings.jurisdiction.autoplayRestrictions.autoPlays;\n        this.mandatory = this.settings.autoplayRestrictions.mandatory;\n        this.createGraphicsContainer();\n        this.createMainContainer();\n        this.createSelectedBtn();\n        this.crateAutoplayPopUp();\n        this.close(false);\n        this.createBalanceText();\n        this.createBetText();\n\n        Core.LEFT_HAND_MODE.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/autoplay-popup/src/egt/modes/numeric/views/AutoplayPopupViewNumeric.ts:128:9\",(Core.stage.stage),\"pointertap\"]), Core.stage.stage.on('pointertap', this.onPopUpClick, this));\n    }\n\n    public destroy(): void {\n        this.killAllAnimations();\n        this.killNumericKeyboardTween();\n        this.destroyObject(this.mainContainer);\n        this.destroyObject(this.graphicsContainer);\n        this.destroyObject(this.startAutoplayButton);\n        this.destroyObject(this.selectedBtn);\n        this.destroyObject(this.autoplayButtonsContainer);\n        this.destroyObject(this.popUpBackground);\n        this.destroyObject(this.popUpShadow);\n        this.destroyObject(this.popUpFirstSection);\n        this.destroyObject(this.popUpSecondSection);\n        this.destroyObject(this.popUpTitleText);\n        this.destroyObject(this.stopOn);\n        this.destroyObject(this.autoplay);\n        this.destroyObject(this.maxLossAmountFieldContainer);\n        this.destroyObject(this.balanceLessThanFieldContainer);\n        this.destroyObject(this.balanceMoreThanFieldContainer);\n        this.destroyObject(this.winOverFieldContainer);\n        this.destroyObject(this.maxLossAmountField);\n        this.destroyObject(this.balanceLessThanField);\n        this.destroyObject(this.balanceMoreThanField);\n        this.destroyObject(this.winOverField);\n        this.destroyObject(this.maxLossUnderTitle);\n        this.destroyObject(this.balanceLessUnderTitle);\n        this.destroyObject(this.balanceMoreUnderTitle);\n        this.destroyObject(this.winOverUnderTitle);\n        this.destroyObject(this.balanceContainer);\n        this.destroyObject(this.balanceText);\n        this.destroyObject(this.balanceTextValue);\n        this.destroyObject(this.balanceTextCurrency);\n        this.destroyObject(this.betContainer);\n        this.destroyObject(this.betText);\n        this.destroyObject(this.betTextValue);\n        this.destroyObject(this.betTextCurrency);\n        this.destroyObject(this.balanceMoneyFormatter);\n        this.destroyObject(this.betMoneyFormatter);\n        this.destroyObject(this.arrow);\n        this.destroyArray(this.autoplayButtons);\n        this.destroyArray(this.buttonValues);\n        this.destroyArray(this.mandatory);\n        this.underTitleTexts.clear();\n\n        this.removeChildren();\n        super.destroy();\n    }\n\n    public get isOpened(): boolean {\n        return this._isOpened;\n    }\n\n    public set isOpened(value: boolean) {\n        this._isOpened = value;\n    }\n\n    public open(animation: boolean): void {\n        this.isOpened = true;\n        this.killAllAnimations();\n        this.resetButtons();\n\n        for (const field of this.inputFields) {\n            field.setInactive();\n        }\n        this.checkForMandatory();\n\n        this.mainContainer.alpha = 0;\n        this.mainContainer.y = this.componentConfiguration.mainContainerPosition.y + this.startingPoint;\n        this.mainContainer.visible = true;\n\n        const arrowY =\n            Core.LEFT_HAND_MODE.value && Core.ORIENTATION.value.isLandscape\n                ? this.componentConfiguration.arrowPosition.leftHandY\n                : this.componentConfiguration.arrowPosition.y;\n        this.arrow.alpha = 0;\n        this.arrow.y = arrowY + this.startingPoint;\n        this.arrow.visible = true;\n\n        this.selectedBtn.visible = true;\n        this.selectedBtn.alpha = 1;\n\n        if (animation) {\n            this.animationTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/autoplay-popup/src/egt/modes/numeric/views/AutoplayPopupViewNumeric.ts:212:35\",null]), gsap.timeline());\n\n            const animateAlpha = (alpha: number, duration: number) => ({\n                alpha,\n                duration,\n            });\n            const animateBounce = (y: number, duration: number, ease: string) => ({\n                y,\n                duration,\n                ease,\n            });\n\n            const mainContainerY = this.componentConfiguration.mainContainerPosition.y;\n\n            const onComplete = () => {\n                this.graphicsContainer.alpha = 1;\n                this.graphicsContainer.visible = true;\n            };\n\n            this.animationTween\n                .to(this.mainContainer, animateAlpha(1, 0.3), 0)\n                .to(this.arrow, animateAlpha(1, 0.3), '<')\n                .to(this.mainContainer, animateBounce(mainContainerY - this.bounceOffset, 0.25, 'power1.out'), 0)\n                .to(this.arrow, animateBounce(arrowY - this.bounceOffset, 0.25, 'power1.out'), '<')\n                .to(this.mainContainer, animateBounce(mainContainerY, 0.2, 'power1.in'), 0.25)\n                .to(\n                    this.arrow,\n                    {\n                        ...animateBounce(arrowY, 0.2, 'power1.in'),\n                        onComplete,\n                    },\n                    '<',\n                );\n        } else {\n            this.mainContainer.alpha = 1;\n            this.arrow.alpha = 1;\n            this.graphicsContainer.alpha = 1;\n            this.graphicsContainer.visible = true;\n        }\n    }\n\n    public forceClose(): void {\n        this.isOpened = false;\n        this.killAllAnimations();\n        this.noVisibility();\n        this.graphicsContainer.alpha = 0;\n        this.graphicsContainer.visible = false;\n        this.selectedBtn.alpha = 0;\n        this.selectedBtn.visible = false;\n        this.resetInputFields();\n    }\n\n    public close(animation: boolean): void {\n        this.isOpened = false;\n        this.killAllAnimations();\n\n        for (const field of this.inputFields) {\n            field.setInactive();\n        }\n        this.graphicsContainer.alpha = 0;\n        this.graphicsContainer.visible = false;\n        this.mainContainer.alpha = 1;\n        this.mainContainer.visible = true;\n        this.arrow.alpha = 1;\n        this.arrow.visible = true;\n        this.selectedBtn.alpha = 0;\n        this.selectedBtn.visible = false;\n        this.resetInputFields();\n        const arrowY =\n            Core.LEFT_HAND_MODE.value && Core.ORIENTATION.value.isLandscape\n                ? this.componentConfiguration.arrowPosition.leftHandY\n                : this.componentConfiguration.arrowPosition.y;\n\n        if (animation) {\n            this.animationTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/autoplay-popup/src/egt/modes/numeric/views/AutoplayPopupViewNumeric.ts:286:35\",null]), gsap.timeline());\n\n            const animateBounce = (alpha: number, y: number, duration: number) => ({\n                alpha,\n                y,\n                duration,\n            });\n\n            const mainContainerY = this.componentConfiguration.mainContainerPosition.y;\n\n            const onComplete = () => {\n                this.noVisibility();\n            };\n\n            this.animationTween\n                .to(this.mainContainer, animateBounce(0, mainContainerY + this.startingPoint, 0.3))\n                .to(this.arrow, { ...animateBounce(0, arrowY + this.startingPoint, 0.3), onComplete }, '<');\n        } else {\n            this.noVisibility();\n        }\n    }\n\n    public noVisibility() {\n        this.mainContainer.alpha = 0;\n        this.mainContainer.visible = false;\n        this.arrow.alpha = 0;\n        this.arrow.visible = false;\n    }\n\n    public resetInputFields(): void {\n        this.maxLossAmountField.resetToInitial();\n        this.balanceLessThanField.resetToInitial();\n        this.balanceMoreThanField.resetToInitial();\n        this.winOverField.resetToInitial();\n    }\n\n    public updateBetValue(): void {\n        this.betMoneyFormatter.amountMoney = this.getTotalBet();\n        this.betTextValue.text = this.betMoneyFormatter.stringMoney;\n        this.positionBetBalance();\n        this.fitBetBalanceInBounds();\n        if (this.numericKeyboard) {\n            this.numericKeyboard.updateKeyboardBetValue(this.betTextValue.text);\n        }\n    }\n\n    public updateBalance(): void {\n        this.balanceMoneyFormatter.amountMoney = this.rootStore.uiStore.BALANCE.value;\n        this.balanceTextValue.text = this.balanceMoneyFormatter.stringMoney;\n        this.positionBetBalance();\n        this.fitBetBalanceInBounds();\n        if (this.numericKeyboard) {\n            this.numericKeyboard.updateKeyboardBalanceValue(this.balanceTextValue.text);\n        }\n    }\n\n    public updateUnderTitleTexts(): void {\n        const currency = this.rootStore.settings.currency;\n        if (this.maxLossUnderTitle) {\n            this.maxLossUnderTitle.text = this.getRangeText(\n                this.getTotalBet(),\n                this.rootStore.uiStore.BALANCE.value,\n                currency,\n            );\n        }\n        if (this.balanceLessUnderTitle) {\n            this.balanceLessUnderTitle.text = this.getRangeText(this.minBet, this.getLessBalance(), currency);\n        }\n        if (this.balanceMoreUnderTitle) {\n            this.balanceMoreUnderTitle.text = this.getRangeText(this.minBet, this.getMoreBalance(), currency);\n        }\n        if (this.winOverUnderTitle) {\n            this.winOverUnderTitle.text = this.getRangeText(this.minBet, this.getWinOver(), currency);\n        }\n\n        this.maxLossAmountField.setMaxValue(this.rootStore.uiStore.BALANCE.value);\n        this.maxLossAmountField.setMinValue(this.getTotalBet());\n        this.balanceLessThanField.setMaxValue(this.getLessBalance());\n        this.balanceMoreThanField.setMaxValue(this.getMoreBalance());\n        this.winOverField.setMaxValue(this.getWinOver());\n    }\n\n    public fitBetBalanceInBounds(): void {\n        const maxWidth = this.betContainer.x - this.balanceContainer.x;\n        const balanceWidth =\n            this.balanceText.width +\n            this.balanceTextValue.width +\n            this.balanceTextCurrency.width +\n            2 * this.wordSpacing;\n        const betWidth =\n            this.betText.width + this.betTextValue.width + this.betTextCurrency.width + 2 * this.wordSpacing;\n        const actualWidth = balanceWidth + this.wordSpacing + betWidth;\n        this.betContainer.scale.set(1);\n        this.balanceContainer.scale.set(1);\n        if (actualWidth > maxWidth) {\n            const scaleFactor = maxWidth / actualWidth;\n            this.betContainer.scale.set(scaleFactor);\n            this.balanceContainer.scale.set(scaleFactor);\n            this.positionBetBalance();\n        }\n    }\n\n    public positionBetBalance(): void {\n        this.balanceTextCurrency.x = this.balanceTextValue.x + this.balanceTextValue.width + this.wordSpacing;\n        this.betTextCurrency.x = this.betTextValue.x + this.betTextValue.width + this.wordSpacing;\n        this.betContainer.pivot.set(\n            this.betText.width + this.betTextValue.width + this.betTextCurrency.width + 2 * this.wordSpacing,\n            0,\n        );\n    }\n\n    protected onPopUpClick(e): void {\n        if (!this.isOpened) {\n            return;\n        }\n        if (\n            !(\n                e.target.parent instanceof InputField ||\n                e.target.parent instanceof KeyboardActionButtonNumeric ||\n                e.target.parent instanceof KeyboardButtonNumeric ||\n                (e.target.parent.parent instanceof KeyboardNumeric && e.target.name !== 'shadowBackground') ||\n                e.target.parent instanceof KeyboardActionButtonNumeric\n            )\n        ) {\n            this.deselectInput();\n            if (this.numericKeyboard && this.numericKeyboard.visible) {\n                this.hideNumericKeyboardField(true);\n            }\n        }\n    }\n\n    protected onShadowClicked(): void {\n        this.CLOSE.next();\n    }\n\n    protected deselectInput(): void {\n        for (const inputField of this.inputFields) {\n            inputField.setInactive();\n        }\n    }\n\n    private resetButtons(): void {\n        for (let i: number = 0; i < this.autoplayButtons.length; i++) {\n            if (i === 0) {\n                this.autoplayButtons[i].setSelected();\n            } else {\n                this.autoplayButtons[i].setNormal();\n            }\n        }\n    }\n\n    private createBalanceText(): void {\n        const balanceConfig = this.componentConfiguration.balanceText;\n        const currency = this.rootStore.settings.currency;\n\n        this.balanceMoneyFormatter = new Money(this.rootStore.uiStore.BALANCE.value);\n        this.balanceContainer = new Sprite();\n        this.mainContainer.addChild(this.balanceContainer);\n\n        this.balanceText = new Text(Core.translator.translate('BALANCE') + ':', balanceConfig.textStyle);\n        this.balanceText.resolution = 2;\n        this.balanceText.pivot.set(0, this.balanceText.height);\n        this.balanceContainer.addChild(this.balanceText);\n\n        this.balanceTextValue = new Text(this.balanceMoneyFormatter.stringMoney, balanceConfig.valueStyle);\n        this.balanceTextValue.pivot.set(0, this.balanceTextValue.height);\n        this.balanceTextValue.resolution = 2;\n        this.balanceTextValue.x = this.balanceText.x + this.balanceText.width + this.wordSpacing;\n        this.balanceContainer.addChild(this.balanceTextValue);\n\n        this.balanceTextCurrency = new Text(currency, balanceConfig.currencyStyle);\n        this.balanceTextCurrency.pivot.set(0, this.balanceTextCurrency.height);\n        this.balanceTextCurrency.resolution = 2;\n        this.balanceTextCurrency.x = this.balanceTextValue.x + this.balanceTextValue.width + this.wordSpacing;\n        this.balanceContainer.addChild(this.balanceTextCurrency);\n    }\n\n    private createBetText(): void {\n        const betConfig = this.componentConfiguration.betText;\n        const currency = this.rootStore.settings.currency;\n\n        this.betMoneyFormatter = new Money(this.settings.bet * this.settings.denomination * this.settings.factor);\n        this.betContainer = new Sprite();\n        this.mainContainer.addChild(this.betContainer);\n\n        this.betText = new Text(Core.translator.translate('BET') + ':', betConfig.textStyle);\n        this.betText.resolution = 2;\n        this.betText.pivot.set(0, this.betText.height);\n        this.betContainer.addChild(this.betText);\n\n        this.betTextValue = new Text(this.betMoneyFormatter.stringMoney, betConfig.valueStyle);\n        this.betTextValue.resolution = 2;\n        this.betTextValue.pivot.set(0, this.betTextValue.height);\n        this.betTextValue.x = this.betText.x + this.betText.width + this.wordSpacing;\n        this.betContainer.addChild(this.betTextValue);\n\n        this.betTextCurrency = new Text(currency, betConfig.currencyStyle);\n        this.betTextCurrency.resolution = 2;\n        this.betTextCurrency.pivot.set(0, this.betTextCurrency.height);\n        this.betTextCurrency.x = this.betTextValue.x + this.betTextValue.width + this.wordSpacing;\n        this.betContainer.addChild(this.betTextCurrency);\n    }\n\n    private crateAutoplayPopUp(): void {\n        this.createPopupGraphics();\n        this.createPopUpTexts();\n        this.createStartBtn();\n        this.createArrow();\n        this.crateInputFieldsContainers();\n        this.autoplayButtonsContainer = new Sprite();\n        this.mainContainer.addChild(this.autoplayButtonsContainer);\n        for (let i: number = 0; i < this.buttonValues.length; i++) {\n            this.createAutoplayValueButtons(this.buttonValues[i], i);\n        }\n    }\n\n    private createPopupGraphics(): void {\n        this.popUpShadow = new NineSlicePlane(\n            Core.assets.getTextureFromSpriteSheet('autoplayResources', 'shadow.png'),\n            45,\n            45,\n            45,\n            45,\n        );\n        this.popUpShadow.name = 'popUpShadow';\n        this.mainContainer.addChild(this.popUpShadow);\n\n        this.popUpBackground = new NineSlicePlane(\n            Core.assets.getTextureFromSpriteSheet('autoplayResources', 'popup.png'),\n            60,\n            60,\n            60,\n            60,\n        );\n        this.popUpBackground.interactive = true;\n        this.mainContainer.addChild(this.popUpBackground);\n\n        this.popUpFirstSection = new NineSlicePlane(\n            Core.assets.getTextureFromSpriteSheet('autoplayResources', 'popupFill.png'),\n            15,\n            15,\n            15,\n            15,\n        );\n        this.mainContainer.addChild(this.popUpFirstSection);\n\n        this.popUpSecondSection = new NineSlicePlane(\n            Core.assets.getTextureFromSpriteSheet('autoplayResources', 'popupFill.png'),\n            15,\n            15,\n            15,\n            15,\n        );\n        this.mainContainer.addChild(this.popUpSecondSection);\n    }\n\n    private createPopUpTexts(): void {\n        this.popUpTitleText = new Text(\n            Core.translator.translate('AUTOPLAY SETTINGS'),\n            this.componentConfiguration.popUpTitle.textStyle,\n        );\n        this.popUpTitleText.resolution = 2;\n        this.popUpTitleText.anchor.set(0.5);\n        this.mainContainer.addChild(this.popUpTitleText);\n\n        this.stopOn = new Text(\n            Core.translator.translate('STOP ON').toUpperCase(),\n            this.componentConfiguration.stopOnTitle.textStyle,\n        );\n        this.stopOn.resolution = 2;\n        this.stopOn.anchor.set(0.5, 0);\n        this.mainContainer.addChild(this.stopOn);\n\n        this.autoplay = new Text(\n            Core.translator.translate('Autoplay').toUpperCase(),\n            this.componentConfiguration.autoplayTitle.textStyle,\n        );\n        this.autoplay.resolution = 2;\n        this.autoplay.anchor.set(0.5, 0);\n        this.mainContainer.addChild(this.autoplay);\n    }\n\n    private createArrow(): void {\n        this.arrow = new Sprite(Core.assets.getTextureFromSpriteSheet('autoplayResources', 'arrow.png'));\n        this.addChild(this.arrow);\n    }\n\n    protected getTotalBet(): number {\n        return Core.SELECTED_DENOMINATION.value * this.rootStore.uiStore.SELECTED_BET.value * this.settings.factor;\n    }\n\n    private getLessBalance(): number {\n        return (this.rootStore.uiStore.BALANCE.value * this.settings.autoplayRestrictions.lossLimits) / 100;\n    }\n\n    private getMoreBalance(): number {\n        return (this.rootStore.uiStore.BALANCE.value * this.settings.autoplayRestrictions.winLimits) / 100;\n    }\n\n    private getWinOver(): number {\n        return this.getTotalBet() * this.settings.autoplayRestrictions.singleWinLimit;\n    }\n\n    private crateInputFieldsContainers(): void {\n        this.maxLossAmountFieldContainer = new ViewContainer();\n        this.maxLossAmountFieldContainer.pivot.set(0, 0);\n        this.maxLossAmountField = this.createInputField(\n            this.maxLossAmountFieldContainer,\n            this.componentConfiguration.maxLossAmountContainerConfig,\n        );\n\n        this.balanceLessThanFieldContainer = new ViewContainer();\n        this.balanceLessThanFieldContainer.pivot.set(0, 0);\n        this.balanceLessThanField = this.createInputField(\n            this.balanceLessThanFieldContainer,\n            this.componentConfiguration.balanceLessThanContainerConfig,\n        );\n\n        this.balanceMoreThanFieldContainer = new ViewContainer();\n        this.balanceMoreThanFieldContainer.pivot.set(0, 0);\n        this.balanceMoreThanField = this.createInputField(\n            this.balanceMoreThanFieldContainer,\n            this.componentConfiguration.balanceMoreThanContainerConfig,\n        );\n\n        this.winOverFieldContainer = new ViewContainer();\n        this.winOverFieldContainer.pivot.set(0, 0);\n        this.winOverField = this.createInputField(\n            this.winOverFieldContainer,\n            this.componentConfiguration.winOverContainerConfig,\n        );\n\n        this.maxLossAmountField.setMaxValue(this.rootStore.uiStore.BALANCE.value);\n        this.balanceLessThanField.setMaxValue(this.getLessBalance());\n        this.balanceMoreThanField.setMaxValue(this.getMoreBalance());\n        this.winOverField.setMaxValue(this.getWinOver());\n\n        this.maxLossAmountField.INPUT.pipe(takeUntil(this.DESTROY)).subscribe((value: string) => {\n            this.maxLoss = Number(value);\n            // if (this.shouldSetUiStoreFieldValues) {\n            //     this.rootStore.uiStore.maxTotalLossLimit = this.maxLoss * 100;\n            // }\n            this.checkForMandatory();\n        });\n        this.balanceLessThanField.INPUT.pipe(takeUntil(this.DESTROY)).subscribe((value: string) => {\n            this.balanceLess = Number(value);\n            // if (this.shouldSetUiStoreFieldValues) {\n            //     this.rootStore.uiStore.balanceDecreaseValue = this.balanceLess * 100;\n            // }\n            this.checkForMandatory();\n        });\n        this.balanceMoreThanField.INPUT.pipe(takeUntil(this.DESTROY)).subscribe((value: string) => {\n            this.balanceMore = Number(value);\n            // if (this.shouldSetUiStoreFieldValues) {\n            //     this.rootStore.uiStore.balanceIncreaseValue = this.balanceMore * 100;\n            // }\n            this.checkForMandatory();\n        });\n        this.winOverField.INPUT.pipe(takeUntil(this.DESTROY)).subscribe((value: string) => {\n            this.winOver = Number(value);\n            // if (this.shouldSetUiStoreFieldValues) {\n            //     this.rootStore.uiStore.winLimitValue = this.winOver * 100;\n            // }\n            this.checkForMandatory();\n        });\n\n        this.crateInputsTexts();\n\n        this.underTitleTexts.set(this.maxLossAmountField, this.maxLossUnderTitle);\n        this.underTitleTexts.set(this.balanceLessThanField, this.balanceLessUnderTitle);\n        this.underTitleTexts.set(this.balanceMoreThanField, this.balanceMoreUnderTitle);\n        this.underTitleTexts.set(this.winOverField, this.winOverUnderTitle);\n\n        this.maxLossAmountField.ERROR.subscribe((isError) => {\n            this.maxLossUnderTitle.style = isError\n                ? new TextStyle({ ...this.maxLossUnderTitle.style, fill: '#FF0000' })\n                : this.componentConfiguration.maxLossAmountContainerConfig.underTitleTextStyle;\n            this.checkForMandatory();\n        });\n        this.balanceLessThanField.ERROR.subscribe((isError) => {\n            this.balanceLessUnderTitle.style = isError\n                ? new TextStyle({ ...this.balanceLessUnderTitle.style, fill: '#FF0000' })\n                : this.componentConfiguration.balanceLessThanContainerConfig.underTitleTextStyle;\n            this.checkForMandatory();\n        });\n        this.balanceMoreThanField.ERROR.subscribe((isError) => {\n            this.balanceMoreUnderTitle.style = isError\n                ? new TextStyle({ ...this.balanceMoreUnderTitle.style, fill: '#FF0000' })\n                : this.componentConfiguration.balanceMoreThanContainerConfig.underTitleTextStyle;\n            this.checkForMandatory();\n        });\n        this.winOverField.ERROR.subscribe((isError) => {\n            this.winOverUnderTitle.style = isError\n                ? new TextStyle({ ...this.winOverUnderTitle.style, fill: '#FF0000' })\n                : this.componentConfiguration.winOverContainerConfig.underTitleTextStyle;\n            this.checkForMandatory();\n        });\n    }\n\n    private createInputField(container: Container, config: IInputFieldObject): InputField {\n        this.mainContainer.addChild(container);\n        const inputField = new InputField({\n            containerX: config.containerX,\n            containerY: config.containerY,\n            fieldX: config.fieldX,\n            fieldY: config.fieldY,\n            fieldWidth: config.fieldWidth,\n            fieldHeight: config.fieldHeight,\n            fieldNormalTextStyle: config.fieldNormalTextStyle,\n            fieldHilightedTextStyle: config.fieldHilightedTextStyle,\n            currencyHilightedTextStyle: config.currencyHilightedTextStyle,\n            currencyNormaTextStyle: config.currencyNormaTextStyle,\n            normalTexture: Core.assets.getTextureFromSpriteSheet('numericInput', 'inputNormal.png'),\n            hilightedTexture: Core.assets.getTextureFromSpriteSheet('numericInput', 'inputSelected.png'),\n            inputErrorTexture: Core.assets.getTextureFromSpriteSheet('numericInput', 'inputError.png'),\n            currency: this.rootStore.settings.currency,\n        });\n        container.addChild(inputField);\n\n        this.inputFields.push(inputField);\n\n        return inputField;\n    }\n\n    private setTextProps(\n        text: Text,\n        textValue: string,\n        style: TextStyle,\n        anchor: { x: number; y: number },\n        x: number,\n        y: number,\n    ): void {\n        text.text = textValue;\n        text.style = style;\n        text.resolution = 2;\n        text.anchor.set(anchor.x, anchor.y);\n        text.x = x;\n        text.y = y;\n    }\n\n    private crateInputsTexts(): void {\n        const currency = this.rootStore.settings.currency;\n\n        // MAX LOSS\n        const maxLossTitle = new Text();\n        this.setTextProps(\n            maxLossTitle,\n            this.toSentenceCase(Core.translator.translate('MAX LOSS')),\n            this.componentConfiguration.maxLossAmountContainerConfig.titleTextStyle,\n            { x: 0, y: 0 },\n            this.componentConfiguration.maxLossAmountContainerConfig.titleX,\n            this.componentConfiguration.maxLossAmountContainerConfig.titleY,\n        );\n        this.maxLossAmountFieldContainer.addChild(maxLossTitle);\n\n        this.maxLossUnderTitle = this.createUnderTitleText(\n            this.maxLossAmountFieldContainer,\n            this.getRangeText(this.minBet, this.rootStore.uiStore.BALANCE.value, currency),\n            this.componentConfiguration.maxLossAmountContainerConfig.underTitleTextStyle,\n            this.componentConfiguration.maxLossAmountContainerConfig.underTitleX,\n            this.componentConfiguration.maxLossAmountContainerConfig.underTitleY,\n        );\n\n        this.createMandatorySign(\n            maxLossTitle,\n            '*',\n            this.componentConfiguration.mandatoryText.textStyle,\n            MandatoryValuesNumeric.MAX_LOSS,\n        );\n\n        // BALANCE LESS THAN\n        const balanceLessTitle = new Text();\n        this.setTextProps(\n            balanceLessTitle,\n            this.toSentenceCase(Core.translator.translate('LOSS LIMIT')),\n            this.componentConfiguration.balanceLessThanContainerConfig.titleTextStyle,\n            { x: 0, y: 0 },\n            this.componentConfiguration.balanceLessThanContainerConfig.titleX,\n            this.componentConfiguration.balanceLessThanContainerConfig.titleY,\n        );\n        this.balanceLessThanFieldContainer.addChild(balanceLessTitle);\n        this.balanceLessUnderTitle = this.createUnderTitleText(\n            this.balanceLessThanFieldContainer,\n            this.getRangeText(this.minBet, this.getLessBalance(), currency),\n            this.componentConfiguration.balanceLessThanContainerConfig.underTitleTextStyle,\n            this.componentConfiguration.balanceLessThanContainerConfig.underTitleX,\n            this.componentConfiguration.balanceLessThanContainerConfig.underTitleY,\n        );\n\n        this.createMandatorySign(\n            balanceLessTitle,\n            '*',\n            this.componentConfiguration.mandatoryText.textStyle,\n            MandatoryValuesNumeric.BALANCE_LES,\n        );\n\n        // BALANCE MORE THAN\n        const balanceMoreTitle = new Text();\n        this.setTextProps(\n            balanceMoreTitle,\n            this.toSentenceCase(Core.translator.translate('WINS LIMIT')),\n            this.componentConfiguration.balanceMoreThanContainerConfig.titleTextStyle,\n            { x: 0, y: 0 },\n            this.componentConfiguration.balanceMoreThanContainerConfig.titleX,\n            this.componentConfiguration.balanceMoreThanContainerConfig.titleY,\n        );\n        this.balanceMoreThanFieldContainer.addChild(balanceMoreTitle);\n\n        this.balanceMoreUnderTitle = this.createUnderTitleText(\n            this.balanceMoreThanFieldContainer,\n            this.getRangeText(this.minBet, this.getMoreBalance(), currency),\n            this.componentConfiguration.balanceMoreThanContainerConfig.underTitleTextStyle,\n            this.componentConfiguration.balanceMoreThanContainerConfig.underTitleX,\n            this.componentConfiguration.balanceMoreThanContainerConfig.underTitleY,\n        );\n\n        this.createMandatorySign(\n            balanceMoreTitle,\n            '*',\n            this.componentConfiguration.mandatoryText.textStyle,\n            MandatoryValuesNumeric.BALANCE_MORE,\n        );\n\n        // WIN OVER\n        const winOverTitle = new Text();\n        this.setTextProps(\n            winOverTitle,\n            this.toSentenceCase(Core.translator.translate('STOP ON WIN')),\n            this.componentConfiguration.winOverContainerConfig.titleTextStyle,\n            { x: 0, y: 0 },\n            this.componentConfiguration.winOverContainerConfig.titleX,\n            this.componentConfiguration.winOverContainerConfig.titleY,\n        );\n        this.winOverFieldContainer.addChild(winOverTitle);\n\n        this.winOverUnderTitle = this.createUnderTitleText(\n            this.winOverFieldContainer,\n            this.getRangeText(this.minBet, this.getWinOver(), currency),\n            this.componentConfiguration.winOverContainerConfig.underTitleTextStyle,\n            this.componentConfiguration.winOverContainerConfig.underTitleX,\n            this.componentConfiguration.winOverContainerConfig.underTitleY,\n        );\n\n        this.createMandatorySign(\n            winOverTitle,\n            '*',\n            this.componentConfiguration.mandatoryText.textStyle,\n            MandatoryValuesNumeric.WIN_OVER,\n        );\n    }\n\n    private createMandatorySign(title: Text, textValue: string, style: TextStyle, mandatoryValue: string): void {\n        const mandatorySign = new Text(textValue, style);\n        mandatorySign.x = title.width + mandatorySign.width / 2;\n\n        title.addChild(mandatorySign);\n\n        if (this.settings.autoplayRestrictions.mandatory.indexOf(mandatoryValue) === -1) {\n            mandatorySign.visible = false;\n        }\n    }\n\n    private createUnderTitleText(\n        container: ViewContainer,\n        textValue: string,\n        style: TextStyle,\n        x: number,\n        y: number,\n    ): Text {\n        const underTitle = new Text(textValue, style);\n        underTitle.anchor.set(0, 1);\n        underTitle.x = x;\n        underTitle.y = container.height + y;\n        container.addChild(underTitle);\n        return underTitle;\n    }\n\n    private getRangeText(min: number, max: number, currency: string): string {\n        const minStr = new MoneyFormatter(min).stringMoney;\n        const maxStr = new MoneyFormatter(Math.ceil(max)).stringMoney;\n        return `min. ${minStr} - max. ${maxStr} ${currency}`;\n    }\n\n    private createStartBtn(): void {\n        const btnTextures: AutoplayNumericInputPopupStartButtonTextures =\n            new AutoplayNumericInputPopupStartButtonTextures(\n                Core.assets.getAsset('svgAutoplayStartNormal').texture,\n                Core.assets.getAsset('svgAutoplayStartNormal').texture,\n                Core.assets.getAsset('svgAutoplayStartDisabled').texture,\n                Core.assets.getAsset('svgAutoplayStartHover').texture,\n            );\n        this.startAutoplayButton = new AutoplayNumericInputPopupButton(\n            Core.translator.translate('START AUTOPLAY'),\n            btnTextures,\n            this.componentConfiguration.buttonNormalText.textStyle,\n            this.componentConfiguration.buttonDisabledText.textStyle,\n        );\n        this.mainContainer.addChild(this.startAutoplayButton);\n    }\n\n    private createAutoplayValueButtons(value: number, _buttonIndex: number): void {\n        const btnTextures: AutoplayNumericInputPopupStartButtonTextures =\n            new AutoplayNumericInputPopupStartButtonTextures(\n                Core.assets.getAsset('svgAutoplayPopUpNormal').texture,\n                Core.assets.getAsset('svgAutoplayPopUpSelected').texture,\n                Core.assets.getAsset('svgAutoplayPopUpNormal').texture,\n                Core.assets.getAsset('svgAutoplayPopUpHover').texture,\n            );\n        const button: AutoplayPopupComponentSettingButtonNumeric = new AutoplayPopupComponentSettingButtonNumeric(\n            value,\n            btnTextures,\n            this.componentConfiguration.buttonValueText.textStyle,\n            this.componentConfiguration.buttonValueText.selectedTextStyle,\n            this.componentConfiguration.buttonValueText.width,\n            this.componentConfiguration.buttonValueText.height,\n        );\n\n        this.autoplayButtonsContainer.addChild(button);\n        this.autoplayButtons.push(button);\n    }\n\n    private setOrientation(): void {\n        this.killAllAnimations();\n        if (this.isOpened) {\n            this.mainContainer.alpha = 1;\n            this.arrow.alpha = 1;\n            this.graphicsContainer.alpha = 1;\n            this.graphicsContainer.visible = true;\n        } else {\n            this.noVisibility();\n            this.graphicsContainer.alpha = 0;\n            this.graphicsContainer.visible = false;\n        }\n        this.mainContainer.x = this.componentConfiguration.mainContainerPosition.x;\n        this.mainContainer.y = this.componentConfiguration.mainContainerPosition.y;\n\n        this.popUpBackground.x = this.componentConfiguration.popUpGraphicsContainer.x;\n        this.popUpBackground.y = this.componentConfiguration.popUpGraphicsContainer.y;\n        this.popUpBackground.width = this.componentConfiguration.popUpGraphicsContainer.width;\n        this.popUpBackground.height = this.componentConfiguration.popUpGraphicsContainer.height;\n\n        this.popUpTitleText.x =\n            this.componentConfiguration.popUpGraphicsContainer.x +\n            this.componentConfiguration.popUpGraphicsContainer.width / 2;\n        this.popUpTitleText.y = this.popUpBackground.y + this.componentConfiguration.popUpTitle.yOffset;\n\n        this.stopOn.x = this.componentConfiguration.stopOnTitle.x;\n        this.stopOn.y = this.componentConfiguration.stopOnTitle.y;\n\n        this.autoplay.x = this.componentConfiguration.autoplayTitle.x;\n        this.autoplay.y = this.componentConfiguration.autoplayTitle.y;\n\n        this.maxLossAmountFieldContainer.x = this.componentConfiguration.maxLossAmountContainerConfig.containerX;\n        this.maxLossAmountFieldContainer.y = this.componentConfiguration.maxLossAmountContainerConfig.containerY;\n\n        this.balanceLessThanFieldContainer.x = this.componentConfiguration.balanceLessThanContainerConfig.containerX;\n        this.balanceLessThanFieldContainer.y = this.componentConfiguration.balanceLessThanContainerConfig.containerY;\n\n        this.balanceMoreThanFieldContainer.x = this.componentConfiguration.balanceMoreThanContainerConfig.containerX;\n        this.balanceMoreThanFieldContainer.y = this.componentConfiguration.balanceMoreThanContainerConfig.containerY;\n\n        this.winOverFieldContainer.x = this.componentConfiguration.winOverContainerConfig.containerX;\n        this.winOverFieldContainer.y = this.componentConfiguration.winOverContainerConfig.containerY;\n\n        this.popUpShadow.x = this.componentConfiguration.popUpGraphicsContainer.x - 40;\n        this.popUpShadow.y = this.componentConfiguration.popUpGraphicsContainer.y;\n        this.popUpShadow.width = this.componentConfiguration.popUpGraphicsContainer.width + 80;\n        this.popUpShadow.height = this.componentConfiguration.popUpGraphicsContainer.height + 40;\n\n        this.popUpFirstSection.x = this.componentConfiguration.popUpFirstSectionPosition.x;\n        this.popUpFirstSection.y = this.componentConfiguration.popUpFirstSectionPosition.y;\n        this.popUpFirstSection.width = this.componentConfiguration.popUpFirstSectionPosition.width;\n        this.popUpFirstSection.height = this.componentConfiguration.popUpFirstSectionPosition.height;\n\n        this.popUpSecondSection.x = this.componentConfiguration.popUpSecondSectionPosition.x;\n        this.popUpSecondSection.y = this.componentConfiguration.popUpSecondSectionPosition.y;\n        this.popUpSecondSection.width = this.componentConfiguration.popUpSecondSectionPosition.width;\n        this.popUpSecondSection.height = this.componentConfiguration.popUpSecondSectionPosition.height;\n\n        for (let i: number = 0; i < this.autoplayButtons.length; i++) {\n            this.autoplayButtons[i].x =\n                (this.componentConfiguration.buttonValueText.xOffset +\n                    this.componentConfiguration.buttonValueText.width) *\n                i;\n        }\n\n        this.autoplayButtonsContainer.x =\n            this.popUpSecondSection.x +\n            (this.popUpSecondSection.width -\n                (114 * (this.autoplayButtons.length - 1) + this.autoplayButtons[0].width)) /\n                2;\n        this.autoplayButtonsContainer.y = this.componentConfiguration.buttonsContainerPositions.y;\n\n        this.arrow.x = this.componentConfiguration.arrowPosition.x;\n        this.arrow.y = this.componentConfiguration.arrowPosition.y;\n        this.arrow.angle = this.componentConfiguration.arrowPosition.angle;\n\n        this.balanceContainer.x = this.componentConfiguration.balanceText.x;\n        this.balanceContainer.y = this.componentConfiguration.balanceText.y;\n\n        this.betContainer.x = this.componentConfiguration.betText.x;\n        this.betContainer.y = this.componentConfiguration.betText.y;\n\n        this.startAutoplayButton.x = this.componentConfiguration.startAutoplayBtn.x;\n        this.startAutoplayButton.y = this.componentConfiguration.startAutoplayBtn.y;\n\n        this.selectedBtn.x = this.componentConfiguration.selectedButton.x;\n        this.selectedBtn.y = this.componentConfiguration.selectedButton.y;\n        this.selectedBtn.scale.set(this.componentConfiguration.selectedButton.scale);\n\n        if (this.numericKeyboard) {\n            this.numericKeyboard.reposition();\n        }\n\n        this.setLeftHand();\n    }\n\n    private setLeftHand(): void {\n        if (Core.LEFT_HAND_MODE.value && Core.ORIENTATION.value.isLandscape) {\n            this.mainContainer.x = this.componentConfiguration.mainContainerPosition.leftHandX;\n\n            this.arrow.x = this.componentConfiguration.arrowPosition.leftHandX;\n            this.arrow.y = this.componentConfiguration.arrowPosition.leftHandY;\n            this.arrow.angle = this.componentConfiguration.arrowPosition.leftHandAngle;\n\n            this.selectedBtn.x = this.componentConfiguration.selectedButton.leftHandX;\n            if (this.numericKeyboard) {\n                this.numericKeyboard.reposition();\n            }\n        }\n    }\n\n    private checkForMandatory() {\n        let mandatoryChecked: boolean = true;\n        for (const mandatory of this.mandatory) {\n            if (mandatory === MandatoryValuesNumeric.BALANCE_LES && this.balanceLess === 0) {\n                mandatoryChecked = false;\n            } else if (mandatory === MandatoryValuesNumeric.BALANCE_MORE && this.balanceMore === 0) {\n                mandatoryChecked = false;\n            } else if (mandatory === MandatoryValuesNumeric.WIN_OVER && this.winOver === 0) {\n                mandatoryChecked = false;\n            } else if (mandatory === MandatoryValuesNumeric.MAX_LOSS && this.maxLoss === 0) {\n                mandatoryChecked = false;\n            }\n        }\n\n        let fieldValueOutOfRange: boolean = false;\n        for (const field of this.inputFields) {\n            if (field.hasError && field.getValue() !== '') {\n                mandatoryChecked = false;\n                fieldValueOutOfRange = true;\n                break;\n            }\n        }\n\n        if (mandatoryChecked) {\n            this.startAutoplayButton.setNormal();\n        } else {\n            this.startAutoplayButton.setDisabled();\n        }\n\n        if (this.numericKeyboard && this.numericKeyboard.doneButton) {\n            if (fieldValueOutOfRange) {\n                this.numericKeyboard.doneButton.tintBtn();\n            } else {\n                this.numericKeyboard.doneButton.untintBtn();\n            }\n        }\n    }\n\n    private createSelectedBtn(): void {\n        this.selectedBtn = new Button(\n            [Core.assets.getAsset('svgAutoplaySelected').texture],\n            undefined,\n            ButtonShapes.Circle,\n        );\n        this.selectedBtn.pivot.set(this.selectedBtn.width / 2, this.selectedBtn.height / 2);\n        this.selectedBtn.interactive = true;\n        this.addChild(this.selectedBtn);\n    }\n\n    private createGraphicsContainer(): void {\n        this.graphicsContainer = new Container();\n        this.graphicsContainer.visible = false;\n        this.graphicsContainer.alpha = 0;\n        this.addChild(this.graphicsContainer);\n    }\n\n    private createMainContainer(): void {\n        this.mainContainer = new Container();\n        this.mainContainer.visible = false;\n        this.mainContainer.alpha = 0;\n        this.addChild(this.mainContainer);\n    }\n\n    private killAllAnimations(): void {\n        if (this.animationTween) {\n            this.animationTween.kill();\n            this.animationTween = null;\n        }\n    }\n\n    public showNumericKeyboardField(field: InputField): void {\n        if (Core.isDesktopMode) return;\n        if (this.numericKeyboard && this.isKeyboardVisible) {\n            this.currentField = field;\n            if (this.currentField && this.currentField !== field) {\n                this.currentField.setInactive();\n            }\n\n            this.numericKeyboard.setCurrentField(field);\n            return;\n        }\n\n        if (!this.numericKeyboard) {\n            this.numericKeyboard = new KeyboardNumeric(this.componentConfiguration);\n            this.addChild(this.numericKeyboard);\n\n            this.numericKeyboard.ON_DONE.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n                this.hideNumericKeyboardField(true);\n            });\n            this.numericKeyboard.ON_CANCEL.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n                this.hideNumericKeyboardField(true);\n            });\n            this.numericKeyboard.ON_INPUT.pipe(takeUntil(this.DESTROY)).subscribe((value: string) => {\n                if (this.currentField) {\n                    this.currentField.setValue(value);\n                }\n            });\n        }\n\n        if (this.numericKeyboard) {\n            this.numericKeyboard.updateKeyboardBalanceValue(this.balanceTextValue.text);\n            this.numericKeyboard.updateKeyboardBetValue(this.betTextValue.text);\n            this.numericKeyboard.updateCurrency(this.rootStore.settings.currency);\n        }\n\n        this.currentField = field;\n        this.numericKeyboard.setCurrentField(field);\n\n        this.numericKeyboard.visible = true;\n\n        if (this.numericKeyboard) {\n            this.numericKeyboard.showShadowBackground();\n        }\n\n        this.animateShowKeyboard();\n        this.isKeyboardVisible = true;\n        this.setOrientation();\n    }\n\n    public hideNumericKeyboardField(animate: boolean = false): void {\n        if (this.numericKeyboard) {\n            this.killNumericKeyboardTween();\n            if (animate) {\n                this.animateHideKeyboard();\n            } else {\n                this.numericKeyboard.visible = false;\n                this.numericKeyboard.alpha = 0;\n                this.numericKeyboard.y = this.startingPoint;\n                this.isKeyboardVisible = false;\n                this.numericKeyboard.hideShadowBackground();\n            }\n        }\n    }\n\n    private animateShowKeyboard(): void {\n        // this.setInputFieldsInteractive(false);\n        this.numericKeyboard.alpha = 0;\n        this.numericKeyboard.y = this.startingPoint;\n        this.numericKeyboardTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/autoplay-popup/src/egt/modes/numeric/views/AutoplayPopupViewNumeric.ts:1156:37\",null]), gsap.timeline({\n            // onComplete: () => {\n            //     this.setInputFieldsInteractive(true);\n            // },\n        }));\n        this.numericKeyboardTween\n            .to(this.numericKeyboard, { alpha: 1, duration: 0.2 }, 0)\n            .to(this.numericKeyboard, { y: 0, duration: 0.25, ease: 'power1.out' }, 0);\n    }\n\n    private animateHideKeyboard(): void {\n        // this.setInputFieldsInteractive(false);\n        this.numericKeyboardTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/autoplay-popup/src/egt/modes/numeric/views/AutoplayPopupViewNumeric.ts:1168:37\",null]), gsap.timeline({\n            onComplete: () => {\n                // this.setInputFieldsInteractive(true);\n                this.numericKeyboard.visible = false;\n                this.isKeyboardVisible = false;\n            },\n        }));\n        this.numericKeyboardTween\n            .to(this.numericKeyboard, { alpha: 0, duration: 0.2 }, 0)\n            .to(this.numericKeyboard, { y: this.startingPoint, duration: 0.25, ease: 'power1.in' }, 0);\n    }\n\n    private killNumericKeyboardTween(): void {\n        if (this.numericKeyboardTween) {\n            this.numericKeyboardTween.kill();\n            this.numericKeyboardTween = null;\n        }\n    }\n\n    // private setInputFieldsInteractive(interactive: boolean = true): void {\n    //     for (const field of this.inputFields) {\n    //         field.setInteractive(interactive);\n    //     }\n    // }\n\n    private toSentenceCase(str: string): string {\n        return str.charAt(0).toUpperCase() + str.substring(1).toLowerCase();\n    }\n\n    private destroyArray(arr: any[]) {\n        arr.forEach((child) => {\n            this.destroyObject(child);\n        });\n        // @ts-ignore\n        arr = null;\n    }\n\n    private destroyObject(obj: any) {\n        obj?.destroy?.();\n        // @ts-ignore\n        obj = null;\n    }\n}\n","import Core, { BaseComponent, IModeConfig } from '@egt/core';\nimport { SlotComponents, ZOrders } from '@egt/slot';\nimport { Container } from 'pixi.js';\nimport { Lifecycle } from 'tsyringe';\nimport BackgroundModesConfigurations, { BackgroundModes } from './BackgroundFactory';\nimport BackgroundViewCommon from './common/views/BackgroundViewCommon';\nimport { BackgroundComponentConfigurationFactoryBlurred } from './modes/blurred/configuration/BackgroundComponentConfigurationBlurred';\nimport { BackgroundComponentConfigurationFactoryDefault } from './modes/default/configuration/BackgroundComponentConfigurationDefault';\nimport { IBackgroundComponentConfigurationDefault } from './modes/default/interfaces/IBackgroundComponentConfigurationCommon';\n\nexport default class BackgroundComponent extends BaseComponent {\n    public static configurationName = 'BackgroundComponent';\n\n    public backgroundView: BackgroundViewCommon;\n    public componentType = SlotComponents.BACKGROUND;\n    public configuration: IBackgroundComponentConfigurationDefault;\n    public rootView;\n    // private modeConfig: BackgroundModesConfigurations;\n    // private mode: IModes;\n\n    constructor(modeConfig: IModeConfig) {\n        super();\n        const baseConfigs = {\n            [BackgroundModes.DEFAULT]: BackgroundComponentConfigurationFactoryDefault,\n            [BackgroundModes.BLURRED]: BackgroundComponentConfigurationFactoryBlurred,\n        };\n        this.modeFactory = this.initMode<BackgroundModesConfigurations>(modeConfig, {\n            defaultModeType: BackgroundModes.DEFAULT,\n            baseConfigs,\n            defaultFactory: BackgroundModesConfigurations,\n        });\n    }\n\n    public destroy(): void {\n        this.backgroundView.destroy();\n        // @ts-ignore\n        this.backgroundView = null;\n        (this.configuration as any).destroy();\n        // @ts-ignore\n        this.configuration = null;\n        // @ts-ignore\n        this.rootView = null;\n        // @ts-ignore\n        this.config = null;\n\n        super.destroy();\n    }\n\n    public onAfterGameConfigurationCreated(): void {\n        super.onAfterGameConfigurationCreated();\n        this.configuration = this.dependencyContainer.resolve('BackgroundComponentConfiguration');\n        // const slotConfig: ISlotConfiguration = this.dependencyContainer.resolve('ISlotConfiguration');\n        // if (slotConfig.componentsConfiguration.hasOwnProperty(BackgroundComponent.configurationName)) {\n        //     Object.keys(slotConfig.componentsConfiguration[BackgroundComponent.configurationName]).forEach(key => {\n        //         config[key] = slotConfig.componentsConfiguration[BackgroundComponent.configurationName][key];\n        //     });\n        // }\n    }\n\n    public onRegisterDependencies(container: any): void {\n        super.onRegisterDependencies(container);\n        if (!this.dependencyContainer.isRegistered('BackgroundView')) {\n            this.dependencyContainer.register(\n                'BackgroundView',\n                { useClass: this.mode.view },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n\n        this.dependencyContainer.register('BackgroundComponentConfiguration', this.mode.configuration);\n    }\n\n    public onResolveDependencies(container: any): void {\n        super.onResolveDependencies(container);\n\n        this.rootView = this.dependencyContainer.resolve('RootView');\n        this.backgroundView = this.dependencyContainer.resolve('BackgroundView');\n        this.backgroundView.zIndex = ZOrders.BASE_LEVEL;\n        this.rootView.addChild(this.backgroundView);\n    }\n\n    public onPrepareResources(_rootView: Container): void {\n        this.configuration = this.dependencyContainer.resolve('BackgroundComponentConfiguration');\n        Core.assets.addAssets(this.configuration?.assets?.toArray() || []);\n    }\n\n    public onInit(_view: any): void {\n        this.backgroundView.init();\n    }\n\n    public onInitialRender(_container: any): void {\n        this.backgroundView.onInitialRender();\n    }\n}\n","import { BaseModesConfigurations, IForceSetConfig, IModes } from '@egt/core';\nimport BackgroundViewCommon from './common/views/BackgroundViewCommon';\nimport { BackgroundComponentConfigurationFactoryDefault } from './modes/default/configuration/BackgroundComponentConfigurationDefault';\nimport { BackgroundComponentConfigurationFactoryBlurred } from './modes/blurred/configuration/BackgroundComponentConfigurationBlurred';\n\nexport default class BackgroundModesConfigurations extends BaseModesConfigurations<BackgroundModes> {\n    constructor(modeType: BackgroundModes, forceSetConfig?: IForceSetConfig) {\n        super(modeType, forceSetConfig);\n    }\n\n    protected createBaseModesConfig(modeType: BackgroundModes): IModes {\n        switch (modeType) {\n            case BackgroundModes.BLURRED:\n                return {\n                    view: BackgroundViewCommon,\n                    configuration: BackgroundComponentConfigurationFactoryBlurred(),\n                };\n            default:\n                return {\n                    view: BackgroundViewCommon,\n                    configuration: BackgroundComponentConfigurationFactoryDefault(),\n                };\n        }\n    }\n}\n\nexport enum BackgroundModes {\n    DEFAULT = 'default',\n    BLURRED = 'blurred',\n}\n","import Core, { IOrientation } from '@egt/core';\nimport { ISlotConfiguration, RootStore } from '@egt/slot';\nimport { IBackgroundAssets, ViewContainer } from '@egt/ui-lib';\nimport { Sprite } from 'pixi.js';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { IBackgroundComponentConfigurationDefault } from '../../modes/default/interfaces/IBackgroundComponentConfigurationCommon';\n\n@injectable()\nexport default class BackgroundViewCommon extends ViewContainer {\n    protected background: Sprite;\n    protected backgroundPortrait: Sprite;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('BackgroundComponentConfiguration')\n        protected backgroundComponentConfiguration: IBackgroundComponentConfigurationDefault,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n    ) {\n        super();\n    }\n\n    public init(): void {\n        const backgroundsAssetId: string = this.backgroundComponentConfiguration.backgroundsAssetId;\n        this.background = new Sprite(\n            Core.assets.getTextureFromSpriteSheet(backgroundsAssetId, 'backgroundLandscape.png'),\n        );\n        this.background.name = 'backgroundLandscape';\n        this.addChild(this.background);\n\n        this.backgroundPortrait = new Sprite(\n            Core.assets.getTextureFromSpriteSheet(backgroundsAssetId, 'backgroundPortrait.png'),\n        );\n        this.backgroundPortrait.name = 'backgroundPortrait';\n        this.addChild(this.backgroundPortrait);\n\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n        this.rootStore.subjects.CHANGE_BACKGROUND.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onBackgroundChanged.bind(this),\n        );\n    }\n\n    public onInitialRender(): void {\n        // implement in overrides\n    }\n    public destroy(): void {\n        this.background.destroy();\n        // @ts-ignore\n        this.background = null;\n        if (this.backgroundPortrait) {\n            this.backgroundPortrait.destroy();\n            // @ts-ignore\n            this.backgroundPortrait = null;\n        }\n        super.destroy();\n    }\n\n    protected onBackgroundChanged(param: IBackgroundAssets): void {\n        this.background.texture = param.landscape.background;\n        if (!Core.isDesktopMode) {\n            this.backgroundPortrait.texture = param.portrait.background;\n        }\n    }\n\n    protected setOrientation(orientation: IOrientation): void {\n        this.setPositions();\n        const isLandscape: boolean = orientation.isLandscape;\n        const mainResourcesDesktopScaleFactor = this.slotConfiguration.desktopScale;\n        if (mainResourcesDesktopScaleFactor && Core.isDesktopMode) {\n            this.background.scale.set(mainResourcesDesktopScaleFactor);\n        }\n        this.toggleVisibility(isLandscape);\n    }\n\n    private setPositions() {\n        this.background.x = this.backgroundComponentConfiguration.backgroundPosition.x;\n        this.background.y = this.backgroundComponentConfiguration.backgroundPosition.y;\n        this.backgroundPortrait.x = this.backgroundComponentConfiguration.backgroundPosition.x;\n        this.backgroundPortrait.y = this.backgroundComponentConfiguration.backgroundPosition.y;\n    }\n\n    protected toggleVisibility(landscape: boolean): void {\n        this.background.renderable = landscape;\n        this.background.visible = landscape;\n        this.backgroundPortrait.renderable = !landscape;\n        this.backgroundPortrait.visible = !landscape;\n    }\n}\n","import BackgroundComponent from './BackgroundComponent';\nimport { BackgroundModes } from './BackgroundFactory';\nimport BackgroundViewCommon from './common/views/BackgroundViewCommon';\nimport BackgroundComponentConfigurationBlurred from './modes/blurred/configuration/BackgroundComponentConfigurationBlurred';\nimport BackgroundComponentConfigurationDefault from './modes/default/configuration/BackgroundComponentConfigurationDefault';\nimport { IBackgroundComponentConfigurationBlurred } from './modes/blurred/interfaces/IBackgroundComponentConfigurationCommon';\nimport { IBackgroundComponentConfigurationDefault } from './modes/default/interfaces/IBackgroundComponentConfigurationCommon';\n\nexport {\n    IBackgroundComponentConfigurationDefault,\n    IBackgroundComponentConfigurationBlurred,\n    BackgroundViewCommon,\n    BackgroundModes,\n    BackgroundComponentConfigurationDefault,\n    BackgroundComponentConfigurationBlurred,\n};\nexport default BackgroundComponent;\n","import Core, {\n    AssetPriority,\n    AssetsCollection,\n    BaseComponentConfiguration,\n    DefaultAssets,\n    DefaultValue,\n    DynamicPositionObject,\n} from '@egt/core';\nimport { IBackgroundComponentConfigurationBlurred } from '../interfaces/IBackgroundComponentConfigurationCommon';\nimport { IPointData } from 'pixi.js';\n\nexport default class BackgroundComponentConfigurationBlurred extends BaseComponentConfiguration {}\nexport function BackgroundComponentConfigurationFactoryBlurred(): any {\n    class BackgroundComponentConfigurationBlurredInternalClass\n        extends BackgroundComponentConfigurationBlurred\n        implements IBackgroundComponentConfigurationBlurred\n    {\n        public backgroundsAssetId: string = 'mainResources';\n\n        @DefaultAssets([\n            {\n                id: 'mainResources',\n                url: '../assets/' + Core.configuration.gameKey + '/mainResources/modes/blurred/mainResources.json',\n                priority: AssetPriority.HIGHEST,\n                hasDesktopVersion: true,\n                type: 'texture',\n            },\n        ])\n        public assets: AssetsCollection;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 0, y: 0 },\n        })\n        public backgroundPosition: DynamicPositionObject<IPointData> & IPointData;\n    }\n    return BackgroundComponentConfigurationBlurredInternalClass;\n}\n","import Core, {\n    AssetPriority,\n    AssetsCollection,\n    BaseComponentConfiguration,\n    DefaultAssets,\n    DefaultValue,\n    DynamicPositionObject,\n} from '@egt/core';\nimport { IBackgroundComponentConfigurationDefault } from '../interfaces/IBackgroundComponentConfigurationCommon';\nimport { IPointData } from 'pixi.js';\n\nexport default class BackgroundComponentConfigurationDefault extends BaseComponentConfiguration {}\nexport function BackgroundComponentConfigurationFactoryDefault(): any {\n    class BackgroundComponentConfigurationDefaultInternalClass\n        extends BackgroundComponentConfigurationDefault\n        implements IBackgroundComponentConfigurationDefault\n    {\n        public backgroundsAssetId: string = 'mainResources';\n\n        @DefaultAssets([\n            {\n                id: 'mainResources',\n                url: '../assets/' + Core.configuration.gameKey + '/mainResources/modes/default/mainResources.json',\n                priority: AssetPriority.HIGHEST,\n                hasDesktopVersion: true,\n                type: 'texture',\n            },\n        ])\n        public assets: AssetsCollection;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 0, y: 0 },\n        })\n        public backgroundPosition: DynamicPositionObject<IPointData> & IPointData;\n    }\n    return BackgroundComponentConfigurationDefaultInternalClass;\n}\n","import Core, { BaseComponent, IBaseComponentController, IBaseComponentView, IModeConfig } from '@egt/core';\nimport { ISlotConfiguration, InitialSettings, RootStore, SlotComponents, ZOrders } from '@egt/slot';\nimport { Lifecycle } from 'tsyringe';\nimport BetButtonsModesConfigurations, { BetButtonsModes } from './BetButtonsModeFactory';\nimport BetButtonsComponentConfigurationDefault, {\n    BetButtonsComponentConfigurationFactoryDefault,\n} from './modes/default/configuration/BetButtonsComponentConfigurationDefault';\nimport BetButtonsComponentConfigurationOneDenom, {\n    BetButtonsComponentConfigurationFactoryOneDenom,\n} from './modes/one-denom/configuration/BetButtonsComponentConfigurationOneDenom';\nimport { BetButtonsComponentConfigurationFactoryTurtle } from './modes/turtle/configuration/BetButtonsComponentConfigurationTurtle';\n\nexport default class BetButtonsComponent extends BaseComponent {\n    public static configurationName = 'BetButtonsComponent';\n    public betButnsView: IBaseComponentView;\n    public componentType = SlotComponents.BET_BUTTONS;\n    public configuration;\n    public controller: IBaseComponentController;\n    public rootView;\n    private rootStore: RootStore;\n    private initialSettings: InitialSettings;\n\n    constructor(modeConfig: IModeConfig) {\n        super();\n        const baseConfigs = {\n            [BetButtonsModes.DEFAULT]: BetButtonsComponentConfigurationFactoryDefault,\n            [BetButtonsModes.ONE_DENOM]: BetButtonsComponentConfigurationFactoryOneDenom,\n            [BetButtonsModes.TURTLE]: BetButtonsComponentConfigurationFactoryTurtle,\n        };\n\n        this.modeFactory = this.initMode<BetButtonsModesConfigurations>(modeConfig, {\n            defaultModeType: BetButtonsModes.DEFAULT,\n            baseConfigs,\n            defaultFactory: BetButtonsModesConfigurations,\n        });\n    }\n\n    public onPrepareResources(_container: any): void {\n        this.configuration = this.dependencyContainer.resolve('BetButtonsComponentConfiguration');\n        Core.assets.addAssets(this.configuration.assets);\n    }\n\n    public destroy(): void {\n        this.controller.destroy();\n        // @ts-ignore\n        this.betButnsView = null;\n        // @ts-ignore\n        this.controller = null;\n        (this.configuration as any).destroy();\n        // @ts-ignore\n        this.configuration = null;\n        // @ts-ignore\n        this.rootView = null;\n        // @ts-ignore\n        this.config = null;\n        // @ts-ignore\n        this.rootStore = null;\n        // @ts-ignore\n        this.initialSettings = null;\n        super.destroy();\n    }\n\n    public onAfterGameConfigurationCreated(): void {\n        super.onAfterGameConfigurationCreated();\n        const slotConfig: ISlotConfiguration = this.dependencyContainer.resolve('ISlotConfiguration');\n        const config: BetButtonsComponentConfigurationDefault | BetButtonsComponentConfigurationOneDenom =\n            this.dependencyContainer.resolve('BetButtonsComponentConfiguration');\n        if (slotConfig.componentsConfiguration.hasOwnProperty(BetButtonsComponent.configurationName)) {\n            Object.keys(slotConfig.componentsConfiguration[BetButtonsComponent.configurationName]).forEach((key) => {\n                config[key] = slotConfig.componentsConfiguration[BetButtonsComponent.configurationName][key];\n            });\n        }\n    }\n\n    public onRegisterDependencies(container: any): void {\n        super.onRegisterDependencies(container);\n        this.dependencyContainer.register('BetButtonsComponentConfiguration', this.mode.configuration);\n\n        // if (Core.gameDependencyContainer.isRegistered('InitialSettings')) {\n        // const initialSettings: InitialSettings = this.dependencyContainer.resolve('InitialSettings');\n\n        // const classType =\n        //     initialSettings.allBets.length > this.configuration.betButtons.length\n        //         ? OneDenomBetButtonsView\n        //         : BetButtonsView;\n\n        // if (!this.dependencyContainer.isRegistered('BetButtonsView')) {\n        this.dependencyContainer.register(\n            'BetButtonsView',\n            { useClass: this.mode.view },\n            { lifecycle: Lifecycle.Singleton },\n        );\n        // }\n        // }\n\n        this.dependencyContainer.register(\n            'BetButtonsController',\n            { useClass: this.mode.controller },\n            { lifecycle: Lifecycle.Singleton },\n        );\n    }\n\n    public onResolveDependencies(container: any): void {\n        super.onResolveDependencies(container);\n        this.rootView = this.dependencyContainer.resolve('RootView');\n        this.betButnsView = this.dependencyContainer.resolve('BetButtonsView');\n        this.controller = this.dependencyContainer.resolve('BetButtonsController');\n        this.betButnsView.zIndex = ZOrders.UI_LEVEL;\n        this.rootView.addChild(this.betButnsView);\n        this.rootStore = this.dependencyContainer.resolve('RootStore');\n        this.initialSettings = this.dependencyContainer.resolve('InitialSettings');\n        if (this.initialSettings.allBets.length > this.configuration.betButtons.length) {\n            this.rootStore.subjects.IS_ONE_DENOMINATION.next(true);\n        }\n    }\n\n    public onGameStarted(): void {\n        this.controller.onGameStarted();\n    }\n\n    public onAfterInitialRender(container: any): void {\n        super.onAfterInitialRender(container);\n        this.controller.onAfterInitialRender();\n    }\n}\n","import { BaseModesConfigurations, IForceSetConfig, IModes } from '@egt/core';\nimport BetButtonsControllerDefault from './modes/default/controllers/BetButtonsControllerDefault';\nimport BetButtonsViewDefault from './modes/default/views/BetButtonsViewDefault';\nimport { BetButtonsComponentConfigurationFactoryDefault } from './modes/default/configuration/BetButtonsComponentConfigurationDefault';\nimport BetButtonsControllerOneDenom from './modes/one-denom/controllers/BetButtonsControllerOneDenom';\nimport BetButtonsViewOneDenom from './modes/one-denom/views/BetButtonsViewOneDenom';\nimport { BetButtonsComponentConfigurationFactoryOneDenom } from './modes/one-denom/configuration/BetButtonsComponentConfigurationOneDenom';\nimport BetButtonsControllerTurtle from './modes/turtle/controllers/BetButtonsControllerTurtle';\nimport BetButtonsViewTurtle from './modes/turtle/views/BetButtonsViewTurtle';\nimport { BetButtonsComponentConfigurationFactoryTurtle } from './modes/turtle/configuration/BetButtonsComponentConfigurationTurtle';\n\nexport default class BetButtonsModesConfigurations extends BaseModesConfigurations<BetButtonsModes> {\n    constructor(modeType: BetButtonsModes, forceSetConfig?: IForceSetConfig) {\n        super(modeType, forceSetConfig);\n    }\n\n    protected createBaseModesConfig(modeType: BetButtonsModes): IModes {\n        switch (modeType) {\n            case BetButtonsModes.ONE_DENOM:\n                return {\n                    controller: BetButtonsControllerOneDenom,\n                    view: BetButtonsViewOneDenom,\n                    configuration: BetButtonsComponentConfigurationFactoryOneDenom(),\n                };\n            case BetButtonsModes.TURTLE:\n                return {\n                    controller: BetButtonsControllerTurtle,\n                    view: BetButtonsViewTurtle,\n                    configuration: BetButtonsComponentConfigurationFactoryTurtle(),\n                };\n            default:\n                return {\n                    controller: BetButtonsControllerDefault,\n                    view: BetButtonsViewDefault,\n                    configuration: BetButtonsComponentConfigurationFactoryDefault(),\n                };\n        }\n    }\n}\n\nexport enum BetButtonsModes {\n    DEFAULT = 'default',\n    ONE_DENOM = 'one-denom',\n    TURTLE = 'turtle',\n}\n","import BetButtonsComponent from './BetButtonsComponent';\nimport BetButtonsComponentConfigurationDefault from './modes/default/configuration/BetButtonsComponentConfigurationDefault';\nimport { IBetButtonsComponentConfigurationDefault } from './modes/default/configuration/IBetButtonsComponentConfigurationDefault';\nimport BetButtonsControllerDefault from './modes/default/controllers/BetButtonsControllerDefault';\nimport {\n    IBetButton,\n    IBetButtonsTextures,\n    IFakeBetButtonsMask,\n    IJackpotLabel,\n    IPiecePosition,\n    ISlidAnim,\n    ISlidBetButtonsHitArea,\n} from './common/interfaces/InterfacesCommon';\nimport BetButtonsViewDefault from './modes/default/views/BetButtonsViewDefault';\nimport BetButtonsViewOneDenom from './modes/one-denom/views/BetButtonsViewOneDenom';\nimport BetButtonsComponentConfigurationOneDenom from './modes/one-denom/configuration/BetButtonsComponentConfigurationOneDenom';\nimport { IBetButtonsComponentConfigurationOneDenom } from './modes/one-denom/configuration/IBetButtonsComponentConfigurationOneDenom';\nimport { BetButtonsModes } from './BetButtonsModeFactory';\nimport BetButtonsComponentConfigurationTurtle from './modes/turtle/configuration/BetButtonsComponentConfigurationTurtle';\nimport { IBetButtonsComponentConfigurationTurtle } from './modes/turtle/configuration/IBetButtonsComponentConfigurationTurtle';\nimport BetButtonsViewTurtle from './modes/turtle/views/BetButtonsViewTurtle';\n\nexport {\n    IBetButton,\n    BetButtonsComponentConfigurationDefault,\n    IBetButtonsComponentConfigurationDefault,\n    BetButtonsComponentConfigurationOneDenom,\n    IBetButtonsComponentConfigurationOneDenom,\n    BetButtonsComponentConfigurationTurtle,\n    IBetButtonsComponentConfigurationTurtle,\n    BetButtonsControllerDefault,\n    BetButtonsViewDefault,\n    IBetButtonsTextures,\n    IPiecePosition,\n    ISlidAnim,\n    IFakeBetButtonsMask,\n    ISlidBetButtonsHitArea,\n    IJackpotLabel,\n    BetButtonsViewOneDenom,\n    BetButtonsViewTurtle,\n    BetButtonsModes,\n};\n\nexport default BetButtonsComponent;\n","import {\n    AssetPriority,\n    BaseComponentConfiguration,\n    DefaultValue,\n    DynamicPositionObject,\n    PositionObject,\n} from '@egt/core';\nimport { AutoAlign, IBetButtonsConfig, TextAlign } from '@egt/ui-lib';\nimport { TextStyle } from 'pixi.js';\nimport {\n    IBetButton,\n    IFakeBetButtonsMask,\n    IMoneyContainerGroupAlpha,\n    IPiecePosition,\n    ISlidAnim,\n    ISlidBetButtonsHitArea,\n} from '../../../common/interfaces/InterfacesCommon';\nimport { IBetButtonsComponentConfigurationDefault } from './IBetButtonsComponentConfigurationDefault';\n\nexport default class BetButtonsComponentConfigurationDefault extends BaseComponentConfiguration {}\n\nexport function BetButtonsComponentConfigurationFactoryDefault(): any {\n    class BetButtonsComponentConfigurationDefaultInternalClass\n        extends BetButtonsComponentConfigurationDefault\n        implements IBetButtonsComponentConfigurationDefault\n    {\n        public assets = [\n            {\n                id: 'svgBet',\n                url: '../assets/components/slot/bet-buttons/one-denom/ui-svg/standardButton.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 134, height: 96 },\n                    desktop: { width: 134, height: 96 },\n                },\n            },\n            {\n                id: 'svgBetPressed',\n                url: '../assets/components/slot/bet-buttons/one-denom/ui-svg/standardButtonPressed.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 134, height: 96 },\n                    desktop: { width: 134, height: 96 },\n                },\n            },\n            {\n                id: 'svgActiveBet',\n                url: '../assets/components/slot/bet-buttons/one-denom/ui-svg/standardButtonPressed.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 134, height: 96 },\n                    desktop: { width: 134, height: 96 },\n                },\n            },\n            {\n                id: 'svgActiveBetPressed',\n                url: '../assets/components/slot/bet-buttons/one-denom/ui-svg/standardButtonPressed.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 134, height: 96 },\n                    desktop: { width: 134, height: 96 },\n                },\n            },\n            {\n                id: 'svgBetHover',\n                url: '../assets/components/slot/bet-buttons/one-denom/ui-svg/standardButtonPressed.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 134, height: 96 },\n                    desktop: { width: 134, height: 96 },\n                },\n            },\n            {\n                id: 'svgActiveBetHover',\n                url: '../assets/components/slot/bet-buttons/one-denom/ui-svg/standardButtonPressed.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 134, height: 96 },\n                    desktop: { width: 134, height: 96 },\n                },\n            },\n        ];\n\n        public betButtonsContainerGroup: PositionObject = new PositionObject({\n            landscape: { x: 150.5, y: 662, width: 1080, height: 104 },\n            portrait: { x: 0, y: 693, width: 765, height: 250 },\n            desktop: { x: 151, y: 641, width: 1360, height: 87 },\n        });\n        public moneyContainerGroup: PositionObject = new PositionObject({\n            landscape: { x: 150.5, y: 662, width: 1080, height: 104 },\n            portrait: { x: 0, y: 693, width: 765, height: 250 },\n            desktop: { x: 151, y: 641, width: 1360, height: 87 },\n        });\n\n        @DefaultValue<IMoneyContainerGroupAlpha>({\n            defaults: {\n                defaultAlpha: 1,\n                customAlpha: 0.5,\n            },\n        })\n        public moneyContainerGroupAlpha: DynamicPositionObject<IMoneyContainerGroupAlpha> & IMoneyContainerGroupAlpha;\n\n        @DefaultValue<IPiecePosition>({\n            defaults: {\n                x: 833,\n                y: 4,\n            },\n            portrait: {\n                x: 718.5,\n                y: 149,\n            },\n        })\n        public rightPiecePosition: DynamicPositionObject<IPiecePosition> & IPiecePosition;\n\n        @DefaultValue<IPiecePosition>({\n            defaults: {\n                x: 185,\n                y: 4,\n            },\n            portrait: {\n                x: 6.5,\n                y: 149,\n            },\n        })\n        public leftPiecePosition: DynamicPositionObject<IPiecePosition> & IPiecePosition;\n\n        @DefaultValue<ISlidAnim>({\n            defaults: {\n                leftSlidWidth: -605,\n                rightSlidWidth: 605,\n            },\n            portrait: {\n                leftSlidWidth: -655,\n                rightSlidWidth: 655,\n            },\n        })\n        public slideAnimation: DynamicPositionObject<ISlidAnim> & ISlidAnim;\n\n        @DefaultValue<IFakeBetButtonsMask>({\n            defaults: {\n                x: 200,\n                y: 0,\n                scaleX: 0.935,\n                scaleY: 1.5,\n            },\n            portrait: {\n                x: 23,\n                y: 146,\n                scaleX: 1.02,\n                scaleY: 1,\n            },\n            desktop: {\n                scaleY: 0.8,\n            },\n        })\n        public fakeBetButtonsMask: DynamicPositionObject<IFakeBetButtonsMask> & IFakeBetButtonsMask;\n\n        @DefaultValue<ISlidBetButtonsHitArea>({\n            defaults: {\n                x: 200,\n                y: 0,\n            },\n            portrait: {\n                x: 53,\n                y: 146,\n            },\n        })\n        public slidBetButtonsHitArea: DynamicPositionObject<ISlidBetButtonsHitArea> & ISlidBetButtonsHitArea;\n\n        public fakeBetButtonsPositionsLeft: PositionObject[] = [\n            new PositionObject({\n                landscape: { x: -378, y: 4 },\n                portrait: { x: -593, y: 149 },\n            }),\n            new PositionObject({\n                landscape: { x: -257, y: 4 },\n                portrait: { x: -462, y: 149 },\n            }),\n            new PositionObject({\n                landscape: { x: -136, y: 4 },\n                portrait: { x: -331, y: 149 },\n            }),\n            new PositionObject({\n                landscape: { x: -15, y: 4 },\n                portrait: { x: -200, y: 149 },\n            }),\n            new PositionObject({\n                landscape: { x: 106, y: 4 },\n                portrait: { x: -69, y: 149 },\n            }),\n        ];\n        public fakeBetButtonsPositionsRight: PositionObject[] = [\n            new PositionObject({\n                landscape: { x: 832, y: 4 },\n                portrait: { x: 717, y: 149 },\n            }),\n            new PositionObject({\n                landscape: { x: 953, y: 4 },\n                portrait: { x: 848, y: 149 },\n            }),\n            new PositionObject({\n                landscape: { x: 1074, y: 4 },\n                portrait: { x: 979, y: 149 },\n            }),\n            new PositionObject({\n                landscape: { x: 1195, y: 4 },\n                portrait: { x: 1110, y: 149 },\n            }),\n            new PositionObject({\n                landscape: { x: 1316, y: 4 },\n                portrait: { x: 1241, y: 149 },\n            }),\n        ];\n\n        @DefaultValue<IBetButtonsConfig>({\n            defaults: {\n                currency: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                        fontSize: 18,\n                        fill: '#C6C5C5',\n                        letterSpacing: 0.9,\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                        fontSize: 18,\n                        fill: '#FFD200',\n                        letterSpacing: 0.9,\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 3.5,\n                    bounds: { width: 106, height: 30 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                amount: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                        fontSize: 42,\n                        fill: '#C6C5C5', // '#FFFFFF'\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                        fontSize: 42,\n                        fill: '#FFFFFF',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 30,\n                    bounds: { width: 106, height: 34 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                label: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                        fontSize: 22,\n                        fill: '#FFD200',\n                        padding: 5,\n                        letterSpacing: 0.66,\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                        fontSize: 22,\n                        fill: '#FFD200',\n                        padding: 5,\n                        letterSpacing: 0.66,\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 61,\n                    bounds: { width: 106, height: 30 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                stamp: {\n                    hasStamp: false,\n                    x: 0,\n                    y: 0,\n                    width: 0,\n                    height: 0,\n                    alpha: 0,\n                    texture: { source: '', name: '' },\n                },\n                textures: ['svgBet', 'svgBetPressed', 'svgBet', 'svgBet'],\n                selectedTextures: ['svgActiveBet', 'svgActiveBetPressed', 'svgActiveBet', 'svgActiveBet'],\n                fakeMaskTexture: 'maxBet',\n                width: 120,\n                height: 96,\n            },\n            desktop: {\n                currency: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                        fontSize: 15,\n                        fill: '#C6C5C5', // '#FFD200'\n                        letterSpacing: 0.75,\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                        fontSize: 15,\n                        fill: '#FFD200',\n                        letterSpacing: 0.75,\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 3,\n                    bounds: { width: 84, height: 20 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                amount: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                        fontSize: 35,\n                        fill: '#C6C5C5', // '#FFFFFF'\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                        fontSize: 35,\n                        fill: '#FFFFFF',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 27.5,\n                    bounds: { width: 84, height: 20 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                label: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                        fontSize: 16,\n                        fill: '#FFD200',\n                        letterSpacing: 1.12,\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                        fontSize: 16,\n                        fill: '#FFD200',\n                        letterSpacing: 1.12,\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 54,\n                    bounds: { width: 78, height: 17 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                textures: ['svgBet', 'svgBetPressed', 'svgBetHover', 'svgBet'],\n                selectedTextures: ['svgActiveBet', 'svgActiveBetPressed', 'svgActiveBetHover', 'svgActiveBet'],\n                width: 94,\n                height: 75,\n            },\n        })\n        public betButtonsConfigs: DynamicPositionObject<IBetButtonsConfig> & IBetButtonsConfig;\n\n        public betButtons: Array<DynamicPositionObject<IBetButton>> = [\n            new DynamicPositionObject<IBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs, x: 0, y: 0 },\n                landscape: { x: 227, y: 4 },\n                portrait: { x: 58.5, y: 149 },\n                desktop: { x: 282, y: 6 },\n            }),\n            new DynamicPositionObject<IBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs, x: 0, y: 0 },\n                landscape: { x: 348, y: 4 },\n                portrait: { x: 190.5, y: 149 },\n                desktop: { x: 382, y: 6 },\n            }),\n            new DynamicPositionObject<IBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs, x: 0, y: 0 },\n                landscape: { x: 469, y: 4 },\n                portrait: { x: 322.5, y: 149 },\n                desktop: { x: 482, y: 6 },\n            }),\n            new DynamicPositionObject<IBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs, x: 0, y: 0 },\n                landscape: { x: 590, y: 4 },\n                portrait: { x: 454.5, y: 149 },\n                desktop: { x: 582, y: 6 },\n            }),\n            new DynamicPositionObject<IBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs, x: 0, y: 0 },\n                landscape: { x: 711, y: 4 },\n                portrait: { x: 586.5, y: 149 },\n                desktop: { x: 682, y: 6 },\n            }),\n        ];\n    }\n    return BetButtonsComponentConfigurationDefaultInternalClass;\n}\n","import Core, { BaseController, FeatureFlags, Timers } from '@egt/core';\nimport {\n    FeatureController,\n    Features,\n    ISlotConfiguration,\n    InitialSettings,\n    RootStore,\n    ServerState,\n    UIState,\n} from '@egt/slot';\nimport { BetButton } from '@egt/ui-lib';\nimport { filter, take, takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport BetButtonsViewDefault from '../views/BetButtonsViewDefault';\nimport { fromEvent, merge } from 'rxjs';\n\n@injectable()\nexport default class BetButtonsControllerDefault extends BaseController {\n    public ready: () => Promise<void>;\n\n    private inactivityTimer;\n    private inactivityTimeout: number = 3000;\n\n    constructor(\n        @inject('BetButtonsView') protected view: BetButtonsViewDefault,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('FeatureController') protected featureController: FeatureController,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('InitialSettings') protected initialSettings: InitialSettings,\n    ) {\n        super(view);\n\n        this.rootStore.subjects.DENOMINATIONS_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onDenominationsChanged.bind(this),\n        );\n\n        this.attachEventListeners();\n        this.selectBet(\n            'bet' + (this.rootStore.uiStore.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value) + 1),\n            true,\n        );\n    }\n\n    public onGameStarted(): void {\n        const interactionEvents = ['click', 'touchstart', 'mousemove', 'keydown'];\n        merge(...interactionEvents.map((event) => fromEvent(window, event)))\n            .pipe(take(2))\n            .subscribe(() => {\n                this.clearInactivityTimer();\n            });\n\n        this.inactivityTimer = Timers.setTimeout(() => {\n            this.view.onGameLoaded();\n        }, this.inactivityTimeout);\n    }\n\n    public onAfterInitialRender(): void {\n        const hasDefaultMinBetRestriction = Core.flags.isActive(FeatureFlags.USE_DEFAULT_BET_ON_LOAD);\n        const isIdleState = this.initialSettings.state === ServerState.IDLE;\n        if (hasDefaultMinBetRestriction && isIdleState) {\n            Core.SELECTED_DENOMINATION.next(this.initialSettings?.settings?.settings?.denomination);\n            this.rootStore.uiStore.SELECTED_BET.next(this.initialSettings?.settings?.settings?.bet);\n            this.rootStore.subjects.SETTINGS_BET_CHANGED.next();\n        }\n        this.rootStore.uiStore.CURRENT_BET_LEVEL.next({\n            betLevel: this.rootStore.uiStore.SELECTED_BET.value,\n            denomLevel: Core.SELECTED_DENOMINATION.value,\n        });\n    }\n\n    protected onDenominationsChanged(): void {\n        this.view.onDenominationsChanged();\n        if (!this.view.oneDenomView) {\n            this.addBetButtonsEventListeners();\n        }\n    }\n\n    protected attachEventListeners(): void {\n        this.addBetButtonsEventListeners();\n\n        this.view.UPDATE_SELECTED_BET.pipe(takeUntil(this.DESTROY)).subscribe(this.selectWhenSliding.bind(this));\n\n        this.rootStore.subjects.SETTINGS_BET_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.selectFromSettings.bind(this),\n        );\n\n        // this.rootStore.subjects.SETTINGS_POPUP_CLOSED.pipe(takeUntil(this.DESTROY)).subscribe(\n        //     this.onSettingsPopupClosed.bind(this),\n        // );\n\n        // this.rootStore.subjects.SETTINGS_POPUP_OPENED.pipe(takeUntil(this.DESTROY)).subscribe(\n        //     this.onSettingsPopupOpened.bind(this),\n        // );\n\n        this.rootStore.uiStore.SHOW_HIDE_BET_BUTTONS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.showHideBetButtons.bind(this),\n        );\n\n        this.rootStore.subjects.KEY_UP.pipe(takeUntil(this.DESTROY)).subscribe(this.onKeyReleased.bind(this));\n        this.rootStore.subjects.SWITCH_BET_BUTTONS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.switchBetButtons.bind(this),\n        );\n\n        this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onExtendedMultipleBuyBonusActivated.bind(this),\n        );\n    }\n\n    private addBetButtonsEventListeners(): void {\n        this.view.betButtons.forEach((_bet, index) => {\n            this.view\n                .find('bet' + (index + 1))\n                .CLICK.pipe(\n                    filter(\n                        (_x) =>\n                            !this.rootStore.subjects.KEY_DOWN.value &&\n                            this.rootStore.subjects.SHOW_JP_STATS.value.type === -1,\n                    ),\n                    takeUntil(this.DESTROY),\n                )\n                .subscribe(this.onSelectedBetChanged.bind(this, 'bet' + (index + 1)));\n        });\n    }\n\n    protected onExtendedMultipleBuyBonusActivated(value: boolean): void {\n        if (\n            this.rootStore.settings.haveGameMode('DOUBLE_CHANCE') &&\n            this.rootStore.settings.factor === this.rootStore.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE')\n        ) {\n            value = false;\n        }\n        for (const betButton of this.view.betButtons) {\n            betButton.buyBonusActivated = value;\n        }\n        // Timers.setTimeout(()=>{\n        this.view.resizeBetButtonsFonts();\n        // },1000);\n    }\n\n    protected selectWhenSliding(e): void {\n        const betButton = 'bet' + (this.rootStore.uiStore.bets.indexOf(e) + 1);\n        const button: BetButton = this.view.find(betButton);\n        if (!button) {\n            return;\n        }\n        this.view.slideIfNotVisible(false);\n        this.view.clearBetSelection();\n        button.selected = true;\n    }\n\n    protected selectFromSettings(): void {\n        this.selectBet(\n            'bet' + (this.rootStore.uiStore.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value) + 1),\n            true,\n        );\n    }\n\n    protected selectBet(betButton: string, fromSettings: boolean = false): void {\n        const button: BetButton = this.view.find(betButton);\n        if (!button) {\n            return;\n        }\n        this.rootStore.uiStore.SELECTED_BET.next(button.betPerLine);\n        this.view.slideIfNotVisible(false, undefined, fromSettings);\n        this.view.clearBetSelection();\n        button.selected = true;\n    }\n\n    protected onKeyReleased(e: KeyboardEvent): void {\n        if (\n            e &&\n            this.rootStore.uiStore.SHOW_SETTINGS.value &&\n            ['ArrowDown', 'KeyC', 'KeyV', 'KeyB', 'KeyN', 'KeyM'].indexOf(e.code) > -1\n        ) {\n            return;\n        }\n        if (e === null || Core.UI_BLOCKER.value) {\n            return;\n        }\n        const currentUIState = this.rootStore.uiStore.STATE.value;\n\n        if ((e.code !== undefined && e.code === 'KeyC') || (e.keyCode !== undefined && e.keyCode === 67)) {\n            this.reactBasedOnState(currentUIState, 1);\n        }\n        if ((e.code !== undefined && e.code === 'KeyV') || (e.keyCode !== undefined && e.keyCode === 86)) {\n            this.reactBasedOnState(currentUIState, 2);\n        }\n        if ((e.code !== undefined && e.code === 'KeyB') || (e.keyCode !== undefined && e.keyCode === 66)) {\n            this.reactBasedOnState(currentUIState, 3);\n        }\n        if ((e.code !== undefined && e.code === 'KeyN') || (e.keyCode !== undefined && e.keyCode === 78)) {\n            this.reactBasedOnState(currentUIState, 4);\n        }\n        if ((e.code !== undefined && e.code === 'KeyM') || (e.keyCode !== undefined && e.keyCode === 77)) {\n            this.reactBasedOnState(currentUIState, 5);\n        }\n    }\n\n    protected reactBasedOnState(state: string, buttonValue: number): void {\n        let but = this.view.betButtons.filter((x) => x.name === 'bet' + buttonValue)[0];\n        if (this.view.oneDenomView) {\n            but = this.view.visibleBetButtons[buttonValue - 1];\n        }\n        if (!but || but.enabled === false || but.interactive === false) {\n            return;\n        }\n        switch (state) {\n            case UIState.IDLE:\n            case UIState.WAITING_FOR_COLLECT:\n            case UIState.BONUS_IDLE:\n                this.onBetButtonKeyPressed(but.name);\n\n                break;\n        }\n    }\n    protected onBetButtonKeyPressed(butName: string): void {\n        if (\n            this.rootStore.domainStore.SPIN_MODE.value !== Features.MANUAL_SPIN ||\n            Core.UI_BLOCKER.value ||\n            this.rootStore.uiStore.STATE.value === UIState.COLLECT_BEFORE_IDLE\n        ) {\n            return;\n        }\n        if (this.rootStore.subjects.TAB_OPENED.value) {\n            this.rootStore.subjects.CLOSE_SETTINGS_POPUP.next();\n            this.rootStore.subjects.RESET_AUTOPLAY_RESTRICTIONS.next();\n            return;\n        }\n        this.view.find(butName).CLICK.next();\n    }\n\n    protected onSelectedBetChanged(betButton: string): void {\n        if (!this.featureController.isInGiftSpins) {\n            this.selectBet(betButton);\n            this.rootStore.uiStore.CLEAR_BANG_UP.next();\n            if (this.rootStore.uiStore.CURRENT_BET_LEVEL.value.betLevel !== this.view.find(betButton).betPerLine) {\n                this.rootStore.uiStore.CURRENT_BET_LEVEL.next({\n                    betLevel: this.rootStore.uiStore.SELECTED_BET.value,\n                    denomLevel: Core.SELECTED_DENOMINATION.value,\n                });\n            }\n            this.rootStore.subjects.START_MANUAL_SPIN.next();\n        }\n        if (this.view.betButtons[0].name === betButton) {\n            this.rootStore.subjects.FIRST_BET_CLICKED.next();\n        }\n    }\n\n    protected switchBetButtons(event: { fromIndex: number; toIndex: number }): any {\n        if (event.fromIndex === event.toIndex) {\n            return;\n        }\n        this.view.switchBetButtons(event.fromIndex, event.toIndex);\n    }\n\n    private showHideBetButtons(show: boolean): void {\n        if (show) {\n            this.view.showBetButtons();\n        } else {\n            this.view.hideBetButtons();\n        }\n    }\n\n    private clearInactivityTimer(): void {\n        if (this.inactivityTimer) {\n            Timers.clearTimeout(this.inactivityTimer);\n            this.inactivityTimer = null;\n        }\n    }\n}\n","import { BuyBonusModes } from '@egt/buy-bonus';\nimport Core, { AnalyticsDispatcher, IOrientation } from '@egt/core';\nimport {\n    FeatureController,\n    ISlotConfiguration,\n    InitialSettings,\n    RootStore,\n    ServerState,\n    SlotComponents,\n    UIState,\n} from '@egt/slot';\nimport { BetButton, ButtonStates, FakeBetButton, ViewContainer } from '@egt/ui-lib';\nimport { gsap } from 'gsap';\nimport { Graphics, Sprite } from 'pixi.js';\nimport { Subject, Subscription, fromEvent } from 'rxjs';\nimport { filter, takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { IBetButtonsComponentConfigurationDefault } from '../configuration/IBetButtonsComponentConfigurationDefault';\nimport { UIViewModes } from '@egt/ui-view';\n\n@injectable()\nexport default class BetButtonsViewDefault extends ViewContainer {\n    public betButtons: BetButton[] = [];\n    public visibleBetButtons: BetButton[] = [];\n    public oneDenomView: boolean = false;\n    public UPDATE_SELECTED_BET = new Subject();\n    protected moneyContainerGroup: ViewContainer;\n    protected betButtonsContainer: Sprite;\n    protected fakeBetButtonsCurrent: BetButton[] = [];\n    protected fakeBetButtonsNewLeft: BetButton[] = [];\n    protected fakeBetButtonsNewRight: BetButton[] = [];\n    protected fakeBetButtonsOffset: number = 0;\n    protected betButtonsSlidingStart: boolean = false;\n    protected slidBetButtonsHitArea: Graphics;\n    protected betButtonsContainerGroup: Sprite;\n    protected betBtnPieceLeft: Sprite;\n    protected betBtnPieceRight: Sprite;\n    protected slideType: 'slideLeft' | 'slideRight' | 'none' = 'none';\n    protected slideTimeline: any;\n    protected xDown: any;\n    protected yDown: any;\n    protected pointerId: number = -1;\n    protected fakeBetButtonsMask: Sprite;\n    protected currentState: any;\n    protected handleTouchEndFn: any;\n    protected denomSubscription: Subscription;\n\n    private alteredBtnOriginalPosition: { [K in 'desktop' | 'landscape' | 'portrait']?: { x: number; y: number } } = {};\n    private initialValueFontSize: number = 0;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected configuration: ISlotConfiguration,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('FeatureController') protected feature: FeatureController,\n        @inject('BetButtonsComponentConfiguration')\n        protected componentConfiguration: IBetButtonsComponentConfigurationDefault,\n    ) {\n        super();\n        this.initialValueFontSize = Number(this.componentConfiguration.betButtonsConfigs.amount.defaultStyle.fontSize);\n        this.initialRender();\n\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe((orientation) =>\n            this.setOrientation(orientation, true),\n        );\n        this.denomSubscription = Core.SELECTED_DENOMINATION.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.resizeBetButtonsFonts.bind(this),\n        );\n        Core.MONEY_MODE_IN_CREDITS.pipe(takeUntil(Core.ON_GAME_UNLOADED)).subscribe(this.onMoneyModeChanged.bind(this));\n\n        this.rootStore.subjects.BET_BUTTONS_LABLE_STATE.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.setBetButtonsLable.bind(this),\n        );\n        this.rootStore.subjects.FACTOR_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(this.onFactorChanged.bind(this));\n        this.rootStore.subjects.ENABLE_BET_BUTTON.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.enableBetButton.bind(this),\n        );\n        this.rootStore.subjects.ENABLE_ALL_BET_BUTTONS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.enableBetButtons.bind(this),\n        );\n        this.rootStore.subjects.REELS_START.pipe(takeUntil(this.DESTROY)).subscribe(this.onReelsStart.bind(this));\n        this.rootStore.subjects.SHOW_BET_BUTTONS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.showBetButtons.bind(this),\n        );\n        this.rootStore.subjects.HIDE_BET_BUTTONS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.hideBetButtons.bind(this),\n        );\n        if (Core.configuration.mode === 'kiosk') {\n            this.rootStore.subjects.KEY_UP.pipe(takeUntil(this.DESTROY)).subscribe(this.onKeyReleased.bind(this));\n        }\n        this.rootStore.uiStore.STATE.pipe(takeUntil(this.DESTROY)).subscribe(this.onStateChanged.bind(this));\n        this.rootStore.uiStore.LINES.pipe(takeUntil(this.DESTROY)).subscribe(this.linesChanged.bind(this));\n        this.rootStore.uiStore.SHOW_HIDE_EXACT_BET_BUTTON.pipe(takeUntil(this.DESTROY)).subscribe(\n            ({ index, visible, shouldAlterPosition, alteredPosition }) => {\n                this.betButtons[index].visible = visible;\n                if (shouldAlterPosition) {\n                    this.updateExactBetBtnDisplayModeConfig(index, alteredPosition);\n                    this.setOrientation(Core.ORIENTATION.value);\n                }\n            },\n        );\n\n        this.rootStore.subjects.CHANGE_MONEY_CONTAINER_GROUP_ALPHA.pipe(takeUntil(this.DESTROY)).subscribe((val) => {\n            this.changeMoneyContainerGroupAlpha(val);\n        });\n\n        this.rootStore.subjects.SET_BET_BUTTONS_OPACITY.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.setBetButtonsOpacity.bind(this),\n        );\n    }\n\n    public onGameLoaded() {\n        // custom implementation\n    }\n\n    public onDenominationsChanged() {\n        const wereVisible = this.betButtons[0].visible;\n        this.denomSubscription.unsubscribe();\n        this.removeChildren();\n        this.destroyBetButtons();\n        this.initialRender();\n        this.denomSubscription = Core.SELECTED_DENOMINATION.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.resizeBetButtonsFonts.bind(this),\n        );\n        if (!wereVisible) {\n            this.hideBetButtons();\n        }\n        this.setOrientation(Core.ORIENTATION.value);\n    }\n\n    public clearBetSelection(): void {\n        this.rootStore.uiStore.bets.forEach((_bet, index) => {\n            this.find('bet' + (index + 1)).selected = false;\n        });\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public slideIfNotVisible(animation: boolean = true, targetIndex?: number, preserveOrder?: boolean): void {\n        // implement custom logic\n    }\n\n    public clearInactivityTimer(): void {\n        // implement custom logic\n    }\n\n    protected destroyBetButtons() {\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        this.betButtons.forEach((betButton: BetButton) => {\n            // @ts-ignore\n            betButton = null;\n        });\n        this.betButtons = [];\n\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        this.fakeBetButtonsCurrent.forEach((fakeBetButtonCurrent: BetButton) => {\n            // @ts-ignore\n            fakeBetButtonCurrent = null;\n        });\n        this.fakeBetButtonsCurrent = [];\n\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        this.fakeBetButtonsNewLeft.forEach((fakeBetButtonNewLeft: BetButton) => {\n            // @ts-ignore\n            fakeBetButtonNewLeft = null;\n        });\n        this.fakeBetButtonsNewLeft = [];\n\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        this.fakeBetButtonsNewRight.forEach((fakeBetButtonNewRight: BetButton) => {\n            // @ts-ignore\n            fakeBetButtonNewRight = null;\n        });\n        this.fakeBetButtonsNewRight = [];\n    }\n\n    public enableUI(enableUI: boolean): void {\n        this.interactiveChildren = enableUI;\n    }\n\n    public initialRender(): void {\n        // Create money container group\n        this.moneyContainerGroup = this.createMoneyContainerGroup();\n        this.moneyContainerGroup.name = 'moneyContainerGroup';\n        this.moneyContainerGroup.interactive = true;\n        this.moneyContainerGroup.alpha = this.componentConfiguration.moneyContainerGroupAlpha.defaultAlpha;\n\n        if (this.settings.denominations.length > 1) {\n            this.createSlidBetButtonsEvents();\n        }\n        this.betButtonsContainerGroup = new Sprite();\n        this.betButtonsContainerGroup.name = 'betButtonsContainerGroup';\n        this.betButtonsContainerGroup.interactive = true;\n\n        this.addChild(this.betButtonsContainerGroup);\n        this.addChild(this.moneyContainerGroup);\n    }\n\n    public destroy(): void {\n        this.removeChildren();\n        this.denomSubscription.unsubscribe();\n        // @ts-ignore\n        this.denomSubscription = null;\n\n        this.betButtons.forEach((betButt) => {\n            betButt.destroy();\n        });\n        this.betButtons = [];\n        // @ts-ignore\n        this.betButtons = null;\n\n        this.fakeBetButtonsCurrent.forEach((betButt) => {\n            betButt.destroy();\n        });\n        this.fakeBetButtonsCurrent = [];\n        // @ts-ignore\n        this.fakeBetButtonsCurrent = null;\n\n        this.fakeBetButtonsNewLeft.forEach((betButt) => {\n            betButt.destroy();\n        });\n        this.fakeBetButtonsNewLeft = [];\n        // @ts-ignore\n        this.fakeBetButtonsNewLeft = null;\n\n        this.fakeBetButtonsNewRight.forEach((betButt) => {\n            betButt.destroy();\n        });\n        this.fakeBetButtonsNewRight = [];\n        // @ts-ignore\n        this.fakeBetButtonsNewRight = null;\n\n        // @ts-ignore\n        this.betbuttonsGraphics = null;\n\n        window.removeEventListener('pointerup', this.handleTouchEndFn);\n\n        if (this.handleTouchEndFn) {\n            this.handleTouchEndFn = null;\n        }\n        // @ts-ignore\n        this.alteredBtnOriginalPosition = null;\n        super.destroy({ children: true, texture: true, baseTexture: true });\n    }\n\n    public enableBetButton(obj: { id: number; enabled: boolean }): void {\n        this.betButtons[obj.id].enabled = obj.enabled;\n    }\n\n    public enableBetButtons(enable: boolean): void {\n        if (this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value) {\n            return;\n        }\n        for (const button of this.betButtons) {\n            button.interactive = enable;\n            button.interactiveChildren = enable;\n            button.state = ButtonStates.Normal;\n        }\n        if (Core.isDesktopMode) {\n            return;\n        }\n        // this.setBetBtnPiecesInteractive(enable, this.betBtnPieceRight, this.betBtnPieceLeft);\n        this.slidBetButtonsHitArea.visible = enable;\n    }\n\n    public createBetButtons(container: ViewContainer): void {\n        this.createBetButtonsHitArea(container);\n        const bets: number[] = this.rootStore.uiStore.bets;\n\n        // Create Balance Money Text\n        // const betButtonTextures = this.getBetButtonsTextures();\n        // const betButtonSelectedTextures = this.getBetButtonsSelectedTextures();\n        // Create Bets Money Texts\n        for (let i = 0; i < bets.length; i++) {\n            const maxBetBuyBonus =\n                this.rootStore.settings.settings.settings.clientSettings.maxBetLimits &&\n                Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS)\n                    ? this.rootStore.settings.settings.settings.clientSettings.maxBetLimits[\n                          this.rootStore.settings.currency\n                      ]\n                    : undefined;\n\n            // TODO: REFACTOR constructor of BetButton\n            const bet: BetButton = new BetButton({\n                name: 'bet' + (i + 1),\n                betPerLine: bets[i],\n                currency: this.rootStore.uiStore.currency,\n                units: this.rootStore.uiStore.units,\n                denomination: Core.SELECTED_DENOMINATION.value,\n                lines: this.rootStore.uiStore.LINES.value,\n                factor: this.rootStore.settings.factor,\n                width: this.componentConfiguration.betButtons[i].get('betConfig').width,\n                height: this.componentConfiguration.betButtons[i].get('betConfig').height,\n                text: Core.translator.translate('PLAY'),\n                textures: this.getBetButtonsTextures(\n                    this.componentConfiguration.betButtons[i].get('betConfig').textures,\n                ),\n                selectedTextures: this.getBetButtonsTextures(\n                    this.componentConfiguration.betButtons[i].get('betConfig').selectedTextures,\n                ),\n                fakeMaskTexture: Core.assets.getAsset(\n                    this.componentConfiguration.betButtons[i].get('betConfig').fakeMaskTexture,\n                )?.texture,\n                selected: false,\n                // betButtonStyles: this.configuration.betButtonStyles,\n                dynamicConfig: this.componentConfiguration.betButtons[i].get('betConfig'),\n                maxBet: this.rootStore.settings.maxBet,\n                maxBetBuyBonus,\n            });\n            this.betButtons.push(bet);\n            this.betButtonsContainer.addChild(bet);\n            if (bets[i] === this.rootStore.uiStore.SELECTED_BET.value) {\n                bet.selected = true;\n            }\n            bet.buyBonusActivated = this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value;\n        }\n        if (!Core.isDesktopMode) {\n            this.createBetButtonsParts(container);\n        }\n        this.resizeBetButtonsFonts();\n    }\n\n    public showBetButtons(): void {\n        if (this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value) {\n            return;\n        }\n        for (const betButton of this.betButtons) {\n            betButton.visible = true;\n        }\n        this.showBetButtonParts();\n        if (!Core.isDesktopMode) {\n            this.slidBetButtonsHitArea.visible = true;\n        }\n    }\n\n    public hideBetButtons(): void {\n        for (const betButton of this.betButtons) {\n            betButton.visible = false;\n        }\n        if (Core.isDesktopMode) {\n            return;\n        }\n        this.betBtnPieceLeft.visible = false;\n        this.betBtnPieceRight.visible = false;\n        this.slidBetButtonsHitArea.visible = false;\n    }\n\n    public setPositionsBetButtons(): void {\n        this.setOrientation(Core.ORIENTATION.value);\n    }\n\n    protected getBetButtonsTextures(element: string[]): any[] {\n        return [\n            Core.assets.getAsset(element[ButtonStates.Normal]).texture,\n            Core.assets.getAsset(element[ButtonStates.Pressed]).texture,\n            Core.assets.getAsset(element[ButtonStates.Over]).texture,\n            Core.assets.getAsset(element[ButtonStates.Disabled]).texture,\n        ];\n    }\n\n    protected onReelsStart(): void {\n        this.rootStore.subjects.BET_BUTTONS_LABLE_STATE.next('STOP');\n    }\n\n    protected setOrientation(_orientation: IOrientation, orientationChanged: boolean = false): void {\n        if (orientationChanged && this.rootStore.uiStore.STATE.value === UIState.SLIDING_BETS) {\n            this.betButtonsSlidingStart = false;\n            this.xDown = null;\n            this.pointerId = -1;\n            if (this.slideTimeline) {\n                this.slideTimeline.kill();\n                this.slideTimeline = null;\n            }\n            if (this.fakeBetButtonsCurrent.length > 0) {\n                this.destroyFakeBetButtons();\n            }\n            this.rootStore.uiStore.STATE.next(this.currentState || UIState.IDLE);\n            this.currentState = null;\n            this.showBetButtons();\n            this.showBetButtonParts();\n        }\n\n        if (this.slideTimeline) {\n            this.slideTimeline.totalProgress(1);\n        }\n        this.betButtonsContainerGroup.x = this.componentConfiguration.betButtonsContainerGroup.x;\n        this.betButtonsContainerGroup.y = this.componentConfiguration.betButtonsContainerGroup.y;\n        this.betButtonsContainerGroup.width = this.componentConfiguration.betButtonsContainerGroup.width;\n        this.betButtonsContainerGroup.height = this.componentConfiguration.betButtonsContainerGroup.height;\n        this.betButtonsContainerGroup.scale.set(this.componentConfiguration.betButtonsContainerGroup.scale);\n        this.moneyContainerGroup.x = this.componentConfiguration.moneyContainerGroup.x;\n        this.moneyContainerGroup.y = this.componentConfiguration.moneyContainerGroup.y;\n\n        for (let i = 0; i < this.betButtons.length; i++) {\n            this.betButtons[i].x = this.componentConfiguration.betButtons[i]?.get('x');\n            this.betButtons[i].y = this.componentConfiguration.betButtons[i]?.get('y');\n            this.betButtons[i].updateConfig();\n        }\n\n        for (let i = 0; i < this.fakeBetButtonsCurrent.length; i++) {\n            this.fakeBetButtonsCurrent[i].x = this.componentConfiguration.betButtons[i].get('x');\n            this.fakeBetButtonsCurrent[i].y = this.componentConfiguration.betButtons[i].get('y');\n        }\n        for (let i = 0; i < this.fakeBetButtonsNewRight.length; i++) {\n            this.fakeBetButtonsNewRight[i].x = this.componentConfiguration.fakeBetButtonsPositionsRight[i].x;\n            this.fakeBetButtonsNewRight[i].y = this.componentConfiguration.fakeBetButtonsPositionsRight[i].y;\n        }\n\n        for (let i = 0; i < this.fakeBetButtonsNewLeft.length; i++) {\n            this.fakeBetButtonsNewLeft[i].x = this.componentConfiguration.fakeBetButtonsPositionsLeft[i].x;\n            this.fakeBetButtonsNewLeft[i].y = this.componentConfiguration.fakeBetButtonsPositionsLeft[i].y;\n        }\n        if (this.betBtnPieceLeft) {\n            this.betBtnPieceLeft.x = this.componentConfiguration.leftPiecePosition.x;\n            this.betBtnPieceLeft.y = this.componentConfiguration.leftPiecePosition.y;\n        }\n\n        if (this.betBtnPieceRight) {\n            this.betBtnPieceRight.x = this.componentConfiguration.rightPiecePosition.x;\n            this.betBtnPieceRight.y = this.componentConfiguration.rightPiecePosition.y;\n        }\n\n        this.slidBetButtonsHitArea.x = this.componentConfiguration.slidBetButtonsHitArea.x;\n        this.slidBetButtonsHitArea.y = this.componentConfiguration.slidBetButtonsHitArea.y;\n\n        if (this.fakeBetButtonsMask) {\n            this.fakeBetButtonsMask.x = this.componentConfiguration.fakeBetButtonsMask.x;\n            this.fakeBetButtonsMask.y = this.componentConfiguration.fakeBetButtonsMask.y;\n            this.fakeBetButtonsMask.scale.set(\n                this.componentConfiguration.fakeBetButtonsMask.scaleX,\n                this.componentConfiguration.fakeBetButtonsMask.scaleY,\n            );\n        }\n    }\n    protected onStateChanged(): void {\n        switch (this.rootStore.uiStore.STATE.value) {\n            case UIState.IDLE:\n            case UIState.BONUS_IDLE:\n                this.enableBetButtons.call(this, true);\n                this.rootStore.subjects.BET_BUTTONS_LABLE_STATE.next('PLAY');\n                break;\n            case UIState.UNSET:\n            case UIState.WAITING_FOR_RESPONSE:\n                this.enableBetButtons.call(this, false);\n                break;\n            case UIState.WAITING_FOR_RESPONSE_IN_AUTOPLAY:\n                this.enableBetButtons.call(this, false);\n                break;\n            case UIState.WAITING_FOR_RESPONSE_IN_FREESPIN:\n                this.enableBetButtons.call(this, false);\n                break;\n            case UIState.WIN:\n                this.enableBetButtons.call(this, false);\n                break;\n            case UIState.FREESPIN:\n                this.enableBetButtons.call(this, false);\n                if (this.rootStore.domainStore?.betResponse?.roundWinAmount > 0) {\n                    this.rootStore.subjects.BET_BUTTONS_LABLE_STATE.next('PLAY');\n                }\n                break;\n            case UIState.RESPIN:\n            case UIState.EXIT_FREESPIN:\n            case UIState.BELL_LINK:\n            case UIState.CASH_HEAT:\n            case UIState.GODS_AND_KINGS_LINK:\n            case UIState.BONUS_CHANCE:\n            case UIState.HIGH_CASH_FEATURE:\n                this.enableBetButtons.call(this, false);\n                this.rootStore.subjects.BET_BUTTONS_LABLE_STATE.next('PLAY');\n                break;\n            case UIState.MYSTERY:\n                this.enableBetButtons.call(this, false);\n                break;\n            case UIState.PICK_ME_BONUS:\n                this.enableBetButtons.call(this, false);\n                this.rootStore.subjects.BET_BUTTONS_LABLE_STATE.next('PLAY');\n                break;\n            case UIState.GAMBLE:\n                this.enableBetButtons.call(this, false);\n                break;\n            case UIState.LAST_GAMBLE_WIN:\n                this.enableBetButtons.call(this, false);\n                break;\n            case UIState.GAMBLE_WIN:\n                this.enableBetButtons.call(this, false);\n                break;\n            case UIState.WAITING_FOR_COLLECT:\n                this.enableBetButtons.call(this, true);\n                this.rootStore.subjects.BET_BUTTONS_LABLE_STATE.next('PLAY');\n                break;\n            case UIState.WAITING_FOR_COLLECT_IN_AUTOPLAY:\n                this.enableBetButtons.call(this, false);\n                break;\n            case UIState.SLIDING_BETS:\n            case UIState.DISABLED:\n                this.enableBetButtons(false);\n                break;\n        }\n    }\n\n    public switchBetButtons(fromIndex: number, toIndex: number) {\n        const bet = this.betButtons[toIndex];\n        this.betButtons.splice(toIndex, 1, this.betButtons[fromIndex]);\n        this.betButtons.splice(fromIndex, 1, bet);\n        this.setPositionsBetButtons();\n    }\n\n    protected onMoneyModeChanged(): void {\n        this.resizeBetButtonsFonts();\n    }\n\n    protected isSlidingDisabledInCredits(): boolean {\n        return Core.MONEY_MODE_IN_CREDITS.value;\n    }\n\n    protected createSlidBetButtonsEvents(): void {\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/bet-buttons/src/egt/modes/default/views/BetButtonsViewDefault.ts:516:9\",(this.betButtonsContainer),\"touchstart\"]), fromEvent(this.betButtonsContainer, 'touchstart'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.handleTouchStart.bind(this));\n\n        fromEvent(this.betButtonsContainer, 'touchmove')\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.handleTouchMove.bind(this));\n\n        this.handleTouchEndFn = this.handleTouchEnd.bind(this);\n\n        window.addEventListener('pointerup', this.handleTouchEndFn);\n    }\n\n    protected handleTouchStart(evt): void {\n        if (typeof this.xDown !== 'number') {\n            this.pointerId = evt.data.pointerId;\n        }\n        if (evt.data.pointerId !== this.pointerId) {\n            return;\n        }\n        const firstTouch = evt.data.global;\n        this.xDown = firstTouch.x;\n        // if (this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT) {\n        //     this.betButtonsSlidingStart = true;\n        // }\n    }\n\n    protected handleTouchMove(evt): void {\n        if (\n            evt.data.pointerId !== this.pointerId ||\n            this.isSlidingDisabledInCredits() ||\n            !this.xDown ||\n            this.feature.isInGiftSpins ||\n            this.rootStore.subjects.SHOW_JP_STATS.value.type !== -1\n        ) {\n            return;\n        }\n\n        const xUp: number = evt.data.global.x;\n        const xDiff: number = this.xDown - xUp;\n\n        if (\n            (xDiff > 5 || xDiff < -5) &&\n            (this.rootStore.uiStore.STATE.value === UIState.IDLE ||\n                this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT)\n        ) {\n            AnalyticsDispatcher.slideFeatureEvent(this.rootStore.uiStore.SELECTED_BET.value);\n            this.betButtonsSlidingStart = true;\n        }\n\n        if (!this.betButtonsSlidingStart) {\n            return;\n        }\n\n        if (this.fakeBetButtonsCurrent.length === 0) {\n            this.fakeBetButtonsOffset = this.betButtonsContainerGroup.x - evt.data.global.x;\n            this.createFakeBetButtons();\n        }\n\n        this.betButtonsContainerGroup.x = evt.data.global.x + this.fakeBetButtonsOffset;\n    }\n\n    protected handleTouchEnd(evt): void {\n        if (!evt.isPrimary) {\n            return;\n        }\n        const xUp: number = evt.x;\n        const xDiff: number = this.xDown - xUp;\n        this.xDown = null;\n        this.pointerId = -1;\n\n        if (!this.betButtonsSlidingStart || this.rootStore.uiStore.STATE.value !== UIState.SLIDING_BETS) {\n            this.betButtonsSlidingStart = false;\n            return;\n        }\n\n        this.betButtonsSlidingStart = false;\n\n        if (xDiff < -50 && this.fakeBetButtonsNewLeft.length > 0) {\n            this.slideType = 'slideLeft';\n        } else if (xDiff > 50 && this.fakeBetButtonsNewRight.length > 0) {\n            this.slideType = 'slideRight';\n        } else {\n            this.slideType = 'none';\n        }\n        this.animateFakeBetButtons();\n    }\n\n    protected createMoneyContainerGroup(): ViewContainer {\n        const container: ViewContainer = new ViewContainer();\n        this.createBetButtons(container);\n\n        return container;\n    }\n\n    protected createFakeBetButtons(): void {\n        this.rootStore.subjects.DISABLED_BUY_BONUS.next({ disabled: true, doNotChangeVisual: false });\n        this.rootStore.subjects.DISABLED_DOUBLE_CHANCE.next(true);\n        this.rootStore.subjects.CLOSE_ALL_POPUPS.next();\n        this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(true);\n\n        this.currentState = this.rootStore.uiStore.STATE.value;\n        this.rootStore.uiStore.STATE.next(UIState.SLIDING_BETS);\n        this.hideBetButtons();\n        this.betBtnPieceLeft.visible = false;\n        this.betBtnPieceRight.visible = false;\n\n        const bets: number[] = this.rootStore.uiStore.bets;\n\n        // const defautltFntSize = Number(this.componentConfiguration.betButtonsConfigs.amount.defaultStyle.fontSize);\n        // let minFontSize: number = defautltFntSize;\n        let minFontSize: number = this.initialValueFontSize;\n        // Create Balance Money Text\n        // const betButtonTextures = this.getBetButtonsTextures();\n        // const betButtonSelectedTextures = this.getBetButtonsSelectedTextures();\n\n        // Create Bets Money Texts\n        for (let i = 0; i < bets.length; i++) {\n            // TODO: REFACTOR constructor of BetButton\n\n            const bet: FakeBetButton = this.createFakeBetButton(\n                i,\n                bets[i],\n                Core.SELECTED_DENOMINATION.value,\n                this.getBetButtonsTextures(this.componentConfiguration.betButtons[i].get('betConfig').textures),\n                this.getBetButtonsTextures(this.componentConfiguration.betButtons[i].get('betConfig').selectedTextures),\n                Core.assets.getAsset(this.componentConfiguration.betButtons[i].get('betConfig').fakeMaskTexture)\n                    .texture,\n            );\n            this.fakeBetButtonsCurrent.push(bet);\n            bet.fontSize = this.initialValueFontSize;\n            minFontSize = Math.min(minFontSize, Number(bet.fontSize));\n            if (bets[i] === this.rootStore.uiStore.SELECTED_BET.value) {\n                bet.selected = true;\n            }\n        }\n        this.fakeBetButtonsCurrent.forEach((bet, _index) => {\n            if (this.initialValueFontSize > minFontSize) {\n                bet.fontSize = minFontSize;\n            }\n\n            this.betButtonsContainerGroup.addChild(bet);\n        });\n        const denominationLevelIndex: number = this.getCurrentDenominationLevel() - 1;\n        if (denominationLevelIndex > 0) {\n            const denominationLeft = this.rootStore.uiStore.denominations[denominationLevelIndex - 1];\n            minFontSize = this.initialValueFontSize;\n            for (let i = 0; i < bets.length; i++) {\n                const bet: FakeBetButton = this.createFakeBetButton(\n                    i,\n                    bets[i],\n                    denominationLeft,\n                    this.getBetButtonsTextures(this.componentConfiguration.betButtons[i].get('betConfig').textures),\n                    this.getBetButtonsTextures(\n                        this.componentConfiguration.betButtons[i].get('betConfig').selectedTextures,\n                    ),\n                    Core.assets.getAsset(this.componentConfiguration.betButtons[i].get('betConfig').fakeMaskTexture)\n                        .texture,\n                );\n                this.fakeBetButtonsNewLeft.push(bet);\n                // this.betButtonsContainerGroup.addChild(bet);\n                bet.fontSize = this.initialValueFontSize;\n                minFontSize = Math.min(minFontSize, Number(bet.fontSize));\n                // bet.fontSize = defautltFntSize;\n            }\n            this.fakeBetButtonsNewLeft.forEach((bet, _index) => {\n                if (this.initialValueFontSize > minFontSize) {\n                    bet.fontSize = minFontSize;\n                }\n\n                this.betButtonsContainerGroup.addChild(bet);\n            });\n        }\n\n        if (denominationLevelIndex < this.rootStore.uiStore.denominations.length - 1) {\n            const denominationRight = this.rootStore.uiStore.denominations[denominationLevelIndex + 1];\n            minFontSize = this.initialValueFontSize;\n            for (let i = 0; i < bets.length; i++) {\n                const bet: FakeBetButton = this.createFakeBetButton(\n                    i,\n                    bets[i],\n                    denominationRight,\n                    this.getBetButtonsTextures(this.componentConfiguration.betButtons[i].get('betConfig').textures),\n                    this.getBetButtonsTextures(\n                        this.componentConfiguration.betButtons[i].get('betConfig').selectedTextures,\n                    ),\n                    Core.assets.getAsset(this.componentConfiguration.betButtons[i].get('betConfig').fakeMaskTexture)\n                        .texture,\n                );\n                this.fakeBetButtonsNewRight.push(bet);\n                bet.fontSize = this.initialValueFontSize;\n                minFontSize = Math.min(minFontSize, Number(bet.fontSize));\n            }\n\n            this.fakeBetButtonsNewRight.forEach((bet) => {\n                if (this.initialValueFontSize > minFontSize) {\n                    bet.fontSize = minFontSize;\n                }\n                this.betButtonsContainerGroup.addChild(bet);\n            });\n        }\n\n        this.moneyContainerGroup.addChild(this.fakeBetButtonsMask);\n        this.betButtonsContainerGroup.mask = this.fakeBetButtonsMask;\n        this.setOrientation(Core.ORIENTATION.value);\n    }\n\n    protected getCurrentDenominationLevel(): number {\n        let currentLevel: number = 0;\n        for (let i: number = 0; i < this.rootStore.uiStore.denominations.length; i++) {\n            if (this.rootStore.uiStore.denominations[i] === Core.SELECTED_DENOMINATION.value) {\n                currentLevel = i;\n            }\n        }\n        return currentLevel + 1;\n    }\n\n    protected createFakeBetButton(\n        index: number,\n        bet: number,\n        denomination: number,\n        betButtonTextures,\n        betButtonSelectedTextures,\n        betButtonFakeMaskTexture,\n    ): any {\n        return new FakeBetButton({\n            name: 'fakebet' + (index + 1),\n            betPerLine: bet,\n            currency: this.rootStore.uiStore.currency,\n            units: this.rootStore.uiStore.units,\n            denomination,\n            lines: this.rootStore.uiStore.LINES.value,\n            factor: this.rootStore.settings.factor,\n            width: this.componentConfiguration.betButtons[index].get('betConfig').width,\n            height: this.componentConfiguration.betButtons[index].get('betConfig').height,\n            text: Core.translator.translate('PLAY'),\n            textures: betButtonTextures,\n            selectedTextures: betButtonSelectedTextures,\n            fakeMaskTexture: betButtonFakeMaskTexture,\n            selected: false,\n            // betButtonStyles: this.configuration.betButtonStyles,\n            dynamicConfig: this.componentConfiguration.betButtons[index].get('betConfig'),\n            maxBet: this.rootStore.settings.maxBet,\n        });\n    }\n\n    protected animateFakeBetButtons(): void {\n        const animOffset: number = this.getAnimFakeBetButtonsOffset();\n        let nextDenomination: number = this.getCurrentDenominationLevel();\n        if (this.slideType === 'slideLeft') {\n            nextDenomination--;\n        } else if (this.slideType === 'slideRight') {\n            nextDenomination++;\n        }\n\n        if (this.slideType !== 'none') {\n            Core.sounds.play('slideButton');\n        }\n\n        // const config = this.positions[Core.ORIENTATION.value.orientation].mainPanel;\n\n        this.slideTimeline = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/bet-buttons/src/egt/modes/default/views/BetButtonsViewDefault.ts:777:30\",null]), gsap.to(this.betButtonsContainerGroup, {\n            x: this.componentConfiguration.betButtonsContainerGroup.x - animOffset,\n            duration: 0.5,\n            ease: 'sine',\n            onComplete: () => {\n                const chosenDenomination = this.rootStore.uiStore.denominations[nextDenomination - 1];\n                // do not restore state - it will be set after collect because denomanitaion change\n                let restoreState = true;\n                if (chosenDenomination !== Core.SELECTED_DENOMINATION.value) {\n                    restoreState = this.currentState !== UIState.WAITING_FOR_COLLECT;\n                    this.rootStore.subjects.SETTINGS_DENOMINATION_CHANGED.next({\n                        denomination: nextDenomination,\n                        playDenomChangeSound: false,\n                    });\n\n                    this.updateBetIfDisabled('bet');\n                }\n                this.resizeBetButtonsFonts();\n                this.showBetButtons();\n                this.showBetButtonParts();\n                // if (this.slideType === 'none') {\n                if (restoreState) {\n                    this.rootStore.uiStore.STATE.next(this.currentState);\n                }\n                this.betButtonsContainerGroup.x = this.componentConfiguration.betButtonsContainerGroup.x;\n                this.destroyFakeBetButtons();\n\n                if (\n                    !(\n                        this.rootStore.uiStore.CURRENT_BET_LEVEL.value.betLevel ===\n                            this.rootStore.uiStore.SELECTED_BET.value &&\n                        this.rootStore.uiStore.CURRENT_BET_LEVEL.value.denomLevel === Core.SELECTED_DENOMINATION.value\n                    )\n                ) {\n                    this.rootStore.uiStore.CURRENT_BET_LEVEL.next({\n                        betLevel: this.rootStore.uiStore.SELECTED_BET.value,\n                        denomLevel: Core.SELECTED_DENOMINATION.value,\n                    });\n                }\n            },\n        }));\n    }\n\n    protected updateBetIfDisabled(btnName: string) {\n        const selectedIndex = this.rootStore.uiStore.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value);\n        const currentSelectedButton: BetButton = this.find(btnName + (selectedIndex + 1));\n        if (!currentSelectedButton?.enabled) {\n            for (let i = selectedIndex - 1; i >= 0; i--) {\n                const leftButton: BetButton = this.find(btnName + (i + 1));\n                if (leftButton?.enabled) {\n                    this.rootStore.uiStore.SELECTED_BET.next(this.rootStore.uiStore.bets[i]);\n                    this.rootStore.subjects.SETTINGS_BET_CHANGED.next();\n                    break;\n                }\n            }\n        }\n    }\n\n    protected destroyFakeBetButtons(): void {\n        if (this.slideTimeline) {\n            this.slideTimeline.kill();\n            this.slideTimeline = null;\n        }\n        this.betButtonsContainerGroup.removeChildren();\n        this.moneyContainerGroup.removeChild(this.fakeBetButtonsMask);\n        this.betButtonsContainerGroup.mask = null;\n\n        this.fakeBetButtonsCurrent = [];\n        this.fakeBetButtonsNewLeft = [];\n        this.fakeBetButtonsNewRight = [];\n        this.betButtonsSlidingStart = false;\n        this.fakeBetButtonsOffset = 0;\n\n        this.rootStore.subjects.DISABLED_BUY_BONUS.next({ disabled: false, doNotChangeVisual: false });\n        this.rootStore.subjects.DISABLED_DOUBLE_CHANCE.next(false);\n        this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(false);\n    }\n\n    protected onFactorChanged(): void {\n        for (const betButton of this.betButtons) {\n            betButton.factor = this.settings.factor;\n        }\n    }\n\n    protected showBetButtonParts(): void {\n        if (Core.isDesktopMode) {\n            return;\n        }\n        this.betBtnPieceLeft.visible = false;\n        this.betBtnPieceRight.visible = false;\n        if (\n            this.feature.isInGiftSpins ||\n            this.rootStore.domainStore.SERVER_STATE.value === ServerState.BONUS_IDLE ||\n            this.isSlidingDisabledInCredits() ||\n            !this.isBetButtonsVisible()\n        ) {\n            return;\n        }\n        const denominationLevel: number = this.getCurrentDenominationLevel();\n\n        if (denominationLevel !== 1) {\n            this.betBtnPieceLeft.visible = true;\n        }\n        if (denominationLevel !== this.rootStore.uiStore.denominations.length) {\n            this.betBtnPieceRight.visible = true;\n        }\n    }\n\n    protected getAnimFakeBetButtonsOffset(): number {\n        let animOffset: number = 0;\n        if (this.slideType === 'slideLeft') {\n            animOffset = this.componentConfiguration.slideAnimation.leftSlidWidth;\n        } else if (this.slideType === 'slideRight') {\n            animOffset = this.componentConfiguration.slideAnimation.rightSlidWidth;\n        }\n        return animOffset;\n    }\n\n    protected createBetButtonsHitArea(container: ViewContainer): void {\n        this.betButtonsContainer = new Sprite();\n        this.betButtonsContainer.interactive = Core.isDesktopMode ? false : true;\n        container.addChild(this.betButtonsContainer);\n        this.slidBetButtonsHitArea = new Graphics();\n        this.slidBetButtonsHitArea.beginFill(0xff0000);\n        this.slidBetButtonsHitArea.alpha = 0;\n        this.slidBetButtonsHitArea.drawRect(0, -50, 660, 150);\n        this.slidBetButtonsHitArea.endFill();\n        this.slidBetButtonsHitArea.name = 'slidBetButtonsHitArea';\n        this.betButtonsContainer.addChild(this.slidBetButtonsHitArea);\n        if (Core.isDesktopMode) {\n            this.slidBetButtonsHitArea.visible = false;\n            this.slidBetButtonsHitArea.renderable = false;\n        }\n    }\n\n    protected createBetButtonsParts(container: ViewContainer): void {\n        this.fakeBetButtonsMask = new Sprite(\n            Core.assets.getTextureFromSpriteSheet('miscellaneous', 'betButtonsMask.png'),\n        );\n        this.fakeBetButtonsMask.name = 'fakeBetButtonsMask';\n        this.betBtnPieceLeft = new Sprite(\n            Core.assets.getTextureFromSpriteSheet('miscellaneous', 'betButtonPieceArrowLeft.png'),\n        );\n\n        this.betBtnPieceLeft.scale.set(0.5, 0.5);\n        container.addChild(this.betBtnPieceLeft);\n        this.betBtnPieceRight = new Sprite(\n            Core.assets.getTextureFromSpriteSheet('miscellaneous', 'betButtonPieceArrowRight.png'),\n        );\n        this.betBtnPieceRight.scale.set(0.5, 0.5);\n        container.addChild(this.betBtnPieceRight);\n\n        this.betBtnPieceLeft.interactive = true;\n        this.betBtnPieceRight.interactive = true;\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/bet-buttons/src/egt/modes/default/views/BetButtonsViewDefault.ts:931:9\",(this.betBtnPieceLeft),\"pointertap\"]), fromEvent(this.betBtnPieceLeft, 'pointertap'))\n            .pipe(\n                filter((_x) => this.rootStore.subjects.SHOW_JP_STATS.value.type === -1),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(() => {\n                this.slidArrowsClicked('slideLeft');\n            });\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/bet-buttons/src/egt/modes/default/views/BetButtonsViewDefault.ts:939:9\",(this.betBtnPieceRight),\"pointertap\"]), fromEvent(this.betBtnPieceRight, 'pointertap'))\n            .pipe(\n                filter((_x) => this.rootStore.subjects.SHOW_JP_STATS.value.type === -1),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(() => {\n                this.slidArrowsClicked('slideRight');\n            });\n\n        this.showBetButtonParts();\n    }\n\n    protected setBetButtonsLable(lable: string): void {\n        const nextLable = Core.translator.translate(lable);\n        // biome-ignore lint/suspicious/noAssignInExpressions: <explanation>\n        this.betButtons.forEach((button) => (button.text = nextLable));\n    }\n\n    protected applyFontSize(defaultFontSize: number): void {\n        let minFontSize: number = defaultFontSize;\n\n        for (const betButton of this.betButtons) {\n            betButton.fontSize = defaultFontSize;\n            minFontSize = Math.min(minFontSize, betButton.fontSize);\n        }\n        if (defaultFontSize > minFontSize) {\n            for (const betButton of this.betButtons) {\n                betButton.fontSize = minFontSize;\n            }\n        }\n        this.showBetButtonParts();\n    }\n\n    protected slidArrowsClicked(slideType: 'slideLeft' | 'slideRight' | 'none'): void {\n        if (\n            (this.rootStore.domainStore.SERVER_STATE.value === ServerState.IDLE &&\n                this.rootStore.uiStore.STATE.value === UIState.IDLE) ||\n            (this.rootStore.domainStore.SERVER_STATE.value === ServerState.WIN &&\n                this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT)\n        ) {\n            AnalyticsDispatcher.slideFeatureEvent(this.rootStore.uiStore.SELECTED_BET.value);\n            this.slideType = slideType;\n            this.betButtonsSlidingStart = true;\n            this.createFakeBetButtons();\n\n            this.betButtonsSlidingStart = false;\n            this.animateFakeBetButtons();\n        }\n    }\n\n    public resizeBetButtonsFonts(): void {\n        // const defaultFontSize: number = Number(\n        //     this.componentConfiguration.betButtonsConfigs.amount.defaultStyle.fontSize,\n        // );\n        // if (Core.isDesktopMode) {\n        //     defaultFontSize = 27;\n        // }\n\n        this.updateBetIfDisabled('bet');\n        this.applyFontSize(this.initialValueFontSize);\n    }\n\n    protected resizeFakeBetButtonsFonts(): void {\n        const defaultFontSize: number = Number(\n            this.componentConfiguration.betButtonsConfigs.amount.defaultStyle.fontSize,\n        );\n        let minFontSizeCurrentButtons: number = defaultFontSize;\n        let minFontSizeNewButtons: number = defaultFontSize;\n\n        for (const currentBetButton of this.fakeBetButtonsCurrent) {\n            currentBetButton.fontSize = defaultFontSize;\n            minFontSizeCurrentButtons = Math.min(minFontSizeCurrentButtons, currentBetButton.fontSize as number);\n        }\n        if (defaultFontSize > minFontSizeCurrentButtons) {\n            for (const currentBetButton of this.fakeBetButtonsCurrent) {\n                currentBetButton.fontSize = minFontSizeCurrentButtons;\n            }\n        }\n\n        for (const newBetButton of this.fakeBetButtonsNewLeft) {\n            newBetButton.fontSize = defaultFontSize;\n            minFontSizeNewButtons = Math.min(minFontSizeNewButtons, newBetButton.fontSize as number);\n        }\n        if (defaultFontSize > minFontSizeNewButtons) {\n            for (const newBetButton of this.fakeBetButtonsNewLeft) {\n                newBetButton.fontSize = minFontSizeNewButtons;\n            }\n        }\n\n        for (const newBetButton of this.fakeBetButtonsNewRight) {\n            newBetButton.fontSize = defaultFontSize;\n            minFontSizeNewButtons = Math.min(minFontSizeNewButtons, newBetButton.fontSize as number);\n        }\n        if (defaultFontSize > minFontSizeNewButtons) {\n            for (const newBetButton of this.fakeBetButtonsNewRight) {\n                newBetButton.fontSize = minFontSizeNewButtons;\n            }\n        }\n    }\n\n    protected updateExactBetBtnDisplayModeConfig(\n        index: number,\n        alteredPositons?: { [K in 'desktop' | 'landscape' | 'portrait']?: { x?: number; y?: number } },\n    ): void {\n        if (alteredPositons) {\n            // altering betButtonsComponentConfigration\n            for (const mode in alteredPositons) {\n                if (this.componentConfiguration.betButtons[index].positionData[mode]) {\n                    // keeping original componentConfig for dedicated btn;\n                    this.alteredBtnOriginalPosition[mode] = {\n                        ...this.componentConfiguration.betButtons[index].positionData[mode],\n                    };\n\n                    this.componentConfiguration.betButtons[index].positionData[mode] = {\n                        ...this.componentConfiguration.betButtons[index].positionData[mode],\n                        ...alteredPositons[mode],\n                    };\n                }\n            }\n        } else if (Object.keys(this.alteredBtnOriginalPosition).length) {\n            // reverting changes made to betBtnComponentConfiguration\n            for (const mode in this.alteredBtnOriginalPosition) {\n                if (this.componentConfiguration.betButtons[index].positionData[mode]) {\n                    this.componentConfiguration.betButtons[index].positionData[mode] = {\n                        ...this.alteredBtnOriginalPosition[mode],\n                    };\n                }\n            }\n            this.alteredBtnOriginalPosition = {};\n        }\n    }\n\n    private linesChanged(_lines: number): void {\n        this.betButtons.forEach((button: BetButton) => {\n            button.lines = this.rootStore.uiStore.LINES.value;\n        });\n    }\n\n    private isBetButtonsVisible(): boolean {\n        return this.betButtons.every((button) => button.visible);\n    }\n\n    private changeMoneyContainerGroupAlpha(val: 'customAlpha' | 'defaultAlpha'): void {\n        if (val === 'defaultAlpha') {\n            this.moneyContainerGroup.alpha = this.componentConfiguration.moneyContainerGroupAlpha.defaultAlpha;\n        } else {\n            this.moneyContainerGroup.alpha = this.componentConfiguration.moneyContainerGroupAlpha.customAlpha;\n        }\n    }\n\n    protected onKeyReleased(e: KeyboardEvent): void {\n        if (\n            ![UIState.IDLE, UIState.BONUS_IDLE, UIState.WAITING_FOR_COLLECT].includes(\n                this.rootStore.uiStore.STATE.value as UIState,\n            )\n        ) {\n            return;\n        }\n\n        const bets: number[] = this.rootStore.uiStore.bets;\n        const betIndex = bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value);\n\n        if (e === null || !this.betButtons[betIndex] || !this.betButtons[betIndex].visible) {\n            return;\n        }\n\n        if (e.keyCode !== undefined && (e.code === 'BracketLeft' || e.code === 'BracketRight' || e.code === 'KeyT')) {\n            // when using the turtle UI, we are going to use the internal increase and decrease bet\n            // functionality from the turtle UI in/decrease bet buttons. That's why we handle the\n            // BracketLeft/Right keys only for the other ui views\n            if (\n                !Core.hasComponent(SlotComponents.UI_VIEW, UIViewModes.TURTLE) &&\n                this.rootStore.uiStore.STATE.value !== UIState.BONUS_IDLE\n            ) {\n                if (e.code === 'BracketLeft') {\n                    this.decreaseBet();\n                } else if (e.code === 'BracketRight') {\n                    this.increaseBet();\n                }\n            } else if (e.code === 'KeyT' && this.rootStore.uiStore.STATE.value !== UIState.BONUS_IDLE) {\n                this.setMaxPossibleBet();\n            }\n        }\n    }\n\n    protected setMaxPossibleBet(): void {\n        const bets: number[] = this.settings.bets;\n        const maxDenomination = this.settings.denominations[this.settings.denominations.length - 1];\n        const maxPossibleBet = bets[bets.length - 1];\n\n        Core.SELECTED_DENOMINATION.next(maxDenomination);\n        this.rootStore.uiStore.SELECTED_BET.next(maxPossibleBet);\n        this.rootStore.subjects.DENOMINATIONS_CHANGED.next();\n        this.rootStore.subjects.SETTINGS_BET_CHANGED.next();\n        this.rootStore.uiStore.CURRENT_BET_LEVEL.next({\n            betLevel: this.rootStore.uiStore.SELECTED_BET.value,\n            denomLevel: Core.SELECTED_DENOMINATION.value,\n        });\n        this.rootStore.subjects.CHANGE_SELECTED_BET_BTN_EXTERNALLY.next({\n            betVal: this.rootStore.uiStore.SELECTED_BET.value,\n            changedFromPopUp: false,\n        });\n    }\n\n    protected increaseBet(): void {\n        const bets: number[] = this.rootStore.uiStore.bets;\n        const betIndex = bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value);\n        if (\n            betIndex < bets.length - 1 &&\n            this.rootStore.uiStore.STATE.value !== UIState.SLIDING_BETS &&\n            this.betButtons[betIndex + 1].enabled\n        ) {\n            this.rootStore.uiStore.SELECTED_BET.next(bets[betIndex + 1]);\n            this.betButtons[betIndex].selected = false;\n            this.betButtons[betIndex + 1].selected = true;\n        } else if (this.betBtnPieceRight.visible) {\n            this.betButtons[betIndex].selected = false;\n            this.betButtons[0].selected = true;\n            this.rootStore.uiStore.SELECTED_BET.next(bets[0]);\n            this.slidArrowsClicked('slideRight');\n        }\n        this.rootStore.uiStore.CURRENT_BET_LEVEL.next({\n            betLevel: this.rootStore.uiStore.SELECTED_BET.value,\n            denomLevel: Core.SELECTED_DENOMINATION.value,\n        });\n        this.rootStore.subjects.CHANGE_SELECTED_BET_BTN_EXTERNALLY.next({\n            betVal: this.rootStore.uiStore.SELECTED_BET.value,\n            changedFromPopUp: false,\n        });\n    }\n\n    protected decreaseBet(): void {\n        const bets: number[] = this.rootStore.uiStore.bets;\n        const betIndex = bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value);\n        if (betIndex > 0 && this.rootStore.uiStore.STATE.value !== UIState.SLIDING_BETS) {\n            this.rootStore.uiStore.SELECTED_BET.next(bets[betIndex - 1]);\n            this.betButtons[betIndex].selected = false;\n            this.betButtons[betIndex - 1].selected = true;\n        } else if (this.betBtnPieceLeft.visible) {\n            this.betButtons[betIndex].selected = false;\n            this.betButtons[bets.length - 1].selected = true;\n            this.rootStore.uiStore.SELECTED_BET.next(bets[bets.length - 1]);\n            this.slidArrowsClicked('slideLeft');\n        }\n        this.rootStore.uiStore.CURRENT_BET_LEVEL.next({\n            betLevel: this.rootStore.uiStore.SELECTED_BET.value,\n            denomLevel: Core.SELECTED_DENOMINATION.value,\n        });\n        this.rootStore.subjects.CHANGE_SELECTED_BET_BTN_EXTERNALLY.next({\n            betVal: this.rootStore.uiStore.SELECTED_BET.value,\n            changedFromPopUp: false,\n        });\n    }\n\n    protected setBetButtonsOpacity(opacity: number): void {\n        this.betButtons.forEach((button) => {\n            //selected btn should remain with default opacity\n            if (!button.selected) {\n                button.alpha = opacity;\n            }\n            // button.enabled = opacity < 1 ? false : true;\n        });\n        if (!Core.isDesktopMode) {\n            if (opacity === 1) {\n                this.betBtnPieceLeft.alpha = 1;\n                this.betBtnPieceRight.alpha = 1;\n            } else {\n                this.betBtnPieceLeft.alpha = opacity;\n                this.betBtnPieceRight.alpha = opacity;\n            }\n        }\n    }\n}\n","import {\n    AssetPriority,\n    BaseComponentConfiguration,\n    DefaultValue,\n    DynamicPositionObject,\n    PositionObject,\n} from '@egt/core';\nimport { AutoAlign, IBetButtonsConfig, TextAlign } from '@egt/ui-lib';\nimport { TextStyle } from 'pixi.js';\nimport {\n    IBetButton,\n    IFakeBetButtonsMask,\n    IMoneyContainerGroupAlpha,\n    IPiecePosition,\n    ISlidAnim,\n    ISlidBetButtonsHitArea,\n} from '../../../common/interfaces/InterfacesCommon';\nimport { IBetButtonsComponentConfigurationOneDenom } from './IBetButtonsComponentConfigurationOneDenom';\n\nexport default class BetButtonsComponentConfigurationOneDenom extends BaseComponentConfiguration {}\n\nexport function BetButtonsComponentConfigurationFactoryOneDenom(): any {\n    class BetButtonsComponentConfigurationOneDenomInternalClass\n        extends BetButtonsComponentConfigurationOneDenom\n        implements IBetButtonsComponentConfigurationOneDenom\n    {\n        public assets = [\n            {\n                id: 'svgBet',\n                url: '../assets/components/slot/bet-buttons/one-denom/ui-svg/standardButton.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 134, height: 96 },\n                    desktop: { width: 134, height: 96 },\n                },\n            },\n            {\n                id: 'svgBetPressed',\n                url: '../assets/components/slot/bet-buttons/one-denom/ui-svg/standardButtonPressed.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 134, height: 96 },\n                    desktop: { width: 134, height: 96 },\n                },\n            },\n            {\n                id: 'svgActiveBet',\n                url: '../assets/components/slot/bet-buttons/one-denom/ui-svg/standardButtonPressed.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 134, height: 96 },\n                    desktop: { width: 134, height: 96 },\n                },\n            },\n            {\n                id: 'svgActiveBetPressed',\n                url: '../assets/components/slot/bet-buttons/one-denom/ui-svg/standardButtonPressed.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 134, height: 96 },\n                    desktop: { width: 134, height: 96 },\n                },\n            },\n            {\n                id: 'svgBetHover',\n                url: '../assets/components/slot/bet-buttons/one-denom/ui-svg/standardButtonPressed.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 134, height: 96 },\n                    desktop: { width: 134, height: 96 },\n                },\n            },\n            {\n                id: 'svgActiveBetHover',\n                url: '../assets/components/slot/bet-buttons/one-denom/ui-svg/standardButtonPressed.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 134, height: 96 },\n                    desktop: { width: 134, height: 96 },\n                },\n            },\n        ];\n\n        public betButtonsContainerGroup: PositionObject = new PositionObject({\n            landscape: { x: 150.5, y: 662, width: 1080, height: 104 },\n            portrait: { x: 0, y: 693, width: 765, height: 250 },\n            desktop: { x: 151, y: 641, width: 1360, height: 87 },\n        });\n        public moneyContainerGroup: PositionObject = new PositionObject({\n            landscape: { x: 150.5, y: 662, width: 1080, height: 104 },\n            portrait: { x: 0, y: 693, width: 765, height: 250 },\n            desktop: { x: 151, y: 641, width: 1360, height: 87 },\n        });\n\n        @DefaultValue<IMoneyContainerGroupAlpha>({\n            defaults: {\n                defaultAlpha: 1,\n                customAlpha: 0.5,\n            },\n        })\n        public moneyContainerGroupAlpha: DynamicPositionObject<IMoneyContainerGroupAlpha> & IMoneyContainerGroupAlpha;\n\n        @DefaultValue<IPiecePosition>({\n            defaults: {\n                x: 833,\n                y: 4,\n            },\n            portrait: {\n                x: 718.5,\n                y: 149,\n            },\n        })\n        public rightPiecePosition: DynamicPositionObject<IPiecePosition> & IPiecePosition;\n\n        @DefaultValue<IPiecePosition>({\n            defaults: {\n                x: 185,\n                y: 4,\n            },\n            portrait: {\n                x: 6.5,\n                y: 149,\n            },\n        })\n        public leftPiecePosition: DynamicPositionObject<IPiecePosition> & IPiecePosition;\n\n        @DefaultValue<ISlidAnim>({\n            defaults: {\n                leftSlidWidth: -605,\n                rightSlidWidth: 605,\n            },\n            portrait: {\n                leftSlidWidth: -655,\n                rightSlidWidth: 655,\n            },\n        })\n        public slideAnimation: DynamicPositionObject<ISlidAnim> & ISlidAnim;\n\n        @DefaultValue<IFakeBetButtonsMask>({\n            defaults: {\n                x: 200,\n                y: 0,\n                scaleX: 0.935,\n                scaleY: 1.5,\n            },\n            portrait: {\n                x: 23,\n                y: 146,\n                scaleX: 1.02,\n                scaleY: 1,\n            },\n            desktop: {\n                scaleY: 0.8,\n            },\n        })\n        public fakeBetButtonsMask: DynamicPositionObject<IFakeBetButtonsMask> & IFakeBetButtonsMask;\n\n        @DefaultValue<ISlidBetButtonsHitArea>({\n            defaults: {\n                x: 200,\n                y: 0,\n            },\n            portrait: {\n                x: 53,\n                y: 146,\n            },\n        })\n        public slidBetButtonsHitArea: DynamicPositionObject<ISlidBetButtonsHitArea> & ISlidBetButtonsHitArea;\n\n        public fakeBetButtonsPositionsLeft: PositionObject[] = [\n            new PositionObject({\n                landscape: { x: -378, y: 4 },\n                portrait: { x: -593, y: 149 },\n            }),\n            new PositionObject({\n                landscape: { x: -257, y: 4 },\n                portrait: { x: -462, y: 149 },\n            }),\n            new PositionObject({\n                landscape: { x: -136, y: 4 },\n                portrait: { x: -331, y: 149 },\n            }),\n            new PositionObject({\n                landscape: { x: -15, y: 4 },\n                portrait: { x: -200, y: 149 },\n            }),\n            new PositionObject({\n                landscape: { x: 106, y: 4 },\n                portrait: { x: -69, y: 149 },\n            }),\n        ];\n        public fakeBetButtonsPositionsRight: PositionObject[] = [\n            new PositionObject({\n                landscape: { x: 832, y: 4 },\n                portrait: { x: 717, y: 149 },\n            }),\n            new PositionObject({\n                landscape: { x: 953, y: 4 },\n                portrait: { x: 848, y: 149 },\n            }),\n            new PositionObject({\n                landscape: { x: 1074, y: 4 },\n                portrait: { x: 979, y: 149 },\n            }),\n            new PositionObject({\n                landscape: { x: 1195, y: 4 },\n                portrait: { x: 1110, y: 149 },\n            }),\n            new PositionObject({\n                landscape: { x: 1316, y: 4 },\n                portrait: { x: 1241, y: 149 },\n            }),\n        ];\n\n        @DefaultValue<IBetButtonsConfig>({\n            defaults: {\n                currency: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                        fontSize: 18,\n                        fill: '#C6C5C5',\n                        letterSpacing: 0.9,\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                        fontSize: 18,\n                        fill: '#FFD200',\n                        letterSpacing: 0.9,\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 3.5,\n                    bounds: { width: 106, height: 30 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                amount: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                        fontSize: 42,\n                        fill: '#C6C5C5', // '#FFFFFF'\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                        fontSize: 42,\n                        fill: '#FFFFFF',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 30,\n                    bounds: { width: 106, height: 34 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                label: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                        fontSize: 22,\n                        fill: '#FFD200',\n                        padding: 5,\n                        letterSpacing: 0.66,\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                        fontSize: 22,\n                        fill: '#FFD200',\n                        padding: 5,\n                        letterSpacing: 0.66,\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 61,\n                    bounds: { width: 106, height: 30 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                stamp: {\n                    hasStamp: false,\n                    x: 0,\n                    y: 0,\n                    width: 0,\n                    height: 0,\n                    alpha: 0,\n                    texture: { source: '', name: '' },\n                },\n                textures: ['svgBet', 'svgBetPressed', 'svgBet', 'svgBet'],\n                selectedTextures: ['svgActiveBet', 'svgActiveBetPressed', 'svgActiveBet', 'svgActiveBet'],\n                fakeMaskTexture: 'maxBet',\n                width: 120,\n                height: 96,\n            },\n            desktop: {\n                currency: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                        fontSize: 15,\n                        fill: '#C6C5C5', // '#FFD200'\n                        letterSpacing: 0.75,\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                        fontSize: 15,\n                        fill: '#FFD200',\n                        letterSpacing: 0.75,\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 3,\n                    bounds: { width: 84, height: 20 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                amount: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                        fontSize: 35,\n                        fill: '#C6C5C5', // '#FFFFFF'\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                        fontSize: 35,\n                        fill: '#FFFFFF',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 27.5,\n                    bounds: { width: 84, height: 20 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                label: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                        fontSize: 16,\n                        fill: '#FFD200',\n                        letterSpacing: 1.12,\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                        fontSize: 16,\n                        fill: '#FFD200',\n                        letterSpacing: 1.12,\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 54,\n                    bounds: { width: 78, height: 17 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                textures: ['svgBet', 'svgBetPressed', 'svgBetHover', 'svgBet'],\n                selectedTextures: ['svgActiveBet', 'svgActiveBetPressed', 'svgActiveBetHover', 'svgActiveBet'],\n                width: 94,\n                height: 75,\n            },\n        })\n        public betButtonsConfigs: DynamicPositionObject<IBetButtonsConfig> & IBetButtonsConfig;\n\n        public betButtons: Array<DynamicPositionObject<IBetButton>> = [\n            new DynamicPositionObject<IBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs, x: 0, y: 0 },\n                landscape: { x: 227, y: 4 },\n                portrait: { x: 58.5, y: 149 },\n                desktop: { x: 282, y: 6 },\n            }),\n            new DynamicPositionObject<IBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs, x: 0, y: 0 },\n                landscape: { x: 348, y: 4 },\n                portrait: { x: 190.5, y: 149 },\n                desktop: { x: 382, y: 6 },\n            }),\n            new DynamicPositionObject<IBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs, x: 0, y: 0 },\n                landscape: { x: 469, y: 4 },\n                portrait: { x: 322.5, y: 149 },\n                desktop: { x: 482, y: 6 },\n            }),\n            new DynamicPositionObject<IBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs, x: 0, y: 0 },\n                landscape: { x: 590, y: 4 },\n                portrait: { x: 454.5, y: 149 },\n                desktop: { x: 582, y: 6 },\n            }),\n            new DynamicPositionObject<IBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs, x: 0, y: 0 },\n                landscape: { x: 711, y: 4 },\n                portrait: { x: 586.5, y: 149 },\n                desktop: { x: 682, y: 6 },\n            }),\n        ];\n    }\n    return BetButtonsComponentConfigurationOneDenomInternalClass;\n}\n","import Core, { BaseController, FeatureFlags, Timers } from '@egt/core';\nimport {\n    FeatureController,\n    Features,\n    ISlotConfiguration,\n    InitialSettings,\n    RootStore,\n    ServerState,\n    UIState,\n} from '@egt/slot';\nimport { BetButton } from '@egt/ui-lib';\nimport { filter, take, takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport BetButtonsViewOneDenom from '../views/BetButtonsViewOneDenom';\nimport { fromEvent, merge } from 'rxjs';\n\n@injectable()\nexport default class BetButtonsControllerOneDenom extends BaseController {\n    public ready: () => Promise<void>;\n\n    private inactivityTimer;\n    private inactivityTimeout: number = 3000;\n\n    constructor(\n        @inject('BetButtonsView') protected view: BetButtonsViewOneDenom,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('FeatureController') protected featureController: FeatureController,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('InitialSettings') protected initialSettings: InitialSettings,\n    ) {\n        super(view);\n\n        this.rootStore.subjects.DENOMINATIONS_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onDenominationsChanged.bind(this),\n        );\n\n        this.attachEventListeners();\n        this.selectBet(\n            'bet' + (this.rootStore.uiStore.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value) + 1),\n            true,\n        );\n    }\n\n    public async onGameStarted(): Promise<void> {\n        const interactionEvents = ['click', 'touchstart', 'mousemove', 'keydown'];\n        merge(...interactionEvents.map((event) => fromEvent(window, event)))\n            .pipe(take(2))\n            .subscribe(() => {\n                this.clearInactivityTimer();\n            });\n\n        this.inactivityTimer = Timers.setTimeout(() => {\n            this.view.onGameLoaded();\n        }, this.inactivityTimeout);\n    }\n\n    public onAfterInitialRender(): void {\n        const hasDefaultMinBetRestriction = Core.flags.isActive(FeatureFlags.USE_DEFAULT_BET_ON_LOAD);\n        const isIdleState = this.initialSettings.state === ServerState.IDLE;\n        if (hasDefaultMinBetRestriction && isIdleState) {\n            Core.SELECTED_DENOMINATION.next(this.initialSettings?.settings?.settings?.denomination);\n            this.rootStore.uiStore.SELECTED_BET.next(this.initialSettings?.settings?.settings?.bet);\n            this.rootStore.subjects.SETTINGS_BET_CHANGED.next();\n        }\n        this.rootStore.uiStore.CURRENT_BET_LEVEL.next({\n            betLevel: this.rootStore.uiStore.SELECTED_BET.value,\n            denomLevel: Core.SELECTED_DENOMINATION.value,\n        });\n    }\n\n    protected onDenominationsChanged(): void {\n        this.view.onDenominationsChanged();\n        if (!this.view.oneDenomView) {\n            this.addBetButtonsEventListeners();\n        }\n    }\n\n    protected attachEventListeners(): void {\n        this.addBetButtonsEventListeners();\n\n        this.view.UPDATE_SELECTED_BET.pipe(takeUntil(this.DESTROY)).subscribe(this.selectWhenSliding.bind(this));\n\n        this.rootStore.subjects.SETTINGS_BET_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.selectFromSettings.bind(this),\n        );\n\n        // this.rootStore.subjects.SETTINGS_POPUP_CLOSED.pipe(takeUntil(this.DESTROY)).subscribe(\n        //     this.onSettingsPopupClosed.bind(this),\n        // );\n\n        // this.rootStore.subjects.SETTINGS_POPUP_OPENED.pipe(takeUntil(this.DESTROY)).subscribe(\n        //     this.onSettingsPopupOpened.bind(this),\n        // );\n\n        this.rootStore.uiStore.SHOW_HIDE_BET_BUTTONS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.showHideBetButtons.bind(this),\n        );\n\n        this.rootStore.subjects.KEY_UP.pipe(takeUntil(this.DESTROY)).subscribe(this.onKeyReleased.bind(this));\n        this.rootStore.subjects.SWITCH_BET_BUTTONS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.switchBetButtons.bind(this),\n        );\n\n        this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onExtendedMultipleBuyBonusActivated.bind(this),\n        );\n    }\n\n    private addBetButtonsEventListeners(): void {\n        this.view.betButtons.forEach((_bet, index) => {\n            this.view\n                .find('bet' + (index + 1))\n                .CLICK.pipe(\n                    filter(\n                        (_x) =>\n                            !this.rootStore.subjects.KEY_DOWN.value &&\n                            this.rootStore.subjects.SHOW_JP_STATS.value.type === -1,\n                    ),\n                    takeUntil(this.DESTROY),\n                )\n                .subscribe(this.onSelectedBetChanged.bind(this, 'bet' + (index + 1)));\n        });\n    }\n\n    protected onExtendedMultipleBuyBonusActivated(value: boolean): void {\n        if (\n            this.rootStore.settings.haveGameMode('DOUBLE_CHANCE') &&\n            this.rootStore.settings.factor === this.rootStore.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE')\n        ) {\n            value = false;\n        }\n        for (const betButton of this.view.betButtons) {\n            betButton.buyBonusActivated = value;\n        }\n        // Timers.setTimeout(()=>{\n        this.view.resizeBetButtonsFonts();\n        // },1000);\n    }\n\n    protected selectWhenSliding(e): void {\n        const betButton = 'bet' + (this.rootStore.uiStore.bets.indexOf(e) + 1);\n        const button: BetButton = this.view.find(betButton);\n        if (!button) {\n            return;\n        }\n        this.view.slideIfNotVisible(false);\n        this.view.clearBetSelection();\n        button.selected = true;\n    }\n\n    protected selectFromSettings(): void {\n        this.selectBet(\n            'bet' + (this.rootStore.uiStore.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value) + 1),\n            true,\n        );\n    }\n\n    protected selectBet(betButton: string, fromSettings: boolean = false): void {\n        const button: BetButton = this.view.find(betButton);\n        if (!button) {\n            return;\n        }\n        this.rootStore.uiStore.SELECTED_BET.next(button.betPerLine);\n        this.view.slideIfNotVisible(false, undefined, fromSettings);\n        this.view.clearBetSelection();\n        button.selected = true;\n    }\n\n    protected onKeyReleased(e: KeyboardEvent): void {\n        if (\n            e &&\n            this.rootStore.uiStore.SHOW_SETTINGS.value &&\n            ['ArrowDown', 'KeyC', 'KeyV', 'KeyB', 'KeyN', 'KeyM'].indexOf(e.code) > -1\n        ) {\n            return;\n        }\n        if (e === null || Core.UI_BLOCKER.value) {\n            return;\n        }\n        const currentUIState = this.rootStore.uiStore.STATE.value;\n\n        if ((e.code !== undefined && e.code === 'KeyC') || (e.keyCode !== undefined && e.keyCode === 67)) {\n            this.reactBasedOnState(currentUIState, 1);\n        }\n        if ((e.code !== undefined && e.code === 'KeyV') || (e.keyCode !== undefined && e.keyCode === 86)) {\n            this.reactBasedOnState(currentUIState, 2);\n        }\n        if ((e.code !== undefined && e.code === 'KeyB') || (e.keyCode !== undefined && e.keyCode === 66)) {\n            this.reactBasedOnState(currentUIState, 3);\n        }\n        if ((e.code !== undefined && e.code === 'KeyN') || (e.keyCode !== undefined && e.keyCode === 78)) {\n            this.reactBasedOnState(currentUIState, 4);\n        }\n        if ((e.code !== undefined && e.code === 'KeyM') || (e.keyCode !== undefined && e.keyCode === 77)) {\n            this.reactBasedOnState(currentUIState, 5);\n        }\n    }\n\n    protected reactBasedOnState(state: string, buttonValue: number): void {\n        let but = this.view.betButtons.filter((x) => x.name === 'bet' + buttonValue)[0];\n        if (this.view.oneDenomView) {\n            but = this.view.visibleBetButtons[buttonValue - 1];\n        }\n        if (!but || but.enabled === false || but.interactive === false) {\n            return;\n        }\n        switch (state) {\n            case UIState.IDLE:\n            case UIState.WAITING_FOR_COLLECT:\n            case UIState.BONUS_IDLE:\n                this.onBetButtonKeyPressed(but.name);\n\n                break;\n        }\n    }\n    protected onBetButtonKeyPressed(butName: string): void {\n        if (\n            this.rootStore.domainStore.SPIN_MODE.value !== Features.MANUAL_SPIN ||\n            Core.UI_BLOCKER.value ||\n            this.rootStore.uiStore.STATE.value === UIState.COLLECT_BEFORE_IDLE\n        ) {\n            return;\n        }\n        if (this.rootStore.subjects.TAB_OPENED.value) {\n            this.rootStore.subjects.CLOSE_SETTINGS_POPUP.next();\n            this.rootStore.subjects.RESET_AUTOPLAY_RESTRICTIONS.next();\n            return;\n        }\n        this.view.find(butName).CLICK.next();\n    }\n\n    protected onSelectedBetChanged(betButton: string): void {\n        if (!this.featureController.isInGiftSpins) {\n            this.selectBet(betButton);\n            this.rootStore.uiStore.CLEAR_BANG_UP.next();\n            if (this.rootStore.uiStore.CURRENT_BET_LEVEL.value.betLevel !== this.view.find(betButton).betPerLine) {\n                this.rootStore.uiStore.CURRENT_BET_LEVEL.next({\n                    betLevel: this.rootStore.uiStore.SELECTED_BET.value,\n                    denomLevel: Core.SELECTED_DENOMINATION.value,\n                });\n            }\n            this.rootStore.subjects.START_MANUAL_SPIN.next();\n        }\n        if (this.view.betButtons[0].name === betButton) {\n            this.rootStore.subjects.FIRST_BET_CLICKED.next();\n        }\n    }\n\n    protected switchBetButtons(event: { fromIndex: number; toIndex: number }): any {\n        if (event.fromIndex === event.toIndex) {\n            return;\n        }\n        this.view.switchBetButtons(event.fromIndex, event.toIndex);\n    }\n\n    private showHideBetButtons(show: boolean): void {\n        if (show) {\n            this.view.showBetButtons();\n        } else {\n            this.view.hideBetButtons();\n        }\n    }\n\n    private clearInactivityTimer(): void {\n        if (this.inactivityTimer) {\n            Timers.clearTimeout(this.inactivityTimer);\n            this.inactivityTimer = null;\n        }\n    }\n}\n","import { BuyBonusModes } from '@egt/buy-bonus';\nimport Core, { AnalyticsDispatcher, IOrientation, Timers } from '@egt/core';\nimport {\n    FeatureController,\n    ISlotConfiguration,\n    InitialSettings,\n    RootStore,\n    ServerState,\n    SlotComponents,\n    UIState,\n} from '@egt/slot';\nimport { BetButton, ButtonStates, ViewContainer } from '@egt/ui-lib';\nimport { gsap } from 'gsap';\nimport { Graphics, InteractionEvent, Sprite } from 'pixi.js';\nimport { fromEvent } from 'rxjs';\nimport { filter, takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport BetButtonsViewDefault from '../../default/views/BetButtonsViewDefault';\nimport { IBetButtonsComponentConfigurationOneDenom } from '../configuration/IBetButtonsComponentConfigurationOneDenom';\n\n// TO DO refactor this class to extends common view not view from Default mode\n// default mode view should be refactored to use this new common view\n@injectable()\nexport default class BetButtonsViewOneDenom extends BetButtonsViewDefault {\n    private buttonsHidden: boolean;\n\n    private isSlidingInitialized;\n    private startTouchX;\n    private lastTouchX;\n    private startTouchTime;\n    private slidingAnimation;\n    private buttonsToSlide;\n    private slideToBet: number;\n\n    protected betsModalLayer: Graphics;\n\n    private initialVisibleSelectedIndex: number = -1;\n\n    // sliding demonstration props\n    private initialAnimationTimeouts: any[] = [];\n    private initialAnimationInProgress: boolean = false;\n\n    private fakeActiveBet: BetButton;\n    private fakeActiveBetPositionIndex: number;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected configuration: ISlotConfiguration,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('FeatureController') protected feature: FeatureController,\n        @inject('BetButtonsComponentConfiguration')\n        protected componentConfiguration: IBetButtonsComponentConfigurationOneDenom,\n    ) {\n        super(rootStore, configuration, settings, feature, componentConfiguration);\n        this.updateVisibleButtons();\n        this.slideIfNotVisible(false);\n\n        this.rootStore.uiStore.SHOW_HIDE_EXACT_BET_BUTTON.pipe(takeUntil(this.DESTROY)).subscribe(\n            ({ index, visible }) => {\n                this.betButtons[index].visible = false;\n                this.fakeBetButtonsMask.visible = visible;\n            },\n        );\n\n        this.rootStore.uiStore.SHOW_FAKE_ACTIVE_BET.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.showFakeActiveBet.bind(this),\n        );\n        this.rootStore.uiStore.ANIMATE_BET_BTNS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.animateBetBtnsExternally.bind(this),\n        );\n\n        this.rootStore.subjects;\n\n        Core.ON_SERVER_MESSAGE.pipe(takeUntil(this.DESTROY)).subscribe(this.onMessage.bind(this));\n    }\n\n    public onGameLoaded() {\n        if (\n            this.rootStore.domainStore.SERVER_STATE.value === ServerState.IDLE &&\n            this.rootStore.uiStore.STATE.value === UIState.IDLE &&\n            !Core.isDesktopMode\n        ) {\n            this.simulateFakeTouchEvents(this.betButtonsContainer);\n        }\n    }\n\n    public onDenominationsChanged() {\n        return;\n    }\n\n    public initialRender(): void {\n        this.saveCurrentUIState();\n        this.oneDenomView = this.rootStore.uiStore.bets.length > this.componentConfiguration.betButtons.length;\n\n        super.initialRender();\n        this.createBetsModalLayer();\n        this.createSlidBetButtonsEvents();\n\n        if (this.fakeBetButtonsMask) {\n            this.moneyContainerGroup.addChild(this.fakeBetButtonsMask);\n            this.betButtonsContainer.mask = this.fakeBetButtonsMask;\n        }\n    }\n\n    public destroy(): void {\n        super.destroy();\n        this.killSlidingAnimation();\n        this.killInitialAnimationTimeouts();\n        if (this.fakeActiveBet) {\n            this.fakeActiveBet.destroy();\n            // @ts-ignore\n            this.fakeActiveBet = null;\n        }\n    }\n\n    public enableBetButtons(enable: boolean): void {\n        super.enableBetButtons(enable);\n        if (this.fakeActiveBet) {\n            this.fakeActiveBet.interactive = enable;\n            this.fakeActiveBet.interactiveChildren = enable;\n            this.fakeActiveBet.state = ButtonStates.Normal;\n\n            this.betsModalLayer.visible = !enable;\n        }\n        if (enable) {\n            this.betButtonsContainer.interactive = true;\n        }\n    }\n\n    protected setBetButtonsLable(lable: string): void {\n        super.setBetButtonsLable(lable);\n        if (this.fakeActiveBet) {\n            const nextLable = Core.translator.translate(lable);\n            this.fakeActiveBet.text = nextLable;\n        }\n    }\n\n    public createBetButtons(container: ViewContainer): void {\n        this.createBetButtonsHitArea(container);\n        const bets: number[] = this.rootStore.uiStore.bets;\n        for (let i = 0; i < bets.length; i++) {\n            const betLength = this.componentConfiguration.betButtons.length;\n            const index = i % betLength;\n            const denomIndex = Math.floor(i / betLength);\n\n            const bet: BetButton = this.createBetButton('bet', i, bets, denomIndex, index);\n            this.betButtons.push(bet);\n            this.betButtonsContainer.addChild(bet);\n            if (bets[i] === this.rootStore.uiStore.SELECTED_BET.value) {\n                bet.selected = true;\n            }\n        }\n        this.createBetButtonsParts(container);\n        this.resizeBetButtonsFonts();\n    }\n\n    private animateBetBtnsExternally(direction: 'slideLeft' | 'slideRight' | 'none'): void {\n        this.slidArrowsClicked(direction);\n    }\n\n    protected createBetButton(name: string, i: number, bets: number[], denomIndex: number, index: number): BetButton {\n        const maxBetLimits =\n            this.rootStore.settings.settings.settings?.clientSettings?.maxBetLimits &&\n            Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS)\n                ? this.rootStore.settings.settings.settings.clientSettings.maxBetLimits[\n                      this.rootStore.settings.currency\n                  ]\n                : undefined;\n        return new BetButton({\n            name: name + (i + 1),\n            betPerLine: bets[i],\n            currency: this.rootStore.uiStore.currency,\n            units: this.rootStore.uiStore.units,\n            denomination: denomIndex,\n            lines: this.rootStore.uiStore.LINES.value,\n            factor: this.rootStore.settings.factor,\n            width: this.componentConfiguration.betButtons[index].get('betConfig').width,\n            height: this.componentConfiguration.betButtons[index].get('betConfig').height,\n            text: Core.translator.translate('PLAY'),\n            textures: this.getBetButtonsTextures(\n                this.componentConfiguration.betButtons[index].get('betConfig').textures,\n            ),\n            selectedTextures: this.getBetButtonsTextures(\n                this.componentConfiguration.betButtons[index].get('betConfig').selectedTextures,\n            ),\n            fakeMaskTexture: Core.assets.getAsset(\n                this.componentConfiguration.betButtons[index].get('betConfig').fakeMaskTexture,\n            )?.texture,\n            selected: false,\n            // betButtonStyles: this.configuration.betButtonStyles,\n            dynamicConfig: this.componentConfiguration.betButtons[index].get('betConfig'),\n            maxBet: this.rootStore.settings.maxBet,\n            maxBetBuyBonus: maxBetLimits,\n        });\n    }\n\n    public createBetsModalLayer(): void {\n        this.betsModalLayer = new Graphics();\n        this.betsModalLayer.beginFill(0x49de32);\n        this.betsModalLayer.drawRect(0, 0, 1, 1);\n        this.betsModalLayer.endFill();\n        this.betsModalLayer.alpha = 0;\n        this.betsModalLayer.interactive = this.isWaitingForResponse();\n        this.betsModalLayer.name = 'betsModalLayer';\n        this.moneyContainerGroup.addChild(this.betsModalLayer);\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/bet-buttons/src/egt/modes/one-denom/views/BetButtonsViewOneDenom.ts:207:9\",(this.betsModalLayer),\"pointerdown\"]), fromEvent(this.betsModalLayer, 'pointerdown'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(() => {\n                if (this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value > 0) {\n                    return;\n                }\n                this.rootStore.subjects.REELS_STOP_ALL.next();\n\n                if (this.rootStore.uiStore.SHOW_ALL_LINES.value) {\n                    this.rootStore.uiStore.SHOW_ALL_LINES.next(false);\n                }\n            });\n    }\n\n    public showFakeActiveBet(data: { index: number; visible: boolean }): void {\n        if (data.visible) {\n            this.fakeActiveBetPositionIndex = data.index;\n            if (!this.fakeActiveBet) {\n                const i = this.rootStore.uiStore.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value);\n                const betLength = this.componentConfiguration.betButtons.length;\n\n                this.fakeActiveBet = this.createBetButton(\n                    'fakeBet',\n                    i,\n                    this.rootStore.uiStore.bets,\n                    Math.floor(i / betLength),\n                    i % betLength,\n                );\n                this.fakeActiveBet.selected = true;\n                this.moneyContainerGroup.addChild(this.fakeActiveBet);\n\n                this.fakeActiveBet.CLICK.pipe(\n                    filter(\n                        (_x) =>\n                            !this.rootStore.subjects.KEY_DOWN.value &&\n                            this.rootStore.subjects.SHOW_JP_STATS.value.type === -1,\n                    ),\n                    takeUntil(this.DESTROY),\n                ).subscribe(() => {\n                    this.rootStore.subjects.FIRST_BET_CLICKED.next();\n                });\n            } else {\n                this.fakeActiveBet.betPerLine = this.rootStore.uiStore.SELECTED_BET.value;\n                this.fakeActiveBet.lines = this.rootStore.uiStore.LINES.value;\n            }\n            this.setOrientation(Core.ORIENTATION.value);\n        } else {\n            this.moneyContainerGroup.removeChild(this.fakeActiveBet);\n            // @ts-ignore\n            this.fakeActiveBet = null;\n        }\n    }\n\n    public showBetButtons(): void {\n        if (this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value) {\n            return;\n        }\n        this.buttonsHidden = false;\n        super.showBetButtons();\n        this.slideIfNotVisible(false);\n        this.updateVisibleButtons();\n        this.betsModalLayer.visible = true;\n        this.fakeBetButtonsMask.visible = true;\n    }\n\n    public hideBetButtons(): void {\n        this.buttonsHidden = true;\n        super.hideBetButtons();\n        this.updateVisibleButtons();\n        this.betsModalLayer.visible = false;\n        this.fakeBetButtonsMask.visible = false;\n    }\n\n    protected setOrientation(_orientation: IOrientation): void {\n        super.setOrientation(_orientation);\n        const betLength = this.componentConfiguration.betButtons.length;\n        const btnWidth = this.componentConfiguration.betButtons[0].get('betConfig').width;\n        const spacing =\n            this.componentConfiguration.betButtons[1].get('x') -\n            (this.componentConfiguration.betButtons[0].get('x') + btnWidth);\n\n        for (let i = 0; i < this.betButtons.length; i++) {\n            const denomIndex = Math.floor(i / betLength);\n            const index = i % betLength;\n\n            const visibleButtonsWidth =\n                this.componentConfiguration.betButtons[this.componentConfiguration.betButtons.length - 1].get('x') +\n                btnWidth -\n                this.componentConfiguration.betButtons[0].get('x');\n\n            this.betButtons[i].x =\n                this.componentConfiguration.betButtons[index].get('x') +\n                denomIndex * visibleButtonsWidth +\n                spacing * denomIndex;\n            this.betButtons[i].y = this.componentConfiguration.betButtons[index].get('y');\n            this.betButtons[i].updateConfig();\n        }\n\n        if (this.fakeActiveBet) {\n            this.fakeActiveBet.x = this.componentConfiguration.betButtons[this.fakeActiveBetPositionIndex].get('x');\n            this.fakeActiveBet.y = this.componentConfiguration.betButtons[this.fakeActiveBetPositionIndex].get('y');\n        }\n\n        this.betsModalLayer.x = this.componentConfiguration.fakeBetButtonsMask.x;\n        this.betsModalLayer.y = this.componentConfiguration.fakeBetButtonsMask.y;\n        this.betsModalLayer.width = this.fakeBetButtonsMask.width;\n        this.betsModalLayer.height = this.fakeBetButtonsMask.height;\n\n        if (this.betButtonsSlidingStart) {\n            const pendingSelected = this.betButtons.find((btn) => btn.selected);\n            if (\n                pendingSelected &&\n                pendingSelected.betPerLine !== this.rootStore.uiStore.SELECTED_BET.value &&\n                pendingSelected.enabled\n            ) {\n                this.rootStore.uiStore.SELECTED_BET.next(pendingSelected.betPerLine);\n\n                if (\n                    this.rootStore.uiStore.CURRENT_BET_LEVEL.value.betLevel !==\n                    this.rootStore.uiStore.SELECTED_BET.value\n                ) {\n                    this.rootStore.uiStore.CURRENT_BET_LEVEL.next({\n                        betLevel: this.rootStore.uiStore.SELECTED_BET.value,\n                        denomLevel: Core.SELECTED_DENOMINATION.value,\n                    });\n                }\n            }\n            this.betButtonsSlidingStart = false;\n        }\n        if (this.slidingAnimation) {\n            this.slidingAnimation.totalProgress(1);\n        }\n        this.killSlidingAnimation();\n        this.slideType = 'none';\n        if (!this.initialAnimationInProgress) {\n            this.xDown = null;\n        }\n        this.slideToCurrentSelectedIndex(false);\n    }\n\n    protected onStateChanged(): void {\n        super.onStateChanged();\n        this.betsModalLayer.interactive = this.isWaitingForResponse();\n    }\n\n    protected isWaitingForResponse(): boolean {\n        return (\n            this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_RESPONSE ||\n            this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_RESPONSE_IN_AUTOPLAY ||\n            this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_RESPONSE_IN_FREESPIN\n        );\n    }\n\n    protected createSlidBetButtonsEvents(): void {\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/bet-buttons/src/egt/modes/one-denom/views/BetButtonsViewOneDenom.ts:361:9\",(this.fakeBetButtonsMask),\"pointerup\"]), fromEvent(this.fakeBetButtonsMask, 'pointerup'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.handlePointerTap.bind(this));\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/bet-buttons/src/egt/modes/one-denom/views/BetButtonsViewOneDenom.ts:364:9\",(this.fakeBetButtonsMask),\"pointerdown\"]), fromEvent(this.fakeBetButtonsMask, 'pointerdown'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.handlePointerDown.bind(this));\n\n        this.handleTouchEndFn = this.handleTouchEnd.bind(this);\n\n        // List of all \"up\" and interaction events\n        const interactionEvents = [\n            // 'pointerup',    // added in BetButtonsView\n            'pointerupoutside',\n            'mouseup',\n            'touchend',\n            'blur', // When the window/tab loses focus\n            'visibilitychange', // When tab visibility changes (e.g., switching tabs)\n            'resize', // When window resizes\n            'beforeunload', // Before user closes the tab or navigates away\n        ];\n\n        interactionEvents.forEach((event) => {\n            window.addEventListener(event, this.handleTouchEndFn);\n        });\n\n        super.createSlidBetButtonsEvents();\n    }\n\n    protected handlePointerTap(): void {\n        if (!this.betButtonsSlidingStart && this.slidingAnimation?.paused()) {\n            this.fakeBetButtonsMask.interactive = false;\n            this.stopSlidingAnimation();\n        }\n    }\n\n    protected handlePointerDown(evt): void {\n        if (this.initialAnimationInProgress) {\n            return;\n        }\n        if (this.slidingAnimation) {\n            this.slidingAnimation.pause();\n            this.handleTouchStart(evt);\n        }\n    }\n\n    protected stopSlidingAnimation() {\n        if (this.slidingAnimation) {\n            this.killSlidingAnimation();\n            this.fakeBetButtonsMask.interactive = false;\n            this.xDown = null;\n\n            this.slideToCurrentSelectedIndex();\n        }\n    }\n\n    public switchBetButtons(_fromIndex: number, _toIndex: number) {\n        return;\n    }\n\n    protected slideToCurrentSelectedIndex(animation: boolean = true) {\n        if (this.visibleBetButtons.length === 0) {\n            return;\n        }\n\n        // when holding a bet button and rotate the array contains undefined objects\n        // restore all visible bet buttons\n        if (this.slideType === 'none' && this.visibleBetButtons.some((btn) => btn == undefined)) {\n            if (this.visibleBetButtons[0] == undefined) {\n                this.slideType = 'slideRight';\n            } else {\n                this.slideType = 'slideLeft';\n            }\n        }\n\n        // this.visibleBetButtons contains undefined obejcts;\n        // if slide if right get the first non-undefined object in the array\n        // if slide is left get the last non-undefined object in the array\n        const directionBtn =\n            this.slideType == 'slideRight'\n                ? this.visibleBetButtons.find((item) => item !== undefined)\n                : [...this.visibleBetButtons].reverse().find((item) => item !== undefined);\n        const targetIndex = this.betButtons.findIndex((button) => button.name == directionBtn?.name);\n\n        const buttonsToTarget = this.visibleBetButtons.length - 1;\n\n        let targetButton = this.betButtons[0];\n        if (this.slideType === 'slideRight' && targetIndex > 0) {\n            targetButton = this.betButtons[targetIndex];\n        } else if (this.slideType === 'slideLeft' && targetIndex < this.betButtons.length - 1) {\n            targetButton = this.betButtons[targetIndex - buttonsToTarget];\n        } else if (this.slideType === 'slideLeft') {\n            targetButton = this.betButtons[targetIndex - buttonsToTarget];\n        } else if (this.slideType === 'none') {\n            targetButton = this.visibleBetButtons[0];\n        }\n\n        this.slideToButton(targetButton, this.slideType == 'slideLeft', animation);\n    }\n\n    protected handleTouchStart(evt): void {\n        super.handleTouchStart(evt);\n\n        if (!this.slidingAnimation) {\n            this.initialVisibleSelectedIndex = this.findSelectedButtonIndex();\n        }\n\n        this.xDown = evt.data.global.x;\n\n        this.lastTouchX = this.xDown;\n        this.startTouchX = this.xDown;\n        this.startTouchTime = evt.data.originalEvent.timeStamp;\n    }\n\n    protected handleTouchMove(evt): void {\n        if (evt.data.pointerId !== this.pointerId || typeof this.xDown !== 'number' || this.feature.isInGiftSpins) {\n            this.xDown = null;\n            return;\n        }\n\n        const xUp: number = evt.data.global.x;\n        const xDiff: number = this.xDown - xUp;\n\n        if (\n            (xDiff > 5 || xDiff < -5) &&\n            (this.rootStore.uiStore.STATE.value === UIState.IDLE ||\n                this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT ||\n                this.rootStore.uiStore.STATE.value === UIState.SLIDING_BETS)\n        ) {\n            AnalyticsDispatcher.slideFeatureEvent(this.rootStore.uiStore.SELECTED_BET.value);\n            this.betButtonsSlidingStart = true;\n        }\n\n        if (!this.betButtonsSlidingStart) {\n            return;\n        }\n\n        this.isSlidingInitialized = true;\n        this.updateVisibleButtons();\n\n        if (\n            this.visibleBetButtons[this.initialVisibleSelectedIndex] &&\n            this.visibleBetButtons[this.initialVisibleSelectedIndex].enabled\n        ) {\n            if (!this.visibleBetButtons[this.initialVisibleSelectedIndex].selected) {\n                this.clearBetSelection();\n                this.visibleBetButtons[this.initialVisibleSelectedIndex].selected = true;\n                Core.sounds.play('sliderClick');\n            }\n        }\n        if (this.initialAnimationInProgress) {\n            this.betButtonsContainer.interactive = false;\n            this.enableBetButtons(false);\n        } else if (this.rootStore.uiStore.STATE.value !== UIState.DISABLED) {\n            this.saveCurrentUIState();\n            this.rootStore.uiStore.STATE.next(UIState.SLIDING_BETS);\n        }\n\n        this.checkCollect();\n\n        const currentX: number = evt.data.global.x;\n        if (\n            (currentX > this.lastTouchX && currentX <= this.startTouchX && Math.abs(currentX - this.lastTouchX) > 5) || // Direction changed to right\n            (currentX < this.lastTouchX && currentX >= this.startTouchX && Math.abs(currentX - this.lastTouchX) > 5) // Direction changed to left\n        ) {\n            // Reset the starting position and time when the sliding direction changes\n            this.xDown = currentX;\n            this.startTouchX = currentX;\n            this.startTouchTime = evt.data.originalEvent.timeStamp;\n        }\n        let speedMultiplier = 2.5;\n        if (\n            (this.visibleBetButtons.find((button) => button == this.betButtons[0]) && currentX - this.lastTouchX > 0) ||\n            (this.visibleBetButtons.find((button) => button == this.betButtons[this.betButtons.length - 1]) &&\n                currentX - this.lastTouchX < 0)\n        ) {\n            speedMultiplier = 0.5;\n        }\n        if (this.initialAnimationInProgress) {\n            speedMultiplier = 1;\n        }\n\n        const offset = (currentX - this.lastTouchX) * speedMultiplier;\n        this.betButtonsContainer.x += offset;\n        this.lastTouchX = currentX;\n    }\n\n    protected handleTouchEnd(evt, isFake: boolean = false): void {\n        if ((this.initialAnimationInProgress && isFake) || (!isFake && !this.betButtonsSlidingStart)) {\n            this.xDown = null;\n        }\n        if ((this.initialAnimationInProgress && !isFake) || !evt.isPrimary || !this.betButtonsSlidingStart) {\n            return;\n        }\n        this.xDown = null;\n\n        const swipeTime = evt.timeStamp - this.startTouchTime;\n        const swipeDistance = this.lastTouchX - this.startTouchX;\n        let swipeSpeed = swipeTime > 500 ? 1 : swipeTime > 300 ? 2 : swipeTime > 200 ? 4 : 10;\n        if (isFake) {\n            swipeSpeed = 1;\n        }\n\n        // if selected button is pressed\n        const selectedBtn = this.betButtons.find((button) => button.selected);\n        if (selectedBtn) {\n            selectedBtn.state = ButtonStates.Normal;\n        }\n\n        this.fakeBetButtonsMask.interactive = true;\n        this.betButtonsSlidingStart = false;\n        this.pointerId = -1;\n\n        const toLeft: boolean = swipeDistance < 0;\n        this.slideType = toLeft ? 'slideLeft' : 'slideRight';\n\n        const buttonWidth = this.betButtons[0].width / swipeSpeed;\n        this.buttonsToSlide = Math.trunc(swipeDistance / buttonWidth);\n        const firstVisibleIndex = parseInt(this.visibleBetButtons[0]?.name.replace('bet', ''), 10) - 1;\n        const lastVisibleIndex =\n            parseInt(this.visibleBetButtons[this.visibleBetButtons.length - 1]?.name.replace('bet', ''), 10) - 1;\n\n        const targetIndex = (firstVisibleIndex ?? lastVisibleIndex) - this.buttonsToSlide;\n        const targetButton = this.getCenterTargetButton(targetIndex);\n\n        if (swipeSpeed == 1) {\n            this.slideToCurrentSelectedIndex(!isFake);\n        } else {\n            this.slideToButton(targetButton, toLeft);\n        }\n    }\n\n    protected checkCollect(): void {\n        if (\n            (this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT ||\n                (this.rootStore.uiStore.STATE.value === UIState.SLIDING_BETS &&\n                    this.rootStore.domainStore.SERVER_STATE.value === ServerState.WIN)) &&\n            !this.feature.isInGiftSpins\n        ) {\n            this.rootStore.domainStore.collect();\n            this.rootStore.uiStore.COLLECT_CHANGED.next();\n        }\n    }\n\n    public slideIfNotVisible(animation: boolean = true, targetIndex?: number, preserveOrder: boolean = false): void {\n        if (this.slidingAnimation || this.isSlidingInitialized) {\n            return;\n        }\n\n        let prevIndex = this.rootStore.uiStore.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value);\n\n        if (targetIndex === undefined) {\n            targetIndex = this.rootStore.uiStore.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value);\n            prevIndex = this.rootStore.uiStore.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.prevValue);\n        }\n        const selectedBtn: BetButton = this.find('bet' + (targetIndex + 1));\n        const prevBtn: BetButton = this.find('bet' + (prevIndex + 1)) ?? selectedBtn;\n\n        if (!selectedBtn?.enabled) {\n            return;\n        }\n        let targetButton = this.getCenterTargetButton(targetIndex);\n        if (Core.isDesktopMode) {\n            // preserve the order as it is in the denomination popup view\n            const betPerDenomIndex = targetIndex % this.componentConfiguration.betButtons.length;\n            targetIndex = targetIndex - betPerDenomIndex;\n            targetButton = this.getTargetButton(targetIndex);\n        }\n        // else if (this.visibleBetButtons.indexOf(prevBtn) === this.visibleBetButtons.length - 1) {\n        //     targetIndex = targetIndex - (this.visibleBetButtons.length - 1);\n        // }\n\n        if (this.checkIfButtonIsInvisible(selectedBtn) || preserveOrder) {\n            this.saveCurrentUIState();\n            if (animation) {\n                this.rootStore.uiStore.STATE.next(UIState.SLIDING_BETS);\n            }\n            this.slideToButton(targetButton, selectedBtn.betPerLine < prevBtn.betPerLine, animation);\n            this.isSlidingInitialized = true;\n        } else {\n            this.clearBetSelection();\n            selectedBtn.selected = true;\n            if (animation) {\n                this.rootStore.uiStore.SELECTED_BET.next(selectedBtn.betPerLine);\n                Core.sounds.play('sliderClick');\n            }\n        }\n        if (!animation) {\n            this.isSlidingInitialized = false;\n        }\n        this.updateVisibleButtons();\n    }\n\n    protected slideToButton(button: BetButton, toLeft: boolean, animation: boolean = true): void {\n        // if (!button?.enabled) {\n        //     const enabledButton =\n        //         this.slideType == 'slideRight'\n        //             ? this.betButtons.find((item) => item.enabled == true)\n        //             : [...this.betButtons].reverse().find((item) => item.enabled == true);\n\n        //     if (enabledButton) {\n        //         button = enabledButton;\n        //     }\n        // }\n        if (!button) {\n            return;\n        }\n        const buttonX = button.position.x + this.betButtonsContainer.x + button.width / 2;\n        const firstButtonX = this.componentConfiguration.betButtons[0].get('x') + button.width / 2;\n        const distance = toLeft ? buttonX - firstButtonX : firstButtonX - buttonX;\n        const targetX = this.betButtonsContainer.x + (toLeft ? -distance : distance);\n\n        const onComplete = () => {\n            let selectedButton = this.visibleBetButtons[this.initialVisibleSelectedIndex];\n\n            if (!selectedButton.enabled) {\n                for (let i = this.initialVisibleSelectedIndex - 1; i >= 0; i--) {\n                    if (this.visibleBetButtons[i].enabled) {\n                        selectedButton = this.visibleBetButtons[i];\n                        break;\n                    }\n                }\n            }\n            if (!selectedButton.selected) {\n                this.UPDATE_SELECTED_BET.next(selectedButton.betPerLine);\n            }\n            this.rootStore.uiStore.SELECTED_BET.next(selectedButton.betPerLine);\n            this.killSlidingAnimation();\n            this.initialVisibleSelectedIndex = -1;\n            this.isSlidingInitialized = false;\n            this.updateVisibleButtons();\n            this.restoreState();\n\n            if (this.rootStore.uiStore.CURRENT_BET_LEVEL.value.betLevel !== this.rootStore.uiStore.SELECTED_BET.value) {\n                this.rootStore.uiStore.CURRENT_BET_LEVEL.next({\n                    betLevel: this.rootStore.uiStore.SELECTED_BET.value,\n                    denomLevel: Core.SELECTED_DENOMINATION.value,\n                });\n            }\n        };\n\n        if (animation) {\n            const speed = Math.max(Math.abs(this.buttonsToSlide) * 100, 1000);\n            const time = Math.max(distance / speed, 0.5);\n            this.slidingAnimation = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/bet-buttons/src/egt/modes/one-denom/views/BetButtonsViewOneDenom.ts:704:37\",null]), gsap.to(this.betButtonsContainer, {\n                x: targetX,\n                duration: time,\n                physics2D: {\n                    velocity: speed,\n                },\n                onUpdate: () => {\n                    this.updateVisibleButtons();\n                    const selectedButton = this.visibleBetButtons[this.initialVisibleSelectedIndex];\n                    if (selectedButton && this.slideToBet !== selectedButton.betPerLine && selectedButton.enabled) {\n                        this.slideToBet = selectedButton.betPerLine;\n                        this.UPDATE_SELECTED_BET.next(selectedButton.betPerLine);\n                        Core.sounds.play('sliderClick');\n                    }\n                },\n                onComplete: () => {\n                    onComplete();\n                },\n            }));\n        } else {\n            this.betButtonsContainer.x = targetX;\n            this.killSlidingAnimation();\n            this.initialVisibleSelectedIndex = -1;\n            this.isSlidingInitialized = false;\n            this.updateVisibleButtons();\n            if (this.rootStore.uiStore.STATE.value === UIState.SLIDING_BETS) {\n                this.restoreState();\n            }\n        }\n    }\n\n    protected updateVisibleButtons() {\n        const newButtons = Array(this.componentConfiguration.betButtons.length).fill(undefined);\n\n        const maskBounds = {\n            x: this.fakeBetButtonsMask.x,\n            width: this.fakeBetButtonsMask.width,\n        };\n\n        for (const betButton of this.betButtons) {\n            const buttonPosition = betButton.x + this.betButtonsContainer.x;\n            const buttonMiddleX = buttonPosition + betButton.width / 2;\n\n            let isVisible = this.checkIfButtonIsVisible(maskBounds, buttonMiddleX);\n            if (Core.isDesktopMode) {\n                const atTheLeft = this.checkIfButtonIsVisible(maskBounds, buttonPosition);\n                const atTheRight = this.checkIfButtonIsVisible(maskBounds, buttonPosition + betButton.width);\n                isVisible = atTheLeft && atTheRight;\n            }\n\n            if (!this.buttonsHidden) {\n                betButton.visible = isVisible || this.isSlidingInitialized;\n            }\n\n            if (isVisible) {\n                const index = this.componentConfiguration.betButtons.findIndex(\n                    (position) =>\n                        buttonMiddleX >= position.get('x') && buttonMiddleX <= position.get('x') + betButton.width,\n                );\n\n                if (index > -1) {\n                    newButtons[index] = betButton;\n                }\n            }\n        }\n        // Ensure visible array matches the config length and includes first/last buttons\n        if (newButtons.some((btn) => btn !== undefined)) {\n            this.visibleBetButtons = newButtons;\n            this.rootStore.uiStore.VISIBLE_BETS.next(\n                this.visibleBetButtons.map((btn) => (btn !== undefined ? btn.betPerLine : -1)),\n            );\n        }\n\n        this.showBetButtonParts();\n        this.slidBetButtonsHitArea.x = -this.betButtonsContainer.x;\n    }\n\n    protected showBetButtonParts(): void {\n        this.betBtnPieceLeft.visible = false;\n        this.betBtnPieceRight.visible = false;\n        if (Core.isDesktopMode) {\n            return;\n        }\n        if (\n            this.feature.isInGiftSpins ||\n            this.rootStore.domainStore.SERVER_STATE.value === ServerState.BONUS_IDLE ||\n            this.buttonsHidden\n        ) {\n            return;\n        }\n        const denominationLevel: number = this.getCurrentDenominationLevel();\n\n        if (\n            denominationLevel !== 1 ||\n            (this.betButtons[0] !== this.visibleBetButtons[0] && !this.isSlidingInitialized)\n        ) {\n            this.betBtnPieceLeft.visible = true;\n        }\n        if (\n            denominationLevel !== this.rootStore.uiStore.denominations.length ||\n            (this.betButtons[this.betButtons.length - 1] !==\n                this.visibleBetButtons[this.visibleBetButtons.length - 1] &&\n                !this.isSlidingInitialized)\n        ) {\n            this.betBtnPieceRight.visible = true;\n        }\n    }\n\n    protected slidArrowsClicked(slideType: 'slideLeft' | 'slideRight' | 'none'): void {\n        if (\n            (this.rootStore.domainStore.SERVER_STATE.value === ServerState.IDLE &&\n                this.rootStore.uiStore.STATE.value === UIState.IDLE) ||\n            (this.rootStore.domainStore.SERVER_STATE.value === ServerState.WIN &&\n                this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT)\n        ) {\n            AnalyticsDispatcher.slideFeatureEvent(this.rootStore.uiStore.SELECTED_BET.value);\n            this.slideType = slideType;\n\n            const isLeft = this.slideType == 'slideLeft';\n            this.initialVisibleSelectedIndex = this.findSelectedButtonIndex();\n            this.buttonsToSlide = 1;\n            const selectedIndex =\n                this.rootStore.uiStore.bets.indexOf(this.visibleBetButtons[0].betPerLine) + (isLeft ? -1 : 1);\n            const targetButton = this.getTargetButton(selectedIndex);\n\n            this.saveCurrentUIState();\n            this.rootStore.uiStore.STATE.next(UIState.SLIDING_BETS);\n            this.slideToButton(targetButton, isLeft, true);\n            this.isSlidingInitialized = true;\n        }\n    }\n\n    protected increaseBet(): void {\n        const bets: number[] = this.rootStore.uiStore.bets;\n        const betIndex = bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value);\n        // fix for kiosk mode where increasing bets when missing arrow leads to bug\n        if (betIndex < bets.length - 1 && this.betBtnPieceRight.visible) {\n            this.slidArrowsClicked('slideRight');\n        } else if (!this.betBtnPieceRight.visible) {\n            super.increaseBet();\n        }\n    }\n\n    protected decreaseBet(): void {\n        const bets: number[] = this.rootStore.uiStore.bets;\n        const betIndex = bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value);\n        // fix for kiosk mode where decreasing bets when missing arrow leads to bug\n        if (betIndex > 0 && this.betBtnPieceLeft.visible) {\n            this.slidArrowsClicked('slideLeft');\n        } else if (!this.betBtnPieceLeft.visible) {\n            super.decreaseBet();\n        }\n    }\n\n    /** \n     SLIDING DEMO ANIMATION IMPL \n    */\n    private createFakeInteractionEvent(type: string, x: number, y: number, sprite: Sprite): InteractionEvent {\n        return {\n            type,\n            data: {\n                global: { x: sprite.getLocalBounds().x + x, y: sprite.getGlobalPosition().y + y },\n                originalEvent: { timeStamp: Date.now() },\n            },\n            // biome-ignore lint/suspicious/noEmptyBlockStatements: <explanation>\n            stopPropagation: () => {},\n            target: sprite,\n            currentTarget: sprite,\n        } as unknown as InteractionEvent;\n    }\n\n    private createFakePointerEvent(type: string, x: number, y: number, sprite: Sprite): PointerEvent {\n        return new PointerEvent(type, {\n            bubbles: true,\n            cancelable: true,\n            clientX: sprite.getLocalBounds().x + x,\n            clientY: sprite.getGlobalPosition().y + y,\n            pointerId: 1,\n            pointerType: 'touch',\n            isPrimary: true,\n        });\n    }\n\n    private simulateFakeTouchEvents(sprite: Sprite): void {\n        if (!sprite.interactive) {\n            sprite.interactive = true;\n        }\n\n        const initialX = sprite.x;\n        let currentX = initialX;\n\n        const touchStartEvent = this.createFakeInteractionEvent('touchstart', initialX, 0, sprite);\n\n        // This animation serves only as a demonstration that sliding is possible.\n        // It does not trigger any bet changes, so other buttons remain enabled, and the UI state is not updated.\n        this.initialAnimationInProgress = true;\n        this.handleTouchStart(touchStartEvent);\n\n        const stepsToTheLeft = 50;\n        const stepsToTheRight = 60;\n        const isLeft = this.betBtnPieceRight.visible ? 1 : -1; // reverse movement if selected bet is one of the last visible bets\n\n        for (let i = 1; i <= stepsToTheLeft; i++) {\n            const moveTimeout = Timers.setTimeout(() => {\n                currentX = initialX + isLeft * -i;\n                const touchMoveEvent = this.createFakeInteractionEvent('touchmove', currentX, 0, sprite);\n                this.handleTouchMove(touchMoveEvent);\n            }, i * 10);\n            this.initialAnimationTimeouts.push(moveTimeout);\n        }\n\n        let timeout = 0;\n\n        for (let i = 1; i <= stepsToTheRight; i++) {\n            timeout = (stepsToTheLeft + i) * 10;\n            const moveBackTimeout = Timers.setTimeout(() => {\n                currentX = initialX + isLeft * (-stepsToTheLeft + i);\n                const touchMoveEvent = this.createFakeInteractionEvent('touchmove', currentX, 0, sprite);\n                this.handleTouchMove(touchMoveEvent);\n            }, timeout);\n            this.initialAnimationTimeouts.push(moveBackTimeout);\n        }\n\n        const touchEndEvent = this.createFakePointerEvent('touchend', currentX, 0, sprite);\n        const endTimeout = Timers.setTimeout(() => {\n            this.handleTouchEnd(touchEndEvent, true);\n            this.restoreState();\n            this.killInitialAnimationTimeouts();\n            this.initialAnimationInProgress = false;\n        }, timeout);\n        this.initialAnimationTimeouts.push(endTimeout);\n    }\n    /** \n     SLIDING DEMO ANIMATION IMPL END\n    */\n\n    private saveCurrentUIState() {\n        if (this.rootStore.uiStore.STATE.value !== UIState.SLIDING_BETS) {\n            this.currentState = this.rootStore.uiStore.STATE.value;\n        }\n    }\n\n    private restoreState() {\n        this.fakeBetButtonsMask.interactive = false;\n\n        if (this.initialAnimationInProgress) {\n            if (this.rootStore.uiStore.STATE.value == UIState.IDLE) {\n                this.betButtonsContainer.interactive = true;\n                this.enableBetButtons(true);\n            }\n            return;\n        }\n        const restoreState = this.currentState !== UIState.WAITING_FOR_COLLECT;\n        if (restoreState) {\n            this.rootStore.uiStore.STATE.next(this.currentState);\n        }\n    }\n\n    private checkIfButtonIsInvisible(button: BetButton): boolean {\n        const maskX = this.moneyContainerGroup.x + this.fakeBetButtonsMask.x;\n        const maskWidth = this.fakeBetButtonsMask.width;\n\n        const buttonPosition = button.x + this.betButtonsContainer.x + this.moneyContainerGroup.x;\n\n        const atTheLeft = this.checkIfButtonIsVisible({ x: maskX, width: maskWidth }, buttonPosition);\n        const atTheRight = this.checkIfButtonIsVisible({ x: maskX, width: maskWidth }, buttonPosition + button.width);\n\n        return !atTheLeft || !atTheRight;\n    }\n\n    private findSelectedButtonIndex(): number {\n        for (let i = 0; i <= this.visibleBetButtons.length - 1; i++) {\n            if (this.visibleBetButtons[i]?.selected) {\n                return i;\n            }\n        }\n        return 0;\n    }\n\n    private checkIfButtonIsVisible(object: { x: number; width: number }, x: number): boolean {\n        return x >= object.x && x <= object.x + object.width;\n    }\n\n    private getTargetButton(targetIndex: number): BetButton {\n        if (!targetIndex || targetIndex < 1) {\n            targetIndex = 0;\n        } else if (targetIndex >= this.betButtons.length - this.componentConfiguration.betButtons.length) {\n            targetIndex = this.betButtons.length - this.componentConfiguration.betButtons.length;\n        }\n\n        return this.find('bet' + (targetIndex + 1));\n    }\n\n    private getCenterTargetButton(targetIndex: number): BetButton {\n        if (!targetIndex || targetIndex < 2) {\n            targetIndex = 0;\n        } else if (targetIndex >= this.betButtons.length - 2) {\n            targetIndex = this.betButtons.length - this.componentConfiguration.betButtons.length;\n        } else {\n            targetIndex = targetIndex - 2;\n        }\n\n        return this.find('bet' + (targetIndex + 1));\n    }\n\n    private killSlidingAnimation() {\n        if (this.slidingAnimation) {\n            this.slidingAnimation.kill();\n            this.slidingAnimation = null;\n        }\n    }\n\n    private killInitialAnimationTimeouts() {\n        if (this.initialAnimationInProgress) {\n            if (this.initialAnimationTimeouts.length > 0) {\n                this.initialAnimationTimeouts.forEach((timeout) => {\n                    Timers.clearTimeout(timeout);\n                });\n                this.initialAnimationTimeouts = [];\n            }\n        }\n    }\n\n    private onMessage(response: any): void {\n        if (response.event == 'collect') {\n            if (this.currentState === UIState.WAITING_FOR_COLLECT) {\n                this.currentState = response.state;\n                // There is a race condition if collect comes after the tween is finished and the buttons stays locked\n                // @Tcveti please check, and better add state machine\n                if (!this.slidingAnimation) {\n                    this.restoreState();\n                }\n            }\n            if (\n                this.rootStore.uiStore.STATE.value === response.state &&\n                this.slidingAnimation &&\n                !this.initialAnimationInProgress\n            ) {\n                this.rootStore.uiStore.STATE.next(UIState.SLIDING_BETS);\n            }\n        }\n    }\n}\n","import {\n    AssetPriority,\n    BaseComponentConfiguration,\n    DefaultValue,\n    DynamicPositionObject,\n    PositionObject,\n} from '@egt/core';\nimport { AutoAlign, IBetButtonsConfig, TextAlign } from '@egt/ui-lib';\nimport { TextStyle } from 'pixi.js';\nimport {\n    IBetButton,\n    IFakeBetButtonsMask,\n    IMoneyContainerGroupAlpha,\n    IPiecePosition,\n    ISlidAnim,\n    ISlidBetButtonsHitArea,\n} from '../../../common/interfaces/InterfacesCommon';\nimport { IBetButtonsComponentConfigurationTurtle } from './IBetButtonsComponentConfigurationTurtle';\n\nexport default class BetButtonsComponentConfigurationTurtle extends BaseComponentConfiguration {}\n\nexport function BetButtonsComponentConfigurationFactoryTurtle(): any {\n    class BetButtonsComponentConfigurationTurtleInternalClass\n        extends BetButtonsComponentConfigurationTurtle\n        implements IBetButtonsComponentConfigurationTurtle\n    {\n        public assets = [\n            {\n                id: 'svgBet',\n                url: '../assets/components/slot/bet-buttons/turtle/ui-svg/standardButton.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 134, height: 96 },\n                    desktop: { width: 134, height: 96 },\n                },\n            },\n            {\n                id: 'svgBetPressed',\n                url: '../assets/components/slot/bet-buttons/turtle/ui-svg/standardButtonPressed.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 134, height: 96 },\n                    desktop: { width: 134, height: 96 },\n                },\n            },\n            {\n                id: 'svgActiveBet',\n                url: '../assets/components/slot/bet-buttons/turtle/ui-svg/standardButtonPressed.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 134, height: 96 },\n                    desktop: { width: 134, height: 96 },\n                },\n            },\n            {\n                id: 'svgActiveBetPressed',\n                url: '../assets/components/slot/bet-buttons/turtle/ui-svg/standardButtonPressed.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 134, height: 96 },\n                    desktop: { width: 134, height: 96 },\n                },\n            },\n            {\n                id: 'svgBetHover',\n                url: '../assets/components/slot/bet-buttons/turtle/ui-svg/standardButtonPressed.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 134, height: 96 },\n                    desktop: { width: 134, height: 96 },\n                },\n            },\n            {\n                id: 'svgActiveBetHover',\n                url: '../assets/components/slot/bet-buttons/turtle/ui-svg/standardButtonPressed.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 134, height: 96 },\n                    desktop: { width: 134, height: 96 },\n                },\n            },\n        ];\n\n        public betButtonsContainerGroup: PositionObject = new PositionObject({\n            landscape: { x: 150.5, y: 662, width: 1080, height: 104 },\n            portrait: { x: 0, y: 693, width: 765, height: 250 },\n            desktop: { x: 151, y: 641, width: 1360, height: 87 },\n        });\n        public moneyContainerGroup: PositionObject = new PositionObject({\n            landscape: { x: 150.5, y: 662, width: 1080, height: 104 },\n            portrait: { x: 0, y: 693, width: 765, height: 250 },\n            desktop: { x: 151, y: 641, width: 1360, height: 87 },\n        });\n\n        @DefaultValue<IMoneyContainerGroupAlpha>({\n            defaults: {\n                defaultAlpha: 1,\n                customAlpha: 0.5,\n            },\n        })\n        public moneyContainerGroupAlpha: DynamicPositionObject<IMoneyContainerGroupAlpha> & IMoneyContainerGroupAlpha;\n\n        @DefaultValue<IPiecePosition>({\n            defaults: {\n                x: 833,\n                y: 4,\n            },\n            portrait: {\n                x: 718.5,\n                y: 149,\n            },\n        })\n        public rightPiecePosition: DynamicPositionObject<IPiecePosition> & IPiecePosition;\n\n        @DefaultValue<IPiecePosition>({\n            defaults: {\n                x: 185,\n                y: 4,\n            },\n            portrait: {\n                x: 6.5,\n                y: 149,\n            },\n        })\n        public leftPiecePosition: DynamicPositionObject<IPiecePosition> & IPiecePosition;\n\n        @DefaultValue<ISlidAnim>({\n            defaults: {\n                leftSlidWidth: -605,\n                rightSlidWidth: 605,\n            },\n            portrait: {\n                leftSlidWidth: -655,\n                rightSlidWidth: 655,\n            },\n        })\n        public slideAnimation: DynamicPositionObject<ISlidAnim> & ISlidAnim;\n\n        @DefaultValue<IFakeBetButtonsMask>({\n            defaults: {\n                x: 200,\n                y: 0,\n                scaleX: 0.935,\n                scaleY: 1.5,\n            },\n            portrait: {\n                x: 23,\n                y: 146,\n                scaleX: 1.02,\n                scaleY: 1,\n            },\n            desktop: {\n                scaleY: 0.8,\n            },\n        })\n        public fakeBetButtonsMask: DynamicPositionObject<IFakeBetButtonsMask> & IFakeBetButtonsMask;\n\n        @DefaultValue<ISlidBetButtonsHitArea>({\n            defaults: {\n                x: 200,\n                y: 0,\n            },\n            portrait: {\n                x: 53,\n                y: 146,\n            },\n        })\n        public slidBetButtonsHitArea: DynamicPositionObject<ISlidBetButtonsHitArea> & ISlidBetButtonsHitArea;\n\n        public fakeBetButtonsPositionsLeft: PositionObject[] = [\n            new PositionObject({\n                landscape: { x: -378, y: 4 },\n                portrait: { x: -593, y: 149 },\n            }),\n            new PositionObject({\n                landscape: { x: -257, y: 4 },\n                portrait: { x: -462, y: 149 },\n            }),\n            new PositionObject({\n                landscape: { x: -136, y: 4 },\n                portrait: { x: -331, y: 149 },\n            }),\n            new PositionObject({\n                landscape: { x: -15, y: 4 },\n                portrait: { x: -200, y: 149 },\n            }),\n            new PositionObject({\n                landscape: { x: 106, y: 4 },\n                portrait: { x: -69, y: 149 },\n            }),\n        ];\n        public fakeBetButtonsPositionsRight: PositionObject[] = [\n            new PositionObject({\n                landscape: { x: 832, y: 4 },\n                portrait: { x: 717, y: 149 },\n            }),\n            new PositionObject({\n                landscape: { x: 953, y: 4 },\n                portrait: { x: 848, y: 149 },\n            }),\n            new PositionObject({\n                landscape: { x: 1074, y: 4 },\n                portrait: { x: 979, y: 149 },\n            }),\n            new PositionObject({\n                landscape: { x: 1195, y: 4 },\n                portrait: { x: 1110, y: 149 },\n            }),\n            new PositionObject({\n                landscape: { x: 1316, y: 4 },\n                portrait: { x: 1241, y: 149 },\n            }),\n        ];\n\n        @DefaultValue<IBetButtonsConfig>({\n            defaults: {\n                currency: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                        fontSize: 18,\n                        fill: '#C6C5C5',\n                        letterSpacing: 0.9,\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                        fontSize: 18,\n                        fill: '#FFD200',\n                        letterSpacing: 0.9,\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 3.5,\n                    bounds: { width: 106, height: 30 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                amount: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                        fontSize: 42,\n                        fill: '#C6C5C5', // '#FFFFFF'\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                        fontSize: 42,\n                        fill: '#FFFFFF',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 30,\n                    bounds: { width: 106, height: 34 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                label: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                        fontSize: 22,\n                        fill: '#FFD200',\n                        padding: 5,\n                        letterSpacing: 0.66,\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                        fontSize: 22,\n                        fill: '#FFD200',\n                        padding: 5,\n                        letterSpacing: 0.66,\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 61,\n                    bounds: { width: 106, height: 30 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                stamp: {\n                    hasStamp: false,\n                    x: 0,\n                    y: 0,\n                    width: 0,\n                    height: 0,\n                    alpha: 0,\n                    texture: { source: '', name: '' },\n                },\n                textures: ['svgBet', 'svgBetPressed', 'svgBet', 'svgBet'],\n                selectedTextures: ['svgActiveBet', 'svgActiveBetPressed', 'svgActiveBet', 'svgActiveBet'],\n                fakeMaskTexture: 'maxBet',\n                width: 120,\n                height: 96,\n            },\n            desktop: {\n                currency: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                        fontSize: 15,\n                        fill: '#C6C5C5', // '#FFD200'\n                        letterSpacing: 0.75,\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                        fontSize: 15,\n                        fill: '#FFD200',\n                        letterSpacing: 0.75,\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 3,\n                    bounds: { width: 84, height: 20 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                amount: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                        fontSize: 35,\n                        fill: '#C6C5C5', // '#FFFFFF'\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                        fontSize: 35,\n                        fill: '#FFFFFF',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 27.5,\n                    bounds: { width: 84, height: 20 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                label: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                        fontSize: 16,\n                        fill: '#FFD200',\n                        letterSpacing: 1.12,\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                        fontSize: 16,\n                        fill: '#FFD200',\n                        letterSpacing: 1.12,\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 54,\n                    bounds: { width: 78, height: 17 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                textures: ['svgBet', 'svgBetPressed', 'svgBetHover', 'svgBet'],\n                selectedTextures: ['svgActiveBet', 'svgActiveBetPressed', 'svgActiveBetHover', 'svgActiveBet'],\n                width: 94,\n                height: 75,\n            },\n        })\n        public betButtonsConfigs: DynamicPositionObject<IBetButtonsConfig> & IBetButtonsConfig;\n\n        public betButtons: Array<DynamicPositionObject<IBetButton>> = [\n            new DynamicPositionObject<IBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs, x: 0, y: 0 },\n                landscape: { x: 227, y: 4 },\n                portrait: { x: 58.5, y: 149 },\n                desktop: { x: 282, y: 6 },\n            }),\n            new DynamicPositionObject<IBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs, x: 0, y: 0 },\n                landscape: { x: 348, y: 4 },\n                portrait: { x: 190.5, y: 149 },\n                desktop: { x: 382, y: 6 },\n            }),\n            new DynamicPositionObject<IBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs, x: 0, y: 0 },\n                landscape: { x: 469, y: 4 },\n                portrait: { x: 322.5, y: 149 },\n                desktop: { x: 482, y: 6 },\n            }),\n            new DynamicPositionObject<IBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs, x: 0, y: 0 },\n                landscape: { x: 590, y: 4 },\n                portrait: { x: 454.5, y: 149 },\n                desktop: { x: 582, y: 6 },\n            }),\n            new DynamicPositionObject<IBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs, x: 0, y: 0 },\n                landscape: { x: 711, y: 4 },\n                portrait: { x: 586.5, y: 149 },\n                desktop: { x: 682, y: 6 },\n            }),\n        ];\n    }\n    return BetButtonsComponentConfigurationTurtleInternalClass;\n}\n","import Core, { BaseController, FeatureFlags, Timers } from '@egt/core';\nimport {\n    FeatureController,\n    Features,\n    ISlotConfiguration,\n    InitialSettings,\n    RootStore,\n    ServerState,\n    UIState,\n} from '@egt/slot';\nimport { BetButton } from '@egt/ui-lib';\nimport { filter, take, takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport BetButtonsViewTurtle from '../views/BetButtonsViewTurtle';\nimport { fromEvent, merge } from 'rxjs';\n\n@injectable()\nexport default class BetButtonsControllerTurtle extends BaseController {\n    public ready: () => Promise<void>;\n\n    private inactivityTimer;\n    private inactivityTimeout: number = 3000;\n\n    constructor(\n        @inject('BetButtonsView') protected view: BetButtonsViewTurtle,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('FeatureController') protected featureController: FeatureController,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('InitialSettings') protected initialSettings: InitialSettings,\n    ) {\n        super(view);\n\n        this.rootStore.subjects.DENOMINATIONS_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onDenominationsChanged.bind(this),\n        );\n        this.rootStore.subjects.CHANGE_SELECTED_BET_BTN_EXTERNALLY.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.changeBetExternally.bind(this),\n        );\n\n        this.attachEventListeners();\n        this.selectBet('bet' + (this.rootStore.uiStore.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value) + 1));\n    }\n\n    public async onGameStarted(): Promise<void> {\n        const interactionEvents = ['click', 'touchstart', 'mousemove', 'keydown'];\n        merge(...interactionEvents.map((event) => fromEvent(window, event)))\n            .pipe(take(2))\n            .subscribe(() => {\n                this.clearInactivityTimer();\n            });\n\n        this.inactivityTimer = Timers.setTimeout(() => {\n            this.view.onGameLoaded();\n        }, this.inactivityTimeout);\n    }\n\n    public onAfterInitialRender(): void {\n        const hasDefaultMinBetRestriction = Core.flags.isActive(FeatureFlags.USE_DEFAULT_BET_ON_LOAD);\n        const isIdleState = this.initialSettings.state === ServerState.IDLE;\n        if (hasDefaultMinBetRestriction && isIdleState) {\n            Core.SELECTED_DENOMINATION.next(this.initialSettings?.settings?.settings?.denomination);\n\n            this.rootStore.uiStore.SELECTED_BET.next(this.initialSettings?.settings?.settings?.bet);\n            this.rootStore.subjects.CHANGE_SELECTED_BET_BTN_EXTERNALLY.next({\n                betVal: this.rootStore.uiStore.SELECTED_BET.value,\n                changedFromPopUp: false,\n            });\n        }\n        this.rootStore.uiStore.CURRENT_BET_LEVEL.next({\n            betLevel: this.rootStore.uiStore.SELECTED_BET.value,\n            denomLevel: Core.SELECTED_DENOMINATION.value,\n        });\n    }\n\n    protected onDenominationsChanged(): void {\n        this.view.onDenominationsChanged();\n        if (!this.view.oneDenomView) {\n            this.addBetButtonsEventListeners();\n        }\n    }\n\n    protected attachEventListeners(): void {\n        this.addBetButtonsEventListeners();\n        this.view.UPDATE_SELECTED_BET.pipe(takeUntil(this.DESTROY)).subscribe(this.selectWhenSliding.bind(this));\n\n        this.rootStore.uiStore.SHOW_HIDE_BET_BUTTONS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.showHideBetButtons.bind(this),\n        );\n\n        this.rootStore.subjects.KEY_UP.pipe(takeUntil(this.DESTROY)).subscribe(this.onKeyReleased.bind(this));\n        this.rootStore.subjects.SWITCH_BET_BUTTONS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.switchBetButtons.bind(this),\n        );\n\n        this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onExtendedMultipleBuyBonusActivated.bind(this),\n        );\n    }\n\n    private addBetButtonsEventListeners(): void {\n        this.view.betButtons.forEach((_bet, index) => {\n            this.view\n                .find('bet' + (index + 1))\n                .CLICK.pipe(\n                    filter(\n                        (_x) =>\n                            !this.rootStore.subjects.KEY_DOWN.value &&\n                            this.rootStore.subjects.SHOW_JP_STATS.value.type === -1,\n                    ),\n                    takeUntil(this.DESTROY),\n                )\n                .subscribe(this.onSelectedBetChanged.bind(this, 'bet' + (index + 1)));\n        });\n    }\n\n    protected onExtendedMultipleBuyBonusActivated(value: boolean): void {\n        if (\n            this.rootStore.settings.haveGameMode('DOUBLE_CHANCE') &&\n            this.rootStore.settings.factor === this.rootStore.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE')\n        ) {\n            value = false;\n        }\n        for (const betButton of this.view.betButtons) {\n            betButton.buyBonusActivated = value;\n        }\n        // Timers.setTimeout(()=>{\n        this.view.resizeBetButtonsFonts();\n        // },1000);\n    }\n\n    protected selectWhenSliding(e): void {\n        const betButton = 'bet' + (this.rootStore.uiStore.bets.indexOf(e) + 1);\n        const button: BetButton = this.view.find(betButton);\n        if (!button) {\n            return;\n        }\n        this.view.slideIfNotVisible(false);\n        this.view.clearBetSelection();\n        button.selected = true;\n    }\n\n    // protected selectFromSettings(): void {\n    //     this.selectBet(\n    //         'bet' + (this.rootStore.uiStore.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value) + 1),\n    //         true,\n    //     );\n    // }\n    protected changeBetExternally(value: any): void {\n        const buttonValue = 'bet' + (this.rootStore.uiStore.bets.indexOf(value.betVal) + 1);\n        this.selectBet(buttonValue, value.changedFromPopUp);\n    }\n\n    protected selectBet(betButton: string, changedFromPopUp: boolean = false): void {\n        const button: BetButton = this.view.find(betButton);\n        if (!button) {\n            return;\n        }\n        this.rootStore.uiStore.SELECTED_BET.next(button.betPerLine);\n        this.view.slideIfNotVisible(false, undefined, changedFromPopUp);\n        this.view.clearBetSelection();\n        button.selected = true;\n    }\n\n    protected onKeyReleased(e: KeyboardEvent): void {\n        if (\n            e &&\n            this.rootStore.uiStore.SHOW_SETTINGS.value &&\n            ['ArrowDown', 'KeyC', 'KeyV', 'KeyB', 'KeyN', 'KeyM'].indexOf(e.code) > -1\n        ) {\n            return;\n        }\n        if (e === null || Core.UI_BLOCKER.value) {\n            return;\n        }\n        const currentUIState = this.rootStore.uiStore.STATE.value;\n\n        if ((e.code !== undefined && e.code === 'KeyC') || (e.keyCode !== undefined && e.keyCode === 67)) {\n            this.reactBasedOnState(currentUIState, 1);\n        }\n        if ((e.code !== undefined && e.code === 'KeyV') || (e.keyCode !== undefined && e.keyCode === 86)) {\n            this.reactBasedOnState(currentUIState, 2);\n        }\n        if ((e.code !== undefined && e.code === 'KeyB') || (e.keyCode !== undefined && e.keyCode === 66)) {\n            this.reactBasedOnState(currentUIState, 3);\n        }\n        if ((e.code !== undefined && e.code === 'KeyN') || (e.keyCode !== undefined && e.keyCode === 78)) {\n            this.reactBasedOnState(currentUIState, 4);\n        }\n        if ((e.code !== undefined && e.code === 'KeyM') || (e.keyCode !== undefined && e.keyCode === 77)) {\n            this.reactBasedOnState(currentUIState, 5);\n        }\n    }\n\n    protected reactBasedOnState(state: string, buttonValue: number): void {\n        let but = this.view.betButtons.filter((x) => x.name === 'bet' + buttonValue)[0];\n        if (this.view.oneDenomView) {\n            but = this.view.visibleBetButtons[buttonValue - 1];\n        }\n        if (!but || but.enabled === false || but.interactive === false) {\n            return;\n        }\n        switch (state) {\n            case UIState.IDLE:\n            case UIState.WAITING_FOR_COLLECT:\n            case UIState.BONUS_IDLE:\n                this.onBetButtonKeyPressed(but.name);\n\n                break;\n        }\n    }\n    protected onBetButtonKeyPressed(butName: string): void {\n        if (\n            this.rootStore.domainStore.SPIN_MODE.value !== Features.MANUAL_SPIN ||\n            Core.UI_BLOCKER.value ||\n            this.rootStore.uiStore.STATE.value === UIState.COLLECT_BEFORE_IDLE\n        ) {\n            return;\n        }\n        if (this.rootStore.subjects.TAB_OPENED.value) {\n            this.rootStore.subjects.CLOSE_SETTINGS_POPUP.next();\n            this.rootStore.subjects.RESET_AUTOPLAY_RESTRICTIONS.next();\n            return;\n        }\n        this.view.find(butName).CLICK.next();\n    }\n\n    protected onSelectedBetChanged(betButton: string): void {\n        if (!this.featureController.isInGiftSpins) {\n            this.selectBet(betButton);\n            this.rootStore.uiStore.CLEAR_BANG_UP.next();\n            if (this.rootStore.uiStore.CURRENT_BET_LEVEL.value.betLevel !== this.view.find(betButton).betPerLine) {\n                this.rootStore.uiStore.CURRENT_BET_LEVEL.next({\n                    betLevel: this.rootStore.uiStore.SELECTED_BET.value,\n                    denomLevel: Core.SELECTED_DENOMINATION.value,\n                });\n            }\n            this.rootStore.subjects.START_MANUAL_SPIN.next();\n        }\n        if (this.view.betButtons[0].name === betButton) {\n            this.rootStore.subjects.FIRST_BET_CLICKED.next();\n        }\n    }\n\n    protected switchBetButtons(event: { fromIndex: number; toIndex: number }): any {\n        if (event.fromIndex === event.toIndex) {\n            return;\n        }\n        this.view.switchBetButtons(event.fromIndex, event.toIndex);\n    }\n\n    private showHideBetButtons(show: boolean): void {\n        if (show) {\n            this.view.showBetButtons();\n        } else {\n            this.view.hideBetButtons();\n        }\n    }\n\n    private clearInactivityTimer(): void {\n        if (this.inactivityTimer) {\n            Timers.clearTimeout(this.inactivityTimer);\n            this.inactivityTimer = null;\n        }\n    }\n}\n","import { BuyBonusModes } from '@egt/buy-bonus';\nimport Core, { AnalyticsDispatcher, IOrientation, Timers } from '@egt/core';\nimport {\n    FeatureController,\n    ISlotConfiguration,\n    InitialSettings,\n    RootStore,\n    ServerState,\n    SlotComponents,\n    UIState,\n} from '@egt/slot';\nimport { BetButton, ButtonStates, ViewContainer } from '@egt/ui-lib';\nimport UIViewTurtle from 'components/slot/ui-view/src/egt/modes/turtle/views/UIViewTurtle';\nimport { gsap } from 'gsap';\nimport { Graphics, InteractionEvent, Sprite } from 'pixi.js';\nimport { fromEvent } from 'rxjs';\nimport { filter, takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport BetButtonsViewDefault from '../../default/views/BetButtonsViewDefault';\nimport { IBetButtonsComponentConfigurationTurtle } from '../configuration/IBetButtonsComponentConfigurationTurtle';\n\n// TO DO refactor this class to extends common view not view from Default mode\n// default mode view should be refactored to use this new common view\n@injectable()\nexport default class BetButtonsViewTurtle extends BetButtonsViewDefault {\n    private buttonsHidden: boolean;\n\n    private isSlidingInitialized;\n    private startTouchX;\n    private lastTouchX;\n    private startTouchTime;\n    private slidingAnimation;\n    private buttonsToSlide;\n    private slideToBet: number;\n\n    protected betsModalLayer: Graphics;\n\n    private initialVisibleSelectedIndex: number = -1;\n\n    // sliding demonstration props\n    private initialAnimationTimeouts: any[] = [];\n    private initialAnimationInProgress: boolean = false;\n\n    private fakeActiveBet: BetButton;\n    private fakeActiveBetPositionIndex: number;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected configuration: ISlotConfiguration,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('FeatureController') protected feature: FeatureController,\n        @inject('BetButtonsComponentConfiguration')\n        protected componentConfiguration: IBetButtonsComponentConfigurationTurtle,\n        @inject('UIView') protected uiView: UIViewTurtle,\n    ) {\n        super(rootStore, configuration, settings, feature, componentConfiguration);\n        if (!this.isOneDenom()) {\n            return;\n        }\n\n        this.updateVisibleButtons();\n        this.slideIfNotVisible(false);\n\n        this.rootStore.uiStore.SHOW_HIDE_EXACT_BET_BUTTON.pipe(takeUntil(this.DESTROY)).subscribe(\n            ({ index, visible }) => {\n                this.betButtons[index].visible = false;\n                this.fakeBetButtonsMask.visible = visible;\n            },\n        );\n\n        this.rootStore.uiStore.SHOW_FAKE_ACTIVE_BET.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.showFakeActiveBet.bind(this),\n        );\n        this.rootStore.uiStore.ANIMATE_BET_BTNS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.animateBetBtnsExternally.bind(this),\n        );\n        this.rootStore.subjects;\n        Core.ON_SERVER_MESSAGE.pipe(takeUntil(this.DESTROY)).subscribe(this.onMessage.bind(this));\n    }\n\n    public onGameLoaded() {\n        if (!this.isOneDenom()) {\n            return;\n        }\n        if (\n            this.rootStore.domainStore.SERVER_STATE.value === ServerState.IDLE &&\n            this.rootStore.uiStore.STATE.value === UIState.IDLE &&\n            !Core.isDesktopMode\n        ) {\n            this.simulateFakeTouchEvents(this.betButtonsContainer);\n        }\n    }\n\n    public onDenominationsChanged() {\n        if (!this.isOneDenom()) {\n            super.onDenominationsChanged();\n            return;\n        }\n        return;\n    }\n\n    public initialRender(): void {\n        if (!this.isOneDenom()) {\n            super.initialRender();\n            return;\n        }\n\n        this.saveCurrentUIState();\n        this.oneDenomView = this.rootStore.uiStore.bets.length > this.componentConfiguration.betButtons.length;\n\n        super.initialRender();\n        this.createBetsModalLayer();\n        this.createSlidBetButtonsEvents();\n\n        if (this.fakeBetButtonsMask) {\n            this.moneyContainerGroup.addChild(this.fakeBetButtonsMask);\n            this.betButtonsContainer.mask = this.fakeBetButtonsMask;\n        }\n    }\n\n    public destroy(): void {\n        super.destroy();\n        this.killSlidingAnimation();\n        this.killInitialAnimationTimeouts();\n        if (this.fakeActiveBet) {\n            this.fakeActiveBet.destroy();\n            // @ts-ignore\n            this.fakeActiveBet = null;\n        }\n    }\n\n    public enableBetButtons(enable: boolean): void {\n        super.enableBetButtons(enable);\n        if (this.fakeActiveBet) {\n            this.fakeActiveBet.interactive = enable;\n            this.fakeActiveBet.interactiveChildren = enable;\n            this.fakeActiveBet.state = ButtonStates.Normal;\n\n            this.betsModalLayer.visible = !enable;\n        }\n        if (enable) {\n            this.betButtonsContainer.interactive = true;\n        }\n    }\n\n    protected setBetButtonsLable(lable: string): void {\n        super.setBetButtonsLable(lable);\n        if (this.fakeActiveBet) {\n            const nextLable = Core.translator.translate(lable);\n            this.fakeActiveBet.text = nextLable;\n        }\n    }\n\n    public createBetButtons(container: ViewContainer): void {\n        if (!this.isOneDenom()) {\n            super.createBetButtons(container);\n            return;\n        }\n\n        this.createBetButtonsHitArea(container);\n        const bets: number[] = this.rootStore.uiStore.bets;\n        for (let i = 0; i < bets.length; i++) {\n            const betLength = this.componentConfiguration.betButtons.length;\n            const index = i % betLength;\n            const denomIndex = Math.floor(i / betLength);\n\n            const bet: BetButton = this.createBetButton('bet', i, bets, denomIndex, index);\n            this.betButtons.push(bet);\n            this.betButtonsContainer.addChild(bet);\n            if (bets[i] === this.rootStore.uiStore.SELECTED_BET.value) {\n                bet.selected = true;\n            }\n        }\n        this.createBetButtonsParts(container);\n        this.resizeBetButtonsFonts();\n    }\n\n    private animateBetBtnsExternally(direction: 'slideLeft' | 'slideRight' | 'none'): void {\n        this.slidArrowsClicked(direction);\n    }\n\n    protected createBetButton(name: string, i: number, bets: number[], denomIndex: number, index: number): BetButton {\n        const maxBetLimits =\n            this.rootStore.settings.settings.settings?.clientSettings?.maxBetLimits &&\n            Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS)\n                ? this.rootStore.settings.settings.settings.clientSettings.maxBetLimits[\n                      this.rootStore.settings.currency\n                  ]\n                : undefined;\n\n        const isMultiFactor =\n            this.rootStore.settings.numberOfLinesPerDenomination &&\n            this.rootStore.settings.numberOfLinesPerDenomination.length;\n\n        const factor = isMultiFactor\n            ? this.rootStore.settings.numberOfLinesPerDenomination![\n                  this.rootStore.settings.denominations.indexOf(denomIndex)\n              ][1]\n            : this.rootStore.settings.factor;\n        return new BetButton({\n            name: name + (i + 1),\n            betPerLine: bets[i],\n            currency: this.rootStore.uiStore.currency,\n            units: this.rootStore.uiStore.units,\n            denomination: denomIndex,\n            lines: this.rootStore.uiStore.LINES.value,\n            factor,\n            width: this.componentConfiguration.betButtons[index].get('betConfig').width,\n            height: this.componentConfiguration.betButtons[index].get('betConfig').height,\n            text: Core.translator.translate('PLAY'),\n            textures: this.getBetButtonsTextures(\n                this.componentConfiguration.betButtons[index].get('betConfig').textures,\n            ),\n            selectedTextures: this.getBetButtonsTextures(\n                this.componentConfiguration.betButtons[index].get('betConfig').selectedTextures,\n            ),\n            fakeMaskTexture: Core.assets.getAsset(\n                this.componentConfiguration.betButtons[index].get('betConfig').fakeMaskTexture,\n            )?.texture,\n            selected: false,\n            // betButtonStyles: this.configuration.betButtonStyles,\n            dynamicConfig: this.componentConfiguration.betButtons[index].get('betConfig'),\n            maxBet: this.rootStore.settings.maxBet,\n            maxBetBuyBonus: maxBetLimits,\n        });\n    }\n\n    public createBetsModalLayer(): void {\n        this.betsModalLayer = new Graphics();\n        this.betsModalLayer.beginFill(0x49de32);\n        this.betsModalLayer.drawRect(0, 0, 1, 1);\n        this.betsModalLayer.endFill();\n        this.betsModalLayer.alpha = 0;\n        this.betsModalLayer.interactive = this.isWaitingForResponse();\n        this.betsModalLayer.name = 'betsModalLayer';\n        this.moneyContainerGroup.addChild(this.betsModalLayer);\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/bet-buttons/src/egt/modes/turtle/views/BetButtonsViewTurtle.ts:238:9\",(this.betsModalLayer),\"pointerdown\"]), fromEvent(this.betsModalLayer, 'pointerdown'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(() => {\n                if (this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value > 0) {\n                    return;\n                }\n                this.rootStore.subjects.REELS_STOP_ALL.next();\n\n                if (this.rootStore.uiStore.SHOW_ALL_LINES.value) {\n                    this.rootStore.uiStore.SHOW_ALL_LINES.next(false);\n                }\n            });\n    }\n\n    public showFakeActiveBet(data: { index: number; visible: boolean }): void {\n        if (data.visible) {\n            this.fakeActiveBetPositionIndex = data.index;\n            if (!this.fakeActiveBet) {\n                const i = this.rootStore.uiStore.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value);\n                const betLength = this.componentConfiguration.betButtons.length;\n\n                this.fakeActiveBet = this.createBetButton(\n                    'fakeBet',\n                    i,\n                    this.rootStore.uiStore.bets,\n                    Math.floor(i / betLength),\n                    i % betLength,\n                );\n                this.fakeActiveBet.selected = true;\n                this.moneyContainerGroup.addChild(this.fakeActiveBet);\n\n                this.fakeActiveBet.CLICK.pipe(\n                    filter(\n                        (_x) =>\n                            !this.rootStore.subjects.KEY_DOWN.value &&\n                            this.rootStore.subjects.SHOW_JP_STATS.value.type === -1,\n                    ),\n                    takeUntil(this.DESTROY),\n                ).subscribe(() => {\n                    this.rootStore.subjects.FIRST_BET_CLICKED.next();\n                });\n            } else {\n                this.fakeActiveBet.betPerLine = this.rootStore.uiStore.SELECTED_BET.value;\n                this.fakeActiveBet.lines = this.rootStore.uiStore.LINES.value;\n            }\n            this.setOrientation(Core.ORIENTATION.value);\n        } else {\n            this.moneyContainerGroup.removeChild(this.fakeActiveBet);\n            // @ts-ignore\n            this.fakeActiveBet = null;\n        }\n    }\n\n    public showBetButtons(): void {\n        if (!this.isOneDenom()) {\n            super.showBetButtons();\n            return;\n        }\n\n        if (this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value) {\n            return;\n        }\n        this.buttonsHidden = false;\n        super.showBetButtons();\n        this.slideIfNotVisible(false);\n        this.updateVisibleButtons();\n        if (this.betsModalLayer) {\n            this.betsModalLayer.visible = true;\n        }\n        if (this.fakeBetButtonsMask) {\n            this.fakeBetButtonsMask.visible = true;\n        }\n    }\n\n    public hideBetButtons(): void {\n        if (!this.isOneDenom()) {\n            super.hideBetButtons();\n            return;\n        }\n\n        this.buttonsHidden = true;\n        super.hideBetButtons();\n        this.updateVisibleButtons();\n        if (this.betsModalLayer) {\n            this.betsModalLayer.visible = false;\n        }\n        if (this.fakeBetButtonsMask) {\n            this.fakeBetButtonsMask.visible = false;\n        }\n    }\n\n    protected setOrientation(_orientation: IOrientation): void {\n        if (!this.isOneDenom()) {\n            super.setOrientation(_orientation);\n            return;\n        }\n\n        super.setOrientation(_orientation);\n        const betLength = this.componentConfiguration.betButtons.length;\n        const btnWidth = this.componentConfiguration.betButtons[0].get('betConfig').width;\n        const spacing =\n            this.componentConfiguration.betButtons[1].get('x') -\n            (this.componentConfiguration.betButtons[0].get('x') + btnWidth);\n\n        for (let i = 0; i < this.betButtons.length; i++) {\n            const denomIndex = Math.floor(i / betLength);\n            const index = i % betLength;\n\n            const visibleButtonsWidth =\n                this.componentConfiguration.betButtons[this.componentConfiguration.betButtons.length - 1].get('x') +\n                btnWidth -\n                this.componentConfiguration.betButtons[0].get('x');\n\n            this.betButtons[i].x =\n                this.componentConfiguration.betButtons[index].get('x') +\n                denomIndex * visibleButtonsWidth +\n                spacing * denomIndex;\n            this.betButtons[i].y = this.componentConfiguration.betButtons[index].get('y');\n            this.betButtons[i].updateConfig();\n        }\n\n        if (this.fakeActiveBet) {\n            this.fakeActiveBet.x = this.componentConfiguration.betButtons[this.fakeActiveBetPositionIndex].get('x');\n            this.fakeActiveBet.y = this.componentConfiguration.betButtons[this.fakeActiveBetPositionIndex].get('y');\n        }\n\n        if (this.betsModalLayer && this.fakeBetButtonsMask) {\n            this.betsModalLayer.x = this.componentConfiguration.fakeBetButtonsMask.x;\n            this.betsModalLayer.y = this.componentConfiguration.fakeBetButtonsMask.y;\n            this.betsModalLayer.width = this.fakeBetButtonsMask.width;\n            this.betsModalLayer.height = this.fakeBetButtonsMask.height;\n        }\n\n        if (this.betButtonsSlidingStart) {\n            const pendingSelected = this.betButtons.find((btn) => btn.selected);\n            if (pendingSelected && pendingSelected.betPerLine !== this.rootStore.uiStore.SELECTED_BET.value) {\n                this.rootStore.uiStore.SELECTED_BET.next(pendingSelected.betPerLine);\n\n                if (\n                    this.rootStore.uiStore.CURRENT_BET_LEVEL.value.betLevel !==\n                    this.rootStore.uiStore.SELECTED_BET.value\n                ) {\n                    this.rootStore.uiStore.CURRENT_BET_LEVEL.next({\n                        betLevel: this.rootStore.uiStore.SELECTED_BET.value,\n                        denomLevel: Core.SELECTED_DENOMINATION.value,\n                    });\n                }\n            }\n            this.betButtonsSlidingStart = false;\n        }\n        if (this.slidingAnimation) {\n            this.slidingAnimation.totalProgress(1);\n        }\n        this.killSlidingAnimation();\n        this.slideType = 'none';\n        if (!this.initialAnimationInProgress) {\n            this.xDown = null;\n        }\n        this.slideToCurrentSelectedIndex(false);\n    }\n\n    protected onStateChanged(): void {\n        if (!this.isOneDenom()) {\n            super.onStateChanged();\n            return;\n        }\n\n        super.onStateChanged();\n        if (this.betsModalLayer) {\n            this.betsModalLayer.interactive = this.isWaitingForResponse();\n        }\n    }\n\n    protected isWaitingForResponse(): boolean {\n        return (\n            this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_RESPONSE ||\n            this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_RESPONSE_IN_AUTOPLAY ||\n            this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_RESPONSE_IN_FREESPIN\n        );\n    }\n\n    protected createSlidBetButtonsEvents(): void {\n        if (!this.isOneDenom()) {\n            super.createSlidBetButtonsEvents();\n            return;\n        }\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/bet-buttons/src/egt/modes/turtle/views/BetButtonsViewTurtle.ts:425:9\",(this.fakeBetButtonsMask),\"pointerup\"]), fromEvent(this.fakeBetButtonsMask, 'pointerup'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.handlePointerTap.bind(this));\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/bet-buttons/src/egt/modes/turtle/views/BetButtonsViewTurtle.ts:428:9\",(this.fakeBetButtonsMask),\"pointerdown\"]), fromEvent(this.fakeBetButtonsMask, 'pointerdown'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.handlePointerDown.bind(this));\n\n        this.handleTouchEndFn = this.handleTouchEnd.bind(this);\n\n        // List of all \"up\" and interaction events\n        const interactionEvents = [\n            // 'pointerup',    // added in BetButtonsView\n            'pointerupoutside',\n            'mouseup',\n            'touchend',\n            'blur', // When the window/tab loses focus\n            'visibilitychange', // When tab visibility changes (e.g., switching tabs)\n            'resize', // When window resizes\n            'beforeunload', // Before user closes the tab or navigates away\n        ];\n\n        interactionEvents.forEach((event) => {\n            fromEvent(window, event).pipe(takeUntil(this.DESTROY)).subscribe(this.handleTouchEndFn);\n        });\n\n        super.createSlidBetButtonsEvents();\n    }\n\n    protected handlePointerTap(): void {\n        if (!this.betButtonsSlidingStart && this.slidingAnimation?.paused()) {\n            this.fakeBetButtonsMask.interactive = false;\n            this.stopSlidingAnimation();\n        }\n    }\n\n    protected handlePointerDown(evt): void {\n        if (this.initialAnimationInProgress) {\n            return;\n        }\n        if (this.slidingAnimation) {\n            this.slidingAnimation.pause();\n            this.handleTouchStart(evt);\n        }\n    }\n\n    protected stopSlidingAnimation() {\n        if (this.slidingAnimation) {\n            this.killSlidingAnimation();\n            this.fakeBetButtonsMask.interactive = false;\n            this.xDown = null;\n\n            this.slideToCurrentSelectedIndex();\n        }\n    }\n\n    public switchBetButtons(fromIndex: number, toIndex: number) {\n        if (!this.isOneDenom()) {\n            super.switchBetButtons(fromIndex, toIndex);\n            return;\n        }\n        return;\n    }\n\n    protected slideToCurrentSelectedIndex(animation: boolean = true) {\n        if (this.visibleBetButtons.length === 0) {\n            return;\n        }\n\n        // when holding a bet button and rotate the array contains undefined objects\n        // restore all visible bet buttons\n        if (this.slideType === 'none' && this.visibleBetButtons.some((btn) => btn == undefined)) {\n            if (this.visibleBetButtons[0] == undefined) {\n                this.slideType = 'slideRight';\n            } else {\n                this.slideType = 'slideLeft';\n            }\n        }\n\n        // this.visibleBetButtons contains undefined obejcts;\n        // if slide if right get the first non-undefined object in the array\n        // if slide is left get the last non-undefined object in the array\n        const directionBtn =\n            this.slideType == 'slideRight'\n                ? this.visibleBetButtons.find((item) => item !== undefined)\n                : [...this.visibleBetButtons].reverse().find((item) => item !== undefined);\n        const targetIndex = this.betButtons.findIndex((button) => button.name == directionBtn?.name);\n\n        const buttonsToTarget = this.visibleBetButtons.length - 1;\n\n        let targetButton = this.betButtons[0];\n        if (this.slideType === 'slideRight' && targetIndex > 0) {\n            targetButton = this.betButtons[targetIndex];\n        } else if (this.slideType === 'slideLeft' && targetIndex < this.betButtons.length - 1) {\n            targetButton = this.betButtons[targetIndex - buttonsToTarget];\n        } else if (this.slideType === 'slideLeft') {\n            targetButton = this.betButtons[targetIndex - buttonsToTarget];\n        } else if (this.slideType === 'none') {\n            targetButton = this.visibleBetButtons[0];\n        }\n\n        this.slideToButton(targetButton, this.slideType == 'slideLeft', animation);\n    }\n\n    protected handleTouchStart(evt): void {\n        if (!this.isOneDenom()) {\n            super.handleTouchStart(evt);\n            return;\n        }\n\n        super.handleTouchStart(evt);\n\n        if (!this.slidingAnimation) {\n            this.initialVisibleSelectedIndex = this.findSelectedButtonIndex();\n        }\n\n        this.xDown = evt.data.global.x;\n\n        this.lastTouchX = this.xDown;\n        this.startTouchX = this.xDown;\n        this.startTouchTime = evt.data.originalEvent.timeStamp;\n    }\n\n    protected handleTouchMove(evt): void {\n        if (!this.isOneDenom()) {\n            super.handleTouchMove(evt);\n            return;\n        }\n\n        if (evt.data.pointerId !== this.pointerId || typeof this.xDown !== 'number' || this.feature.isInGiftSpins) {\n            this.xDown = null;\n            return;\n        }\n\n        const xUp: number = evt.data.global.x;\n        const xDiff: number = this.xDown - xUp;\n\n        if (\n            (xDiff > 5 || xDiff < -5) &&\n            (this.rootStore.uiStore.STATE.value === UIState.IDLE ||\n                this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT ||\n                this.rootStore.uiStore.STATE.value === UIState.SLIDING_BETS)\n        ) {\n            AnalyticsDispatcher.slideFeatureEvent(this.rootStore.uiStore.SELECTED_BET.value);\n            this.betButtonsSlidingStart = true;\n        }\n\n        if (!this.betButtonsSlidingStart) {\n            return;\n        }\n\n        this.isSlidingInitialized = true;\n        this.updateVisibleButtons();\n\n        if (\n            this.visibleBetButtons[this.initialVisibleSelectedIndex] &&\n            this.visibleBetButtons[this.initialVisibleSelectedIndex].enabled\n        ) {\n            if (!this.visibleBetButtons[this.initialVisibleSelectedIndex].selected) {\n                this.clearBetSelection();\n                this.visibleBetButtons[this.initialVisibleSelectedIndex].selected = true;\n                Core.sounds.play('sliderClick');\n            }\n        }\n        if (this.initialAnimationInProgress) {\n            this.betButtonsContainer.interactive = false;\n            this.enableBetButtons(false);\n        } else if (this.rootStore.uiStore.STATE.value !== UIState.DISABLED) {\n            this.saveCurrentUIState();\n            this.rootStore.uiStore.STATE.next(UIState.SLIDING_BETS);\n        }\n\n        this.checkCollect();\n\n        const currentX: number = evt.data.global.x;\n        if (\n            (currentX > this.lastTouchX && currentX <= this.startTouchX && Math.abs(currentX - this.lastTouchX) > 5) || // Direction changed to right\n            (currentX < this.lastTouchX && currentX >= this.startTouchX && Math.abs(currentX - this.lastTouchX) > 5) // Direction changed to left\n        ) {\n            // Reset the starting position and time when the sliding direction changes\n            this.xDown = currentX;\n            this.startTouchX = currentX;\n            this.startTouchTime = evt.data.originalEvent.timeStamp;\n        }\n        let speedMultiplier = 2.5;\n        if (\n            (this.visibleBetButtons.find((button) => button == this.betButtons[0]) && currentX - this.lastTouchX > 0) ||\n            (this.visibleBetButtons.find((button) => button == this.betButtons[this.betButtons.length - 1]) &&\n                currentX - this.lastTouchX < 0)\n        ) {\n            speedMultiplier = 0.5;\n        }\n        if (this.initialAnimationInProgress) {\n            speedMultiplier = 1;\n        }\n\n        const offset = (currentX - this.lastTouchX) * speedMultiplier;\n        this.betButtonsContainer.x += offset;\n        this.lastTouchX = currentX;\n    }\n\n    protected handleTouchEnd(evt, isFake: boolean = false): void {\n        if (!this.isOneDenom()) {\n            super.handleTouchEnd(evt);\n            return;\n        }\n\n        if ((this.initialAnimationInProgress && isFake) || (!isFake && !this.betButtonsSlidingStart)) {\n            this.xDown = null;\n        }\n        if ((this.initialAnimationInProgress && !isFake) || !evt.isPrimary || !this.betButtonsSlidingStart) {\n            return;\n        }\n        this.xDown = null;\n\n        const swipeTime = evt.timeStamp - this.startTouchTime;\n        const swipeDistance = this.lastTouchX - this.startTouchX;\n        let swipeSpeed = swipeTime > 500 ? 1 : swipeTime > 300 ? 2 : swipeTime > 200 ? 4 : 10;\n        if (isFake) {\n            swipeSpeed = 1;\n        }\n\n        // if selected button is pressed\n        const selectedBtn = this.betButtons.find((button) => button.selected);\n        if (selectedBtn) {\n            selectedBtn.state = ButtonStates.Normal;\n        }\n\n        this.fakeBetButtonsMask.interactive = true;\n        this.betButtonsSlidingStart = false;\n        this.pointerId = -1;\n\n        const toLeft: boolean = swipeDistance < 0;\n        this.slideType = toLeft ? 'slideLeft' : 'slideRight';\n\n        const buttonWidth = this.betButtons[0].width / swipeSpeed;\n        this.buttonsToSlide = Math.trunc(swipeDistance / buttonWidth);\n        const firstVisibleIndex = parseInt(this.visibleBetButtons[0]?.name.replace('bet', ''), 10) - 1;\n        const lastVisibleIndex =\n            parseInt(this.visibleBetButtons[this.visibleBetButtons.length - 1]?.name.replace('bet', ''), 10) - 1;\n\n        const targetIndex = (firstVisibleIndex ?? lastVisibleIndex) - this.buttonsToSlide;\n        const targetButton = this.getCenterTargetButton(targetIndex);\n\n        if (swipeSpeed == 1) {\n            this.slideToCurrentSelectedIndex(!isFake);\n        } else {\n            this.slideToButton(targetButton, toLeft);\n        }\n    }\n\n    protected checkCollect(): void {\n        if (\n            (this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT ||\n                (this.rootStore.uiStore.STATE.value === UIState.SLIDING_BETS &&\n                    this.rootStore.domainStore.SERVER_STATE.value === ServerState.WIN)) &&\n            !this.feature.isInGiftSpins\n        ) {\n            this.rootStore.domainStore.collect();\n            this.rootStore.uiStore.COLLECT_CHANGED.next();\n        }\n    }\n\n    public slideIfNotVisible(animation: boolean = true, targetIndex?: number, changedFromPopUp: boolean = false): void {\n        if (!this.isOneDenom()) {\n            super.slideIfNotVisible(animation, targetIndex, changedFromPopUp);\n            return;\n        }\n\n        if (this.slidingAnimation || this.isSlidingInitialized) {\n            return;\n        }\n        let prevIndex = this.rootStore.uiStore.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value);\n\n        if (targetIndex === undefined) {\n            targetIndex = this.rootStore.uiStore.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value);\n            prevIndex = this.rootStore.uiStore.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.prevValue);\n        }\n        const selectedBtn: BetButton = this.find('bet' + (targetIndex + 1));\n        const prevBtn: BetButton = this.find('bet' + (prevIndex + 1)) ?? selectedBtn;\n\n        if (!selectedBtn?.enabled) {\n            return;\n        }\n        const targetButton = this.getCenterTargetButton(targetIndex);\n        // if (Core.isDesktopMode) {\n        // preserve the order as it is in the denomination popup view\n        // const betPerDenomIndex = targetIndex % this.componentConfiguration.betButtons.length;\n        // targetIndex = targetIndex - betPerDenomIndex;\n        // targetButton = this.getTargetButton(targetIndex);\n        // }\n\n        if (this.checkIfButtonIsInvisible(selectedBtn) || changedFromPopUp) {\n            this.saveCurrentUIState();\n            if (animation) {\n                this.rootStore.uiStore.STATE.next(UIState.SLIDING_BETS);\n            }\n            this.slideToButton(targetButton, selectedBtn.betPerLine < prevBtn.betPerLine, animation);\n            this.isSlidingInitialized = true;\n        } else {\n            this.clearBetSelection();\n            selectedBtn.selected = true;\n            if (animation) {\n                this.rootStore.uiStore.SELECTED_BET.next(selectedBtn.betPerLine);\n                Core.sounds.play('sliderClick');\n            }\n        }\n        if (!animation) {\n            this.isSlidingInitialized = false;\n        }\n        this.updateVisibleButtons();\n    }\n\n    protected slideToButton(\n        button: BetButton,\n        toLeft: boolean,\n        animation: boolean = true,\n        nextButton?: BetButton | undefined,\n    ): void {\n        if (!button) {\n            return;\n        }\n        const buttonX = button.position.x + this.betButtonsContainer.x + button.width / 2;\n        const firstButtonX = this.componentConfiguration.betButtons[0].get('x') + button.width / 2;\n        const distance = toLeft ? buttonX - firstButtonX : firstButtonX - buttonX;\n        const targetX = this.betButtonsContainer.x + (toLeft ? -distance : distance);\n\n        if (animation && nextButton) {\n            this.rootStore.uiStore.SELECTED_BET.next(nextButton.betPerLine);\n        }\n\n        const onComplete = () => {\n            if (!nextButton) {\n                let button = this.visibleBetButtons[this.initialVisibleSelectedIndex];\n\n                if (button) {\n                    if (!button.enabled) {\n                        for (let i = this.initialVisibleSelectedIndex - 1; i >= 0; i--) {\n                            if (this.visibleBetButtons[i].enabled) {\n                                button = this.visibleBetButtons[i];\n                                break;\n                            }\n                        }\n                    }\n                    this.rootStore.uiStore.SELECTED_BET.next(button.betPerLine);\n\n                    if (!button.selected) {\n                        this.UPDATE_SELECTED_BET.next(button.betPerLine);\n                    }\n                }\n            }\n\n            this.killSlidingAnimation();\n            this.initialVisibleSelectedIndex = -1;\n            this.isSlidingInitialized = false;\n            this.updateVisibleButtons();\n            this.restoreState();\n            this.rootStore.uiStore.CURRENT_BET_LEVEL.next({\n                betLevel: this.rootStore.uiStore.SELECTED_BET.value,\n                denomLevel: Core.SELECTED_DENOMINATION.value,\n            });\n        };\n\n        if (animation) {\n            const speed = Math.max(Math.abs(this.buttonsToSlide) * 100, 1000);\n            const time = Math.max(distance / speed, 0.2);\n            this.slidingAnimation = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/bet-buttons/src/egt/modes/turtle/views/BetButtonsViewTurtle.ts:790:37\",null]), gsap.to(this.betButtonsContainer, {\n                x: targetX,\n                duration: time,\n                physics2D: {\n                    velocity: speed,\n                },\n                onUpdate: () => {\n                    this.updateVisibleButtons();\n                    const selectedButton = this.visibleBetButtons[this.initialVisibleSelectedIndex];\n                    if (selectedButton && this.slideToBet !== selectedButton.betPerLine && selectedButton.enabled) {\n                        this.slideToBet = selectedButton.betPerLine;\n                        this.UPDATE_SELECTED_BET.next(selectedButton.betPerLine);\n                        Core.sounds.play('sliderClick');\n                    }\n                },\n                onComplete: () => {\n                    onComplete();\n                },\n            }));\n        } else {\n            this.betButtonsContainer.x = targetX;\n            this.killSlidingAnimation();\n            this.initialVisibleSelectedIndex = -1;\n            this.isSlidingInitialized = false;\n            this.updateVisibleButtons();\n            if (this.rootStore.uiStore.STATE.value === UIState.SLIDING_BETS) {\n                this.restoreState();\n            }\n        }\n    }\n\n    protected updateVisibleButtons() {\n        const newButtons = Array(this.componentConfiguration.betButtons.length).fill(undefined);\n\n        const maskBounds = {\n            x: this.fakeBetButtonsMask.x,\n            width: this.fakeBetButtonsMask.width,\n        };\n\n        for (const betButton of this.betButtons) {\n            const buttonPosition = betButton.x + this.betButtonsContainer.x;\n            const buttonMiddleX = buttonPosition + betButton.width / 2;\n\n            let isVisible = this.checkIfButtonIsVisible(maskBounds, buttonMiddleX);\n            if (Core.isDesktopMode) {\n                const atTheLeft = this.checkIfButtonIsVisible(maskBounds, buttonPosition);\n                const atTheRight = this.checkIfButtonIsVisible(maskBounds, buttonPosition + betButton.width);\n                isVisible = atTheLeft && atTheRight;\n            }\n\n            if (!this.buttonsHidden) {\n                betButton.visible = isVisible || this.isSlidingInitialized;\n            }\n\n            if (isVisible) {\n                const index = this.componentConfiguration.betButtons.findIndex(\n                    (position) =>\n                        buttonMiddleX >= position.get('x') && buttonMiddleX <= position.get('x') + betButton.width,\n                );\n\n                if (index > -1) {\n                    newButtons[index] = betButton;\n                }\n            }\n        }\n        // Ensure visible array matches the config length and includes first/last buttons\n        if (newButtons.some((btn) => btn !== undefined)) {\n            this.visibleBetButtons = newButtons;\n            this.rootStore.uiStore.VISIBLE_BETS.next(\n                this.visibleBetButtons.map((btn) => (btn !== undefined ? btn.betPerLine : -1)),\n            );\n        }\n\n        this.showBetButtonParts();\n        this.slidBetButtonsHitArea.x = -this.betButtonsContainer.x;\n    }\n\n    protected showBetButtonParts(): void {\n        if (!this.isOneDenom()) {\n            super.showBetButtonParts();\n            return;\n        }\n\n        this.betBtnPieceLeft.visible = false;\n        this.betBtnPieceRight.visible = false;\n        if (Core.isDesktopMode) {\n            return;\n        }\n        if (\n            this.feature.isInGiftSpins ||\n            this.rootStore.domainStore.SERVER_STATE.value === ServerState.BONUS_IDLE ||\n            this.buttonsHidden\n        ) {\n            return;\n        }\n        const denominationLevel: number = this.getCurrentDenominationLevel();\n\n        if (\n            denominationLevel !== 1 ||\n            (this.betButtons[0] !== this.visibleBetButtons[0] && !this.isSlidingInitialized)\n        ) {\n            this.betBtnPieceLeft.visible = true;\n        }\n        if (\n            denominationLevel !== this.rootStore.uiStore.denominations.length ||\n            (this.betButtons[this.betButtons.length - 1] !==\n                this.visibleBetButtons[this.visibleBetButtons.length - 1] &&\n                !this.isSlidingInitialized)\n        ) {\n            this.betBtnPieceRight.visible = true;\n        }\n    }\n\n    protected slidArrowsClicked(slideType: 'slideLeft' | 'slideRight' | 'none'): void {\n        if (!this.isOneDenom()) {\n            super.slidArrowsClicked(slideType);\n            return;\n        }\n        // when from blitz play collect for history open bug ON-150753\n        if (\n            this.rootStore.uiStore.lastResponseFromBlitzPlay &&\n            this.rootStore.uiStore.STATE.value === UIState.IDLE &&\n            this.rootStore.domainStore.SERVER_STATE.value !== ServerState.IDLE\n        ) {\n            this.rootStore.domainStore.SERVER_STATE.next(ServerState.IDLE);\n        }\n        if (\n            (this.rootStore.domainStore.SERVER_STATE.value === ServerState.IDLE &&\n                (this.rootStore.uiStore.STATE.value === UIState.IDLE ||\n                    this.rootStore.uiStore.STATE.value === UIState.SLIDING_BETS)) ||\n            (this.rootStore.domainStore.SERVER_STATE.value === ServerState.WIN &&\n                this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT)\n        ) {\n            AnalyticsDispatcher.slideFeatureEvent(this.rootStore.uiStore.SELECTED_BET.value);\n            this.slideType = slideType;\n\n            const isLeft = this.slideType === 'slideLeft';\n\n            if (this.slidingAnimation) {\n                this.slidingAnimation.progress(1);\n                this.killSlidingAnimation();\n                this.isSlidingInitialized = false;\n                this.initialVisibleSelectedIndex = -1;\n                this.updateVisibleButtons();\n            }\n\n            const globalSelectedIndex = this.rootStore.uiStore.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value);\n\n            const nextIndex = globalSelectedIndex + (isLeft ? -1 : 1);\n\n            if (nextIndex < 0 || nextIndex >= this.betButtons.length) {\n                return;\n            }\n\n            let nextButton: BetButton | undefined = this.betButtons[nextIndex];\n\n            if (!nextButton.enabled) {\n                nextButton = undefined;\n            }\n\n            const centerIndex = Math.floor(this.visibleBetButtons.length / 2);\n            this.initialVisibleSelectedIndex = this.findSelectedButtonIndex();\n\n            if (nextButton && this.shouldSelectNextBetWithoutSliding(centerIndex, isLeft)) {\n                this.clearBetSelection();\n                nextButton.selected = true;\n\n                this.rootStore.uiStore.SELECTED_BET.next(nextButton.betPerLine);\n                Core.sounds.play('sliderClick');\n\n                this.updateVisibleButtons();\n                return;\n            }\n\n            this.buttonsToSlide = 1;\n            const firstVisibleIndex =\n                this.rootStore.uiStore.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value) -\n                this.initialVisibleSelectedIndex;\n            const targetIndex = firstVisibleIndex + (isLeft ? -1 : 1);\n            const targetButton = this.getTargetButton(targetIndex);\n\n            this.saveCurrentUIState();\n            this.rootStore.uiStore.STATE.next(UIState.SLIDING_BETS);\n            this.slideToButton(targetButton, isLeft, true, nextButton);\n            this.isSlidingInitialized = true;\n        }\n    }\n\n    private shouldSelectNextBetWithoutSliding(centerIndex: number, isLeft: boolean): boolean {\n        const selectedIndex = this.initialVisibleSelectedIndex;\n        const edgeIndex = isLeft ? 0 : this.visibleBetButtons.length - 1;\n        const edgeBetButton = isLeft ? this.betButtons[0] : this.betButtons[this.betButtons.length - 1];\n\n        if (this.visibleBetButtons[edgeIndex] === edgeBetButton) {\n            return true;\n        }\n\n        return selectedIndex !== centerIndex && selectedIndex !== edgeIndex;\n    }\n\n    /** \n     SLIDING DEMO ANIMATION IMPL \n    */\n    private createFakeInteractionEvent(type: string, x: number, y: number, sprite: Sprite): InteractionEvent {\n        return {\n            type,\n            data: {\n                global: { x: sprite.getLocalBounds().x + x, y: sprite.getGlobalPosition().y + y },\n                originalEvent: { timeStamp: Date.now() },\n            },\n            // biome-ignore lint/suspicious/noEmptyBlockStatements: <explanation>\n            stopPropagation: () => {},\n            target: sprite,\n            currentTarget: sprite,\n        } as unknown as InteractionEvent;\n    }\n\n    private createFakePointerEvent(type: string, x: number, y: number, sprite: Sprite): PointerEvent {\n        return new PointerEvent(type, {\n            bubbles: true,\n            cancelable: true,\n            clientX: sprite.getLocalBounds().x + x,\n            clientY: sprite.getGlobalPosition().y + y,\n            pointerId: 1,\n            pointerType: 'touch',\n            isPrimary: true,\n        });\n    }\n\n    private simulateFakeTouchEvents(sprite: Sprite): void {\n        if (!sprite.interactive) {\n            sprite.interactive = true;\n        }\n\n        const initialX = sprite.x;\n        let currentX = initialX;\n\n        const touchStartEvent = this.createFakeInteractionEvent('touchstart', initialX, 0, sprite);\n\n        // This animation serves only as a demonstration that sliding is possible.\n        // It does not trigger any bet changes, so other buttons remain enabled, and the UI state is not updated.\n        this.initialAnimationInProgress = true;\n\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'betPlusBtn',\n            actions: 'enabled',\n            values: false,\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'betMinusBtn',\n            actions: 'enabled',\n            values: false,\n        });\n\n        this.handleTouchStart(touchStartEvent);\n\n        const stepsToTheLeft = 50;\n        const stepsToTheRight = 60;\n        const isLeft = this.betBtnPieceRight.visible ? 1 : -1; // reverse movement if selected bet is one of the last visible bets\n\n        for (let i = 1; i <= stepsToTheLeft; i++) {\n            const moveTimeout = Timers.setTimeout(() => {\n                currentX = initialX + isLeft * -i;\n                const touchMoveEvent = this.createFakeInteractionEvent('touchmove', currentX, 0, sprite);\n                this.handleTouchMove(touchMoveEvent);\n            }, i * 10);\n            this.initialAnimationTimeouts.push(moveTimeout);\n        }\n\n        let timeout = 0;\n\n        for (let i = 1; i <= stepsToTheRight; i++) {\n            timeout = (stepsToTheLeft + i) * 10;\n            const moveBackTimeout = Timers.setTimeout(() => {\n                currentX = initialX + isLeft * (-stepsToTheLeft + i);\n                const touchMoveEvent = this.createFakeInteractionEvent('touchmove', currentX, 0, sprite);\n                this.handleTouchMove(touchMoveEvent);\n            }, timeout);\n            this.initialAnimationTimeouts.push(moveBackTimeout);\n        }\n\n        const touchEndEvent = this.createFakePointerEvent('touchend', currentX, 0, sprite);\n        const endTimeout = Timers.setTimeout(() => {\n            this.handleTouchEnd(touchEndEvent, true);\n            this.restoreState();\n            this.killInitialAnimationTimeouts();\n            this.initialAnimationInProgress = false;\n\n            this.uiView.setLastBetButtonsState();\n            this.uiView.steFirsBetButtonsState();\n        }, timeout);\n        this.initialAnimationTimeouts.push(endTimeout);\n    }\n    /** \n     SLIDING DEMO ANIMATION IMPL END\n    */\n\n    private saveCurrentUIState() {\n        if (this.rootStore.uiStore.STATE.value !== UIState.SLIDING_BETS) {\n            this.currentState = this.rootStore.uiStore.STATE.value;\n        }\n    }\n\n    private restoreState() {\n        this.fakeBetButtonsMask.interactive = false;\n\n        if (this.initialAnimationInProgress) {\n            if (this.rootStore.uiStore.STATE.value == UIState.IDLE) {\n                this.betButtonsContainer.interactive = true;\n                this.enableBetButtons(true);\n            }\n            return;\n        }\n        const restoreState = this.currentState !== UIState.WAITING_FOR_COLLECT;\n        if (restoreState) {\n            this.rootStore.uiStore.STATE.next(this.currentState);\n        }\n    }\n\n    private checkIfButtonIsInvisible(button: BetButton): boolean {\n        const maskX = this.moneyContainerGroup.x + this.fakeBetButtonsMask.x;\n        const maskWidth = this.fakeBetButtonsMask.width;\n\n        const buttonPosition = button.x + this.betButtonsContainer.x + this.moneyContainerGroup.x;\n\n        const atTheLeft = this.checkIfButtonIsVisible({ x: maskX, width: maskWidth }, buttonPosition);\n        const atTheRight = this.checkIfButtonIsVisible({ x: maskX, width: maskWidth }, buttonPosition + button.width);\n\n        return !atTheLeft || !atTheRight;\n    }\n\n    private findSelectedButtonIndex(): number {\n        for (let i = 0; i <= this.visibleBetButtons.length - 1; i++) {\n            if (this.visibleBetButtons[i]?.selected) {\n                return i;\n            }\n        }\n        return 0;\n    }\n\n    private checkIfButtonIsVisible(object: { x: number; width: number }, x: number): boolean {\n        return x >= object.x && x <= object.x + object.width;\n    }\n\n    private getTargetButton(targetIndex: number): BetButton {\n        if (!targetIndex || targetIndex < 1) {\n            targetIndex = 0;\n        } else if (targetIndex >= this.betButtons.length - this.componentConfiguration.betButtons.length) {\n            targetIndex = this.betButtons.length - this.componentConfiguration.betButtons.length;\n        }\n\n        return this.find('bet' + (targetIndex + 1));\n    }\n\n    private getCenterTargetButton(targetIndex: number): BetButton {\n        if (!targetIndex || targetIndex < 2) {\n            targetIndex = 0;\n        } else if (targetIndex >= this.betButtons.length - 2) {\n            targetIndex = this.betButtons.length - this.componentConfiguration.betButtons.length;\n        } else {\n            targetIndex = targetIndex - 2;\n        }\n\n        return this.find('bet' + (targetIndex + 1));\n    }\n\n    private killSlidingAnimation() {\n        if (this.slidingAnimation) {\n            this.slidingAnimation.kill();\n            this.slidingAnimation = null;\n        }\n    }\n\n    private killInitialAnimationTimeouts() {\n        if (this.initialAnimationInProgress) {\n            if (this.initialAnimationTimeouts.length > 0) {\n                this.initialAnimationTimeouts.forEach((timeout) => {\n                    Timers.clearTimeout(timeout);\n                });\n                this.initialAnimationTimeouts = [];\n            }\n        }\n    }\n\n    private onMessage(response: any): void {\n        if (response.event == 'collect') {\n            if (this.currentState === UIState.WAITING_FOR_COLLECT) {\n                this.currentState = response.state;\n                // There is a race condition if collect comes after the tween is finished and the buttons stays locked\n                // @Tcveti please check, and better add state machine\n                if (!this.slidingAnimation) {\n                    this.restoreState();\n                }\n            }\n            if (\n                this.rootStore.uiStore.STATE.value === response.state &&\n                this.slidingAnimation &&\n                !this.initialAnimationInProgress\n            ) {\n                this.rootStore.uiStore.STATE.next(UIState.SLIDING_BETS);\n            }\n        }\n    }\n\n    private isOneDenom() {\n        return this.rootStore.uiStore.denominations.length === 1;\n    }\n}\n","import Core, { BaseComponent, IBaseComponentController, IBaseComponentView, IModeConfig } from '@egt/core';\nimport { SlotComponents, ZOrders } from '@egt/slot';\nimport { Lifecycle } from 'tsyringe';\nimport BetCalculatorModesConfigurations, { BetCalculatorModes } from './BetCalculatorFactory';\nimport { BetCalculatorComponentConfigurationFactoryDefault } from './modes/default/configuration/BetCalculatorComponentConfigurationDefault';\nimport { BetCalculatorComponentConfigurationFactoryTurtle } from './modes/turtle/configuration/BetCalculatorComponentConfigurationTurtle';\n\nexport default class BetCalculatorComponent extends BaseComponent {\n    public static configurationName = 'BetCalculatorComponent';\n\n    public betCalculatorView: IBaseComponentView;\n    public betCalculatorController: IBaseComponentController;\n    public componentType = SlotComponents.BET_CALCULATOR;\n    public configuration;\n    public rootView;\n\n    constructor(modeConfig: IModeConfig) {\n        super();\n        const baseConfigs = {\n            [BetCalculatorModes.DEFAULT]: BetCalculatorComponentConfigurationFactoryDefault,\n            [BetCalculatorModes.TURTLE]: BetCalculatorComponentConfigurationFactoryTurtle,\n        };\n\n        this.modeFactory = this.initMode<BetCalculatorModesConfigurations>(modeConfig, {\n            defaultModeType: BetCalculatorModes.DEFAULT,\n            baseConfigs,\n            defaultFactory: BetCalculatorModesConfigurations,\n        });\n    }\n\n    public destroy(): void {\n        this.betCalculatorController.destroy();\n        // @ts-ignore\n        this.betCalculatorController = null;\n        // @ts-ignore\n        this.betCalculatorView = null;\n        (this.configuration as any).destroy();\n        // @ts-ignore\n        this.configuration = null;\n        // @ts-ignore\n        this.dependencyContainer = null;\n\n        // @ts-ignore\n        this.config = null;\n\n        // @ts-ignore\n        this.rootView = null;\n\n        super.destroy();\n    }\n\n    public onAfterGameConfigurationCreated(): void {\n        super.onAfterGameConfigurationCreated();\n        this.configuration = this.dependencyContainer.resolve('BetCalculatorComponentConfiguration');\n    }\n\n    public onRegisterDependencies(container: any): void {\n        super.onRegisterDependencies(container);\n\n        if (!this.dependencyContainer.isRegistered('BetCalculator')) {\n            this.dependencyContainer.register(\n                'BetCalculator',\n                { useClass: this.mode.view },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n\n        if (!this.dependencyContainer.isRegistered('BetCalculatorController')) {\n            this.dependencyContainer.register(\n                'BetCalculatorController',\n                { useClass: this.mode.controller },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n        this.dependencyContainer.register('BetCalculatorComponentConfiguration', this.mode.configuration);\n    }\n\n    public onPrepareResources(_container: any): void {\n        // Core.fonts.addAssets([\n        //     {\n        //         id: 'RobotoCondensed-Regular',\n        //         url: '../assets/Fonts/Roboto/RobotoCondensed-Regular.ttf',\n        //         priority: AssetPriority.HIGHEST,\n        //         type: 'font',\n        //     },\n        //     {\n        //         id: 'RobotoCondensed-Bold',\n        //         url: '../assets/Fonts/Roboto/RobotoCondensed-Bold.ttf',\n        //         priority: AssetPriority.HIGHEST,\n        //         type: 'font',\n        //     },\n        // ]);\n        Core.assets.addAssets(this.configuration?.assets?.toArray() || []);\n    }\n\n    public onResolveDependencies(container: any): void {\n        super.onResolveDependencies(container);\n\n        // to do: remove this - this view component must be injected dynamicaly on popup component\n        this.rootView = this.dependencyContainer.resolve('RootView');\n        this.betCalculatorView = this.dependencyContainer.resolve('BetCalculator');\n        this.betCalculatorController = this.dependencyContainer.resolve('BetCalculatorController');\n        this.betCalculatorView.zIndex = ZOrders.POPUP_LEVEL;\n    }\n\n    public onInit(): void {\n        this.betCalculatorView.init();\n        this.betCalculatorController.init();\n    }\n}\n","import { BaseModesConfigurations, IForceSetConfig, IModes } from '@egt/core';\nimport BetCalculatorViewDefault from './modes/default/views/BetCalculatorViewDefault';\nimport BetCalculatorControllerTurtle from './modes/turtle/controllers/BetCalculatorControllerTurtle';\nimport BetCalculatorControllerDefault from './modes/default/controllers/BetCalculatorControllerDefault';\nimport { BetCalculatorComponentConfigurationFactoryDefault } from './modes/default/configuration/BetCalculatorComponentConfigurationDefault';\nimport { BetCalculatorComponentConfigurationFactoryTurtle } from './modes/turtle/configuration/BetCalculatorComponentConfigurationTurtle';\nimport BetCalculatorViewTurtle from './modes/turtle/views/BetCalculatorViewTurtle';\n\nexport default class BetCalculatorModesConfigurations extends BaseModesConfigurations<BetCalculatorModes> {\n    constructor(modeType: BetCalculatorModes, forceSetConfig?: IForceSetConfig) {\n        super(modeType, forceSetConfig);\n    }\n\n    protected createBaseModesConfig(modeType: BetCalculatorModes): IModes {\n        switch (modeType) {\n            case BetCalculatorModes.TURTLE:\n                return {\n                    view: BetCalculatorViewTurtle,\n                    controller: BetCalculatorControllerTurtle,\n                    configuration: BetCalculatorComponentConfigurationFactoryTurtle(),\n                };\n            default:\n                return {\n                    view: BetCalculatorViewDefault,\n                    controller: BetCalculatorControllerDefault,\n                    configuration: BetCalculatorComponentConfigurationFactoryDefault(),\n                };\n        }\n    }\n}\n\nexport enum BetCalculatorModes {\n    DEFAULT = 'default',\n    TURTLE = 'turtle',\n}\n","import Core, { Money, Timers } from '@egt/core';\nimport { ButtonShapes, ViewContainer } from '@egt/ui-lib';\nimport { gsap } from 'gsap';\nimport { Sprite, Text, TextStyle, Texture } from 'pixi.js';\nimport { Subject, fromEvent } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\n\nexport default class BetSettingButtonCommon extends ViewContainer {\n    public readonly CLICK = new Subject();\n\n    public denominationLevel: number;\n    public betLevel: number;\n    protected _factor: number;\n    protected buttonBackground: Sprite;\n\n    protected _state: BetSettingsButtonStatesCommon = BetSettingsButtonStatesCommon.Normal;\n    protected _shape: ButtonShapes = ButtonShapes.Rectangle;\n    protected _enabled: boolean;\n\n    protected textures: BetSettingsButtonTextures;\n    protected btnText: Text;\n    protected currencyText: Text;\n    protected currencyTextBaseY: number;\n    protected btnTextBaseY: number;\n    protected btnTextStyleNormal: TextStyle;\n    protected btnTextStyleNormalHilighted: TextStyle;\n    protected currencyTextStyleNormal: TextStyle;\n    protected currencyTextStyleNormalHilighted: TextStyle;\n    protected hilighted: boolean;\n\n    protected jackpotStamp: Sprite;\n    private jackpotStampTween: any;\n    private jackpotStampTimer: any;\n\n    private maxBet: number | undefined;\n    private buyBonusMaxBet: number | undefined;\n    private _buyBonusActivated: boolean | undefined;\n    private buyBonusDenominations: number[] | undefined;\n\n    constructor(\n        denominationLevel: number,\n        betLevel: number,\n        factor: number,\n        textures: BetSettingsButtonTextures,\n        valueOffset: number,\n        currencyOffset: number,\n        btnTextStyleNormal: TextStyle,\n        currencyTextStyleNormal: TextStyle,\n        currencyTextStyleNormalHilighted?: TextStyle,\n        btnTextStyleNormalHilighted?: TextStyle,\n        width?: number,\n        height?: number,\n        jackpotStamp?: Sprite,\n        stampOffset?: number,\n        maxBet?: number,\n        buyBonusMaxBet?: number,\n        buyBonusDenominations?: number[],\n    ) {\n        super();\n        this.denominationLevel = denominationLevel;\n        this.betLevel = betLevel;\n        this.textures = textures;\n        this.factor = factor;\n        this.btnTextStyleNormal = btnTextStyleNormal;\n        this.btnTextStyleNormalHilighted = btnTextStyleNormalHilighted\n            ? btnTextStyleNormalHilighted\n            : btnTextStyleNormal;\n\n        this.currencyTextStyleNormal = currencyTextStyleNormal;\n        this.currencyTextStyleNormalHilighted = currencyTextStyleNormalHilighted\n            ? currencyTextStyleNormalHilighted\n            : currencyTextStyleNormal;\n        this.maxBet = maxBet;\n        this.buyBonusMaxBet = buyBonusMaxBet;\n        this.buyBonusDenominations = buyBonusDenominations;\n\n        this.createBtnBackground(width, height);\n        this.addBtnText(btnTextStyleNormal, valueOffset);\n        this.addBtnCurrency(currencyTextStyleNormal, currencyOffset);\n        this.addBtnStamp(jackpotStamp, stampOffset);\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/bet-calculator/src/egt/common/buttons/BetSettingButtonCommon.ts:82:9\",(this.buttonBackground),\"pointerdown\"]), fromEvent(this.buttonBackground, 'pointerdown'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerDown.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/bet-calculator/src/egt/common/buttons/BetSettingButtonCommon.ts:86:9\",(this.buttonBackground),\"pointerup\"]), fromEvent(this.buttonBackground, 'pointerup'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerUp.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/bet-calculator/src/egt/common/buttons/BetSettingButtonCommon.ts:90:9\",(this.buttonBackground),\"pointerupoutside\"]), fromEvent(this.buttonBackground, 'pointerupoutside'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerOut.bind(this));\n\n        fromEvent(this.buttonBackground, 'pointerover')\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerOver.bind(this));\n\n        fromEvent(this.buttonBackground, 'pointerout')\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerOut.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/bet-calculator/src/egt/common/buttons/BetSettingButtonCommon.ts:102:9\",(this.buttonBackground),\"pointertap\"]), fromEvent(this.buttonBackground, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerTap.bind(this));\n    }\n\n    public destroy(): void {\n        this.removeChildren();\n\n        this.buttonBackground.destroy({ children: true });\n        this.textures.destroy();\n        // @ts-ignore\n        this.textures = null;\n\n        this.btnText.destroy();\n        // @ts-ignore\n        this.btnText = null;\n\n        super.destroy();\n    }\n\n    public fakeClick(): void {\n        this.buttonBackground.emit('pointertap');\n    }\n\n    public onPointerDown(): void {\n        if (\n            this.state === BetSettingsButtonStatesCommon.Disabled ||\n            this.state === BetSettingsButtonStatesCommon.Selected ||\n            this.state === BetSettingsButtonStatesCommon.MaxBet ||\n            this.state === BetSettingsButtonStatesCommon.RestrictedByDenomination\n        ) {\n            return;\n        }\n        this.state = BetSettingsButtonStatesCommon.Over;\n    }\n\n    /**\n     *\n     */\n    public onPointerOut(): void {\n        if (\n            this.state === BetSettingsButtonStatesCommon.Disabled ||\n            this.state === BetSettingsButtonStatesCommon.Selected ||\n            this.state === BetSettingsButtonStatesCommon.MaxBet ||\n            this.state === BetSettingsButtonStatesCommon.RestrictedByDenomination\n        ) {\n            return;\n        }\n        if (this.hilighted) {\n            this.state = BetSettingsButtonStatesCommon.Hilight;\n        } else {\n            this.state = BetSettingsButtonStatesCommon.Normal;\n        }\n    }\n\n    public setBtnText(text: string) {\n        this.btnText.text = text;\n    }\n\n    public getBtnText(): Text {\n        return this.btnText;\n    }\n\n    public setPressed(): void {\n        this.state = BetSettingsButtonStatesCommon.Pressed;\n    }\n\n    public setSelected(): void {\n        this.state = BetSettingsButtonStatesCommon.Selected;\n        this.buttonBackground.texture = this.textures.selectedTexture;\n        this.currencyText.style = this.currencyTextStyleNormalHilighted;\n        const currentFontSize = this.btnText.style.fontSize;\n        const currentLineHeight = this.btnText.style.lineHeight;\n        this.btnText.style = new TextStyle({\n            ...this.btnTextStyleNormalHilighted,\n            fontSize: currentFontSize,\n            lineHeight: currentLineHeight,\n        });\n    }\n\n    public setHilighted(): void {\n        this.hilighted = true;\n        if (\n            this.state !== BetSettingsButtonStatesCommon.MaxBet &&\n            this.state !== BetSettingsButtonStatesCommon.RestrictedByDenomination\n        ) {\n            this.state = BetSettingsButtonStatesCommon.Hilight;\n        }\n        this.buttonBackground.texture = this.textures.hilightTexture;\n        const currentFontSize = this.btnText.style.fontSize;\n        const currentLineHeight = this.btnText.style.lineHeight;\n        this.btnText.style = new TextStyle({\n            ...this.btnTextStyleNormalHilighted,\n            fontSize: currentFontSize,\n            lineHeight: currentLineHeight,\n        });\n    }\n    public setNormal(): void {\n        this.hilighted = false;\n        if (\n            this.state !== BetSettingsButtonStatesCommon.MaxBet &&\n            this.state !== BetSettingsButtonStatesCommon.RestrictedByDenomination\n        ) {\n            this.state = BetSettingsButtonStatesCommon.Normal;\n        }\n        this.buttonBackground.texture = this.textures.normalTexture;\n        this.btnText.style = this.btnTextStyleNormal;\n        this.currencyText.style = this.currencyTextStyleNormal;\n    }\n\n    public setMaxBet(): void {\n        this.state = BetSettingsButtonStatesCommon.MaxBet;\n    }\n\n    public setRestrictedByDenomination(): void {\n        this.state = BetSettingsButtonStatesCommon.RestrictedByDenomination;\n    }\n\n    public updateTextures(\n        normalTexture: Texture,\n        hilightTexture: Texture,\n        selectedTexture: Texture,\n        disabledTexture?: Texture,\n        overTexture?: Texture,\n        overHilightTexture?: Texture,\n        pressedTexture?: Texture,\n    ): void {\n        this.textures.updateTextures(\n            normalTexture,\n            hilightTexture,\n            selectedTexture,\n            disabledTexture,\n            overTexture,\n            overHilightTexture,\n            pressedTexture,\n        );\n        this.state = this.state;\n    }\n\n    protected addBtnText(btnTextStyle: TextStyle, valueYOffset: number): void {\n        this.btnText = new Text(this.formatMoney(this.getMoney()), btnTextStyle);\n        this.btnText.resolution = 2;\n        this.btnText.anchor.set(0.5, 1);\n        this.btnText.x = this.buttonBackground.width / 2;\n        this.btnText.y = this.height - valueYOffset;\n        this.btnTextBaseY = this.btnText.y;\n        this.addChild(this.btnText);\n    }\n\n    protected addBtnCurrency(currencyTextStyleNormal: TextStyle, offsetY: number): void {\n        this.currencyText = new Text(Core.PLAYER_BALANCE.value.currency, currencyTextStyleNormal);\n        this.currencyText.resolution = 2;\n        this.currencyText.anchor.set(0.5, 1);\n        this.currencyText.x = this.width / 2;\n        this.currencyText.y = offsetY;\n        this.currencyTextBaseY = offsetY;\n        this.addChild(this.currencyText);\n    }\n\n    public updateTextsLayout(currencyValueGap: number, oldFontSize: number, newFontSize: number): void {\n        const fontSizeDifference = newFontSize - oldFontSize;\n        if (fontSizeDifference > currencyValueGap) {\n            this.currencyText.y = this.currencyTextBaseY + currencyValueGap / 2;\n        } else {\n            this.currencyText.y = this.currencyTextBaseY + fontSizeDifference / 2;\n        }\n        this.currencyText.x = this.buttonBackground.width / 2;\n        this.btnText.y = this.currencyText.y + this.btnText.height + currencyValueGap;\n    }\n\n    public restoreTextsDefaultLayout(correctFontSize: number): void {\n        this.currencyText.y = this.currencyTextBaseY;\n        this.btnText.y = this.btnTextBaseY;\n        this.btnText.style.fontSize = correctFontSize;\n    }\n\n    private addBtnStamp(jackpotStamp: Sprite | undefined, offset?: number) {\n        if (jackpotStamp) {\n            this.jackpotStamp = jackpotStamp;\n            this.jackpotStamp.anchor.set(0.5, 0);\n            this.jackpotStamp.x = this.buttonBackground.width / 2;\n            this.jackpotStamp.y = offset || 10;\n            this.jackpotStamp.alpha = 0;\n            this.addChild(this.jackpotStamp);\n        }\n    }\n\n    protected setJackpotStampAnim(): void {\n        this.currencyText.alpha = 0;\n        this.jackpotStampTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/bet-calculator/src/egt/common/buttons/BetSettingButtonCommon.ts:291:34\",null]), gsap.timeline({\n            onComplete: () => {\n                this.currencyText.alpha = 1;\n                this.startJackpotStampAnim();\n            },\n        }));\n        this.jackpotStampTween\n            .to(this.jackpotStamp, {\n                duration: 0.5,\n                alpha: 1,\n                ease: 'power2.inOut',\n                yoyo: true,\n                repeat: 2,\n            })\n            .to(this.jackpotStamp, {\n                duration: 0.5,\n                alpha: 0,\n            });\n    }\n\n    protected startJackpotStampAnim(): void {\n        this.jackpotStampTimer = Timers.setTimeout(() => {\n            this.setJackpotStampAnim();\n        }, 3000);\n    }\n\n    protected checkForJackpotStamp(state: BetSettingsButtonStatesCommon): void {\n        if (this.jackpotStamp && state === BetSettingsButtonStatesCommon.Hilight) {\n            if (!this.jackpotStampTimer) {\n                this.startJackpotStampAnim();\n            }\n        }\n    }\n\n    protected killJackpotStamp(): void {\n        this.currencyText.alpha = 1;\n        if (this.jackpotStampTimer) {\n            Timers.clearTimeout(this.jackpotStampTimer);\n            this.jackpotStampTimer = undefined;\n        }\n        if (this.jackpotStampTween) {\n            this.jackpotStampTween.totalProgress(0);\n            this.jackpotStampTween.kill();\n            this.jackpotStampTween = null;\n        }\n    }\n\n    protected formatMoney(money: Money): string {\n        this.maxBetCheck(money);\n        this.denominationRestrictionCheck();\n        if (money.amountMoney >= 100 && Number.isInteger(money.amountMoney)) {\n            return money.stringMoneyWithoutCents;\n        } else {\n            return money.stringMoney;\n        }\n    }\n\n    protected maxBetCheck(money: Money) {\n        const isOverMaxBet = this.maxBet && money.amountMoney > this.maxBet;\n        const isOverMaxBetBuyBonus =\n            this.buyBonusActivated && this.buyBonusMaxBet && money.amountMoney > this.buyBonusMaxBet;\n\n        if (isOverMaxBet || isOverMaxBetBuyBonus) {\n            if (isOverMaxBet) {\n                this.visible = false;\n            } else {\n                this.visible = true;\n            }\n            if (isOverMaxBetBuyBonus) {\n                this.setMaxBet();\n            }\n        } else {\n            if (this.state === BetSettingsButtonStatesCommon.MaxBet) {\n                this.state = BetSettingsButtonStatesCommon.Normal;\n            }\n            if (this.state !== BetSettingsButtonStatesCommon.RestrictedByDenomination) {\n                this.untintBtn();\n            }\n        }\n    }\n    protected denominationRestrictionCheck(): void {\n        const isRestrictedByDenomination = this.isDenominationNotAllowed();\n\n        if (isRestrictedByDenomination) {\n            this.visible = true;\n            if (this.state !== BetSettingsButtonStatesCommon.MaxBet) {\n                this.setRestrictedByDenomination();\n            }\n        } else {\n            if (this.state === BetSettingsButtonStatesCommon.RestrictedByDenomination) {\n                this.state = BetSettingsButtonStatesCommon.Normal;\n            }\n            if (this.state !== BetSettingsButtonStatesCommon.MaxBet) {\n                this.untintBtn();\n            }\n        }\n    }\n\n    protected isDenominationNotAllowed(): boolean {\n        if (!this.buyBonusActivated || !this.buyBonusDenominations) return false;\n        return !this.buyBonusDenominations.includes(this.denominationLevel);\n    }\n\n    protected createBtnBackground(width?: number, height?: number): void {\n        this.buttonBackground = new Sprite(this.textures.normalTexture);\n        this.buttonBackground.interactive = true;\n        if (width) {\n            this.buttonBackground.width = width;\n        }\n        if (height) {\n            this.buttonBackground.height = height;\n        }\n        this.addChild(this.buttonBackground);\n    }\n\n    protected onPointerUp(): void {\n        if (\n            this.state === BetSettingsButtonStatesCommon.Disabled ||\n            this.state === BetSettingsButtonStatesCommon.Selected ||\n            this.state === BetSettingsButtonStatesCommon.MaxBet ||\n            this.state === BetSettingsButtonStatesCommon.RestrictedByDenomination\n        ) {\n            return;\n        }\n        if (this.hilighted) {\n            this.state = BetSettingsButtonStatesCommon.Hilight;\n        } else {\n            this.state = BetSettingsButtonStatesCommon.Normal;\n        }\n    }\n\n    protected onPointerOver(): void {\n        if (\n            this.state === BetSettingsButtonStatesCommon.Disabled ||\n            this.state === BetSettingsButtonStatesCommon.Selected ||\n            this.state === BetSettingsButtonStatesCommon.MaxBet ||\n            this.state === BetSettingsButtonStatesCommon.RestrictedByDenomination\n        ) {\n            if (this.state === BetSettingsButtonStatesCommon.Selected) {\n                this.cursor = 'pointer';\n            }\n            return;\n        }\n        this.state = BetSettingsButtonStatesCommon.Over;\n    }\n\n    protected onPointerTap(): void {\n        if (\n            this.state === BetSettingsButtonStatesCommon.Disabled ||\n            this.state === BetSettingsButtonStatesCommon.MaxBet ||\n            this.state === BetSettingsButtonStatesCommon.RestrictedByDenomination\n        ) {\n            return;\n        }\n        this.CLICK.next(this);\n    }\n\n    protected getTexture(): BetSettingsButtonTextures {\n        return this.textures;\n    }\n\n    get factor(): number {\n        return this._factor;\n    }\n\n    set factor(factor: number) {\n        this._factor = factor;\n        if (this.btnText) {\n            this.btnText.text = this.formatMoney(this.getMoney());\n            this.btnText.x = this.buttonBackground.width / 2;\n            this.currencyText.x = this.buttonBackground.width / 2;\n        }\n    }\n\n    set enabled(value: boolean) {\n        this._enabled = value;\n        this.interactive = value;\n        this.buttonBackground.interactive = value;\n    }\n\n    set buyBonusActivated(value: boolean | undefined) {\n        this._buyBonusActivated = value;\n        const money = this.getMoney();\n        this.maxBetCheck(money);\n        this.denominationRestrictionCheck();\n    }\n\n    private getMoney(): Money {\n        const moneyInUnits: number = this.betLevel * this.denominationLevel * this.factor;\n        return new Money(moneyInUnits);\n    }\n\n    get buyBonusActivated(): boolean | undefined {\n        return this._buyBonusActivated;\n    }\n\n    get state(): BetSettingsButtonStatesCommon {\n        return this._state;\n    }\n\n    set state(state: BetSettingsButtonStatesCommon) {\n        if (this.betLevel === 10) {\n            // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n            const c = 0;\n        }\n        this._state = state;\n        this.cursor = 'normal';\n        this.checkForJackpotStamp(state);\n        switch (state) {\n            case BetSettingsButtonStatesCommon.Normal:\n                this.buttonBackground.texture = this.textures.normalTexture;\n                break;\n            case BetSettingsButtonStatesCommon.Hilight:\n                this.buttonBackground.texture = this.textures.hilightTexture;\n                break;\n            case BetSettingsButtonStatesCommon.Over:\n                this.cursor = 'pointer';\n                if (this.textures.overTexture && !this.hilighted) {\n                    this.buttonBackground.texture = this.textures.overTexture;\n                } else if (this.textures.overHilightTexture && this.hilighted) {\n                    this.buttonBackground.texture = this.textures.overHilightTexture;\n                } else {\n                    this.buttonBackground.texture = this.textures.normalTexture;\n                }\n                break;\n            case BetSettingsButtonStatesCommon.Selected:\n                this.killJackpotStamp();\n                this.buttonBackground.texture = this.textures.selectedTexture;\n                break;\n            case BetSettingsButtonStatesCommon.Disabled:\n                if (this.textures.disabledTexture) {\n                    this.buttonBackground.texture = this.textures.disabledTexture;\n                } else {\n                    this.buttonBackground.texture = this.textures.normalTexture;\n                }\n                break;\n            case BetSettingsButtonStatesCommon.MaxBet:\n            case BetSettingsButtonStatesCommon.RestrictedByDenomination:\n                this.tintBtn();\n                break;\n            case BetSettingsButtonStatesCommon.Pressed:\n                if (this.textures.pressedTexture) {\n                    this.buttonBackground.texture = this.textures.pressedTexture;\n                } else {\n                    this.buttonBackground.texture = this.textures.normalTexture;\n                }\n                break;\n        }\n    }\n\n    private tintBtn(): void {\n        if (this.buttonBackground) {\n            this.buttonBackground.tint = 0x797979;\n        }\n        if (this.btnText) {\n            this.btnText.tint = 0x797979;\n        }\n        if (this.currencyText) {\n            this.currencyText.tint = 0x797979;\n        }\n        this.interactive = false;\n        this.cursor = 'normal';\n    }\n\n    private untintBtn(): void {\n        if (this.buttonBackground) {\n            this.buttonBackground.tint = 0xffffff;\n        }\n        if (this.btnText) {\n            this.btnText.tint = 0xffffff;\n        }\n        if (this.currencyText) {\n            this.currencyText.tint = 0xffffff;\n        }\n        if (this.enabled) {\n            this.interactive = true;\n        }\n        this.cursor = 'pointer';\n    }\n}\n\nexport enum BetSettingsButtonStatesCommon {\n    Normal,\n    Hilight,\n    Over,\n    Selected,\n    Disabled,\n    MaxBet,\n    Pressed,\n    RestrictedByDenomination,\n}\n\nexport class BetSettingsButtonTextures {\n    constructor(\n        public normalTexture: Texture,\n        public hilightTexture: Texture,\n        public selectedTexture: Texture,\n        public disabledTexture?: Texture,\n        public overTexture?: Texture,\n        public overHilightTexture?: Texture,\n        public pressedTexture?: Texture,\n    ) {\n        //\n    }\n\n    public updateTextures(\n        normalTexture: Texture,\n        hilightTexture: Texture,\n        selectedTexture: Texture,\n        disabledTexture?: Texture,\n        overTexture?: Texture,\n        overHilightTexture?: Texture,\n        pressedTexture?: Texture,\n    ): void {\n        this.normalTexture = normalTexture;\n        this.hilightTexture = hilightTexture;\n        this.selectedTexture = selectedTexture;\n        if (disabledTexture) {\n            this.disabledTexture = disabledTexture;\n        }\n        if (overTexture) {\n            this.overTexture = overTexture;\n        }\n        if (overHilightTexture) {\n            this.overHilightTexture = overHilightTexture;\n        }\n        if (pressedTexture) {\n            this.pressedTexture = pressedTexture;\n        }\n    }\n\n    public destroy() {\n        this.normalTexture.destroy();\n        // @ts-ignore\n        this.normalTexture = null;\n\n        this.hilightTexture.destroy();\n        // @ts-ignore\n        this.hilightTexture = null;\n\n        this.selectedTexture.destroy();\n        // @ts-ignore\n        this.selectedTexture = null;\n\n        if (this.disabledTexture) {\n            this.disabledTexture.destroy();\n            // @ts-ignore\n            this.disabledTexture = null;\n        }\n\n        if (this.overTexture) {\n            this.overTexture.destroy();\n            // @ts-ignore\n            this.overTexture = null;\n        }\n\n        if (this.pressedTexture) {\n            this.pressedTexture.destroy();\n            // @ts-ignore\n            this.pressedTexture = null;\n        }\n    }\n}\n","import BetCalculatorComponent from './BetCalculatorComponent';\nimport {\n    IBetCalculatorInterface,\n    IBetsLayoutConfig,\n    IAdditionalText,\n    IDenominationPopUpBtnsText,\n    IDenominationPopUpPositions,\n    IRowsBackgroundPositions,\n    IJackpotLabel,\n} from './common/interfaces/InterfacesCommon';\nimport BetCalculatorComponentConfigurationDefault from './modes/default/configuration/BetCalculatorComponentConfigurationDefault';\nimport BetCalculatorControllerDefault from './modes/default/controllers/BetCalculatorControllerDefault';\nimport BetCalculatorViewDefault from './modes/default/views/BetCalculatorViewDefault';\nimport BetCalculatorComponentConfigurationTurtle from './modes/turtle/configuration/BetCalculatorComponentConfigurationTurtle';\nimport BetCalculatorControllerTurtle from './modes/turtle/controllers/BetCalculatorControllerTurtle';\nimport BetCalculatorViewTurtle from './modes/turtle/views/BetCalculatorViewTurtle';\nimport { IBetCalculatorComponentConfigurationDefault } from './modes/default/interfaces/InterfacesDefault';\nimport { IBetCalculatorComponentConfigurationTurtle } from './modes/turtle/interfaces/InterfacesTurtle';\nimport { BetCalculatorModes } from './BetCalculatorFactory';\n\nexport {\n    IBetCalculatorComponentConfigurationDefault,\n    IBetCalculatorComponentConfigurationTurtle,\n    IBetCalculatorInterface,\n    BetCalculatorComponentConfigurationDefault,\n    BetCalculatorComponentConfigurationTurtle,\n    BetCalculatorControllerDefault,\n    BetCalculatorControllerTurtle,\n    BetCalculatorViewDefault,\n    BetCalculatorViewTurtle,\n    IAdditionalText,\n    IDenominationPopUpBtnsText,\n    IDenominationPopUpPositions,\n    IRowsBackgroundPositions,\n    IJackpotLabel,\n    IBetsLayoutConfig,\n    BetCalculatorModes,\n};\nexport default BetCalculatorComponent;\n","import {\n    AssetPriority,\n    AssetsCollection,\n    BaseComponentConfiguration,\n    DefaultAssets,\n    DefaultValue,\n    DynamicPositionObject,\n} from '@egt/core';\nimport { TextStyle } from 'pixi.js';\nimport {\n    IAdditionalText,\n    IDenominationPopUpBtnsText,\n    IDenominationPopUpPositions,\n    IRowsBackgroundPositions,\n} from '../../../common/interfaces/InterfacesCommon';\nimport { IBetCalculatorComponentConfigurationDefault } from '../interfaces/InterfacesDefault';\n\nexport default class BetCalculatorComponentConfigurationDefault extends BaseComponentConfiguration {}\nexport function BetCalculatorComponentConfigurationFactoryDefault(): any {\n    class BetCalculatorComponentConfigurationDefaultInternalClass\n        extends BetCalculatorComponentConfigurationDefault\n        implements IBetCalculatorComponentConfigurationDefault\n    {\n        public buttonsToHide = ['betButtons', 'denominationButton'];\n\n        public mainViewComponentsToHide = ['balanceContainer', 'winContainer'];\n\n        @DefaultAssets([\n            {\n                id: 'calculatorResources',\n                url: '../assets/components/slot/bet-calculator/common/calculatorResources.json',\n                priority: AssetPriority.HIGHEST,\n                type: 'texture',\n            },\n            {\n                id: 'svgDenominationPopUpNormal',\n                url: '../assets/components/slot/bet-calculator/default/ui-svg/denominationPopUpNormal.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n            },\n            {\n                id: 'svgDenominationPopUpPressed',\n                url: '../assets/components/slot/bet-calculator/default/ui-svg/denominationPopUpPressed.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n            },\n            {\n                id: 'svgDenominationPopUpFocus',\n                url: '../assets/components/slot/bet-calculator/default/ui-svg/denominationPopUpFocus.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n            },\n            {\n                id: 'svgDenominationPopUpSelected',\n                url: '../assets/components/slot/bet-calculator/default/ui-svg/denominationPopUpSelected.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n            },\n            {\n                id: 'svgDenominationPopUpHover',\n                url: '../assets/components/slot/bet-calculator/default/ui-svg/denominationPopUpHover.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n            },\n        ])\n        public assets: AssetsCollection;\n\n        @DefaultValue<IAdditionalText>({\n            defaults: {\n                x: 503,\n                hasAdditionalText: false,\n                lines: false,\n                valueStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold',\n                    fontSize: 32,\n                    lineHeight: 32,\n                    fill: '#A3A3A3',\n                    align: 'center',\n                }),\n                textStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold',\n                    fontSize: 17,\n                    lineHeight: 17,\n                    fill: '#A3A3A3',\n                    align: 'center',\n                }),\n                selectedFill: '#FFFFFF',\n                textYOffset: -2,\n            },\n            portrait: {\n                x: 70,\n            },\n        })\n        public additionalText: DynamicPositionObject<IAdditionalText> & IAdditionalText;\n\n        @DefaultValue<IDenominationPopUpBtnsText>({\n            defaults: {\n                x: 0,\n                y: 0,\n                width: 134,\n                height: 78,\n                widthBounds: 120,\n                shouldFitInBounds: true,\n                valueOffset: 10,\n                currencyOffset: 25.5,\n                currencyValueGap: 10,\n                normalTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    fontSize: 47,\n                    lineHeight: 47,\n                    fill: '#C6C5C5',\n                    align: 'center',\n                    trim: true,\n                }),\n                hilightedTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    fontSize: 47,\n                    lineHeight: 47,\n                    fill: '#FFFFFF',\n                    align: 'center',\n                    trim: true,\n                }),\n                currencyNormalTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                    fontSize: 20,\n                    lineHeight: 20,\n                    fill: '#FFD200',\n                    align: 'center',\n                    letterSpacing: 0.4,\n                    trim: true,\n                }),\n                currencyHilightedTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                    fontSize: 20,\n                    lineHeight: 20,\n                    fill: '#FFD200',\n                    align: 'center',\n                    letterSpacing: 0.4,\n                    trim: true,\n                }),\n                normalTextures: ['svgBet', 'svgBetPressed', 'svgBet', 'svgBet'],\n                hilightedTextures: ['svgBetBlue', 'svgBetBluePressed', 'svgBetBlue', 'svgBetBlue'],\n            },\n        })\n        public popUpButtonsText: DynamicPositionObject<IDenominationPopUpBtnsText> & IDenominationPopUpBtnsText;\n\n        /**\n         * Positions are based on 6 denomination preview.\n         * When there are fewer than 6 denominations the prop mainContainerPosition is used to move the whole container.\n         */\n        public rowsBackgroundPositions: Array<DynamicPositionObject<IRowsBackgroundPositions>> = [\n            new DynamicPositionObject<IRowsBackgroundPositions>({\n                defaults: { x: 466, y: 83, width: 704, height: 86 },\n                portrait: { x: 30, y: 259, width: 704, height: 86 },\n            }),\n            new DynamicPositionObject<IRowsBackgroundPositions>({\n                defaults: { x: 466, y: 171, width: 704, height: 86 },\n                portrait: { x: 30, y: 347, width: 704, height: 86 },\n            }),\n            new DynamicPositionObject<IRowsBackgroundPositions>({\n                defaults: { x: 466, y: 259, width: 704, height: 86 },\n                portrait: { x: 30, y: 435, width: 704, height: 86 },\n            }),\n            new DynamicPositionObject<IRowsBackgroundPositions>({\n                defaults: { x: 466, y: 347, width: 704, height: 86 },\n                portrait: { x: 30, y: 523, width: 704, height: 86 },\n            }),\n            new DynamicPositionObject<IRowsBackgroundPositions>({\n                defaults: { x: 466, y: 435, width: 704, height: 86 },\n                portrait: { x: 30, y: 611, width: 704, height: 86 },\n            }),\n            new DynamicPositionObject<IRowsBackgroundPositions>({\n                defaults: { x: 466, y: 523, width: 704, height: 86 },\n                portrait: { x: 30, y: 699, width: 704, height: 86 },\n            }),\n            new DynamicPositionObject<IRowsBackgroundPositions>({\n                defaults: { x: 466, y: 611, width: 704, height: 86 },\n                portrait: { x: 30, y: 787, width: 704, height: 86 },\n            }),\n        ];\n\n        public selectedRowsBackgroundPositions: Array<DynamicPositionObject<IRowsBackgroundPositions>> = [\n            new DynamicPositionObject<IRowsBackgroundPositions>({\n                defaults: { x: 466, y: 83, width: 704, height: 86 },\n                portrait: { x: 30, y: 259, width: 704, height: 86 },\n            }),\n            new DynamicPositionObject<IRowsBackgroundPositions>({\n                defaults: { x: 466, y: 171, width: 704, height: 86 },\n                portrait: { x: 30, y: 347, width: 704, height: 86 },\n            }),\n            new DynamicPositionObject<IRowsBackgroundPositions>({\n                defaults: { x: 466, y: 259, width: 704, height: 86 },\n                portrait: { x: 30, y: 435, width: 704, height: 86 },\n            }),\n            new DynamicPositionObject<IRowsBackgroundPositions>({\n                defaults: { x: 466, y: 347, width: 704, height: 86 },\n                portrait: { x: 30, y: 523, width: 704, height: 86 },\n            }),\n            new DynamicPositionObject<IRowsBackgroundPositions>({\n                defaults: { x: 466, y: 435, width: 704, height: 86 },\n                portrait: { x: 30, y: 611, width: 704, height: 86 },\n            }),\n            new DynamicPositionObject<IRowsBackgroundPositions>({\n                defaults: { x: 466, y: 523, width: 704, height: 86 },\n                portrait: { x: 30, y: 699, width: 704, height: 86 },\n            }),\n            new DynamicPositionObject<IRowsBackgroundPositions>({\n                defaults: { x: 466, y: 611, width: 704, height: 86 },\n                portrait: { x: 30, y: 787, width: 704, height: 86 },\n            }),\n        ];\n\n        public betBtnPositions: Array<DynamicPositionObject<IDenominationPopUpPositions>> = [\n            new DynamicPositionObject<IDenominationPopUpPositions>({\n                defaults: { x: 469 },\n                portrait: { x: 31 },\n            }),\n            new DynamicPositionObject<IDenominationPopUpPositions>({\n                defaults: { x: 611 },\n                portrait: { x: 173 },\n            }),\n            new DynamicPositionObject<IDenominationPopUpPositions>({\n                defaults: { x: 753 },\n                portrait: { x: 315 },\n            }),\n            new DynamicPositionObject<IDenominationPopUpPositions>({\n                defaults: { x: 895 },\n                portrait: { x: 457 },\n            }),\n            new DynamicPositionObject<IDenominationPopUpPositions>({\n                defaults: { x: 1037 },\n                portrait: { x: 599 },\n            }),\n        ];\n    }\n    return BetCalculatorComponentConfigurationDefaultInternalClass;\n}\n","import { BuyBonusModes } from '@egt/buy-bonus';\nimport Core, { BaseController, Timers } from '@egt/core';\nimport { FeatureController, ISlotConfiguration, RootStore, SlotComponents, UIState } from '@egt/slot';\nimport { fromEvent } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport BetCalculatorViewDefault from '../views/BetCalculatorViewDefault';\nimport { IBetCalculatorComponentConfigurationDefault } from '../interfaces/InterfacesDefault';\nimport BetSettingButtonCommon, { BetSettingsButtonStatesCommon } from '../../../common/buttons/BetSettingButtonCommon';\n\n@injectable()\nexport default class BetCalculatorController extends BaseController {\n    constructor(\n        @inject('BetCalculator') protected betCalculator: BetCalculatorViewDefault,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('BetCalculatorComponentConfiguration')\n        protected componentConfiguration: IBetCalculatorComponentConfigurationDefault,\n        @inject('FeatureController') protected feature: FeatureController,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n    ) {\n        super(betCalculator);\n    }\n\n    public destroy(): void {\n        super.destroy();\n    }\n\n    public init(): void {\n        this.attachEventListeners();\n    }\n\n    public attachEventListeners(): void {\n        this.addBetButtonsEventListeners();\n\n        this.rootStore.subjects.DENOMINATIONS_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onDenominationsChanged.bind(this),\n        );\n\n        this.rootStore.uiStore.SELECTED_BET.pipe(takeUntil(this.DESTROY)).subscribe(this.onBetChanged.bind(this));\n        this.rootStore.subjects.SETTINGS_DENOMINATION_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onDenominationChanged.bind(this, true),\n        );\n\n        this.rootStore.subjects.FACTOR_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(this.onFactorChanged.bind(this));\n        this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onExtendedMultipleBuyBonusActivated.bind(this),\n        );\n\n        this.rootStore.uiStore.STATE.pipe(takeUntil(this.DESTROY)).subscribe(this.stateChanged.bind(this));\n    }\n\n    protected onFactorChanged(): void {\n        if (this.componentConfiguration.additionalText.lines) {\n            return;\n        }\n        // this.betCalculator.updateBetValue();\n        for (const betButtons of this.betCalculator.betButtons) {\n            for (const betButton of betButtons) {\n                betButton.factor = this.rootStore.settings.factor;\n            }\n        }\n    }\n\n    protected onExtendedMultipleBuyBonusActivated(value: boolean): void {\n        if (\n            this.rootStore.settings.haveGameMode('DOUBLE_CHANCE') &&\n            this.rootStore.settings.factor === this.rootStore.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE')\n        ) {\n            value = false;\n        }\n        for (const betButtons of this.betCalculator.betButtons) {\n            for (const betButton of betButtons) {\n                betButton.buyBonusActivated = value;\n            }\n        }\n    }\n\n    protected updateBet(betBtn: BetSettingButtonCommon, dispatchedFromPopup: boolean) {\n        if (betBtn) {\n            Core.SELECTED_DENOMINATION.next(betBtn.denominationLevel);\n            this.rootStore.uiStore.SELECTED_BET.next(betBtn.betLevel);\n            if (\n                !(\n                    this.rootStore.uiStore.CURRENT_BET_LEVEL.value.betLevel === betBtn.betLevel &&\n                    this.rootStore.uiStore.CURRENT_BET_LEVEL.value.denomLevel === betBtn.denominationLevel\n                )\n            ) {\n                this.rootStore.uiStore.CURRENT_BET_LEVEL.next({\n                    betLevel: this.rootStore.uiStore.SELECTED_BET.value,\n                    denomLevel: Core.SELECTED_DENOMINATION.value,\n                });\n            }\n            this.rootStore.subjects.SETTINGS_BET_CHANGED.next();\n\n            if (dispatchedFromPopup) {\n                Timers.setTimeout(() => {\n                    this.rootStore.subjects.CLOSE_DENOMINATION_POPUP.next();\n                    Core.UI_BLOCKER.next(false);\n                }, 300);\n            }\n        }\n    }\n\n    protected stateChanged(): void {\n        for (const betButtons of this.betCalculator.betButtons) {\n            for (const betButton of betButtons) {\n                betButton.enabled = !this.feature.isInGiftSpins;\n\n                if (betButton.state === BetSettingsButtonStatesCommon.Selected) {\n                    betButton.enabled = true;\n                }\n            }\n        }\n    }\n\n    private onDenominationsChanged(): void {\n        this.betCalculator.onDenominationsChanged();\n        this.addBetButtonsEventListeners();\n    }\n\n    private addBetButtonsEventListeners() {\n        for (const betButtons of this.betCalculator.betButtons) {\n            for (const betButton of betButtons) {\n                betButton.CLICK.pipe(takeUntil(this.DESTROY)).subscribe((btn: BetSettingButtonCommon) => {\n                    Core.sounds.play('changeBetSound');\n                    this.onBetOptionButtonClicked(btn, true);\n                });\n\n                (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/bet-calculator/src/egt/modes/default/controllers/BetCalculatorControllerDefault.ts:129:17\",(betButton),\"pointerup\"]), fromEvent(betButton, 'pointerup'))\n                    .pipe(takeUntil(this.DESTROY))\n                    .subscribe(this.onBetOptionButtonReleased.bind(this));\n\n                (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/bet-calculator/src/egt/modes/default/controllers/BetCalculatorControllerDefault.ts:133:17\",(betButton),\"pointerupoutside\"]), fromEvent(betButton, 'pointerupoutside'))\n                    .pipe(takeUntil(this.DESTROY))\n                    .subscribe(this.onBetOptionButtonReleased.bind(this));\n\n                fromEvent(betButton, 'pointerout')\n                    .pipe(takeUntil(this.DESTROY))\n                    .subscribe(this.onBetOptionButtonReleased.bind(this));\n\n                (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/bet-calculator/src/egt/modes/default/controllers/BetCalculatorControllerDefault.ts:141:17\",(betButton),\"pointerdown\"]), fromEvent(betButton, 'pointerdown'))\n                    .pipe(takeUntil(this.DESTROY))\n                    .subscribe(this.onBetOptionButtonPressed.bind(this));\n            }\n        }\n    }\n\n    private onDenominationChanged(_dispatchedFromSettings: boolean = false, data: any): void {\n        if (data.playDenomChangeSound) {\n            Core.sounds.play('changeDenominationSound');\n        }\n        Core.SELECTED_DENOMINATION.next(this.rootStore.uiStore.denominations[data.denomination - 1]);\n        // this.rootStore.uiStore.CURRENT_BET_LEVEL.next({\n        //     betLevel: this.rootStore.uiStore.SELECTED_BET.value,\n        //     denomLevel: Core.SELECTED_DENOMINATION.value,\n        // });\n        this.onExtendedMultipleBuyBonusActivated(this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value);\n    }\n\n    private onBetChanged(): void {\n        this.betCalculator.resetCalculatorPopUp();\n    }\n\n    private onBetOptionButtonPressed(betButton: any): void {\n        for (let i: number = 0; i < this.betCalculator.betButtons.length; i++) {\n            for (const betBtn of this.betCalculator.betButtons[i]) {\n                if (betButton.currentTarget === betBtn) {\n                    this.betCalculator.animateDownScaleBtn(betBtn);\n                }\n            }\n        }\n    }\n\n    private onBetOptionButtonReleased(betButton: any): void {\n        for (let i: number = 0; i < this.betCalculator.betButtons.length; i++) {\n            for (const betBtn of this.betCalculator.betButtons[i]) {\n                if (betButton.currentTarget === betBtn) {\n                    this.betCalculator.animateUpScaleBtn(betBtn, i);\n                }\n            }\n        }\n    }\n\n    private onBetOptionButtonClicked(betButton: BetSettingButtonCommon, dispatchedFromPopup: boolean): void {\n        if (this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_RESPONSE || this.isInBonusOrGiftSpins()) {\n            return;\n        }\n        Core.UI_BLOCKER.next(true);\n        if (dispatchedFromPopup) {\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'spinSpeedButton',\n                actions: 'visible',\n                values: true,\n            });\n\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'spinSpeedButtonDisabled',\n                actions: 'visible',\n                values: false,\n            });\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'instaSpinsButton',\n                actions: 'enabled',\n                values: true,\n            });\n        }\n        for (let i: number = 0; i < this.betCalculator.betButtons.length; i++) {\n            for (const betBtn of this.betCalculator.betButtons[i]) {\n                if (betButton === betBtn) {\n                    if (!Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS)) {\n                        this.rootStore.subjects.DISABLED_BUY_BONUS.next({\n                            disabled: this.checkForMaxBet(betBtn.betLevel, betBtn.denominationLevel),\n                            doNotChangeVisual: false,\n                        });\n                    }\n                    Timers.setTimeout(() => {\n                        this.betCalculator.updateSelectedRow(i, betBtn);\n                        betBtn.setPressed();\n                    }, 10);\n\n                    Timers.setTimeout(() => {\n                        if (this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_RESPONSE) {\n                            return;\n                        }\n                        betBtn.setSelected();\n                        this.updateBet(betButton, dispatchedFromPopup);\n                    }, 100);\n                }\n            }\n        }\n        // if (!this.betCalculator.isInteractive) {\n        //     this.betCalculator.isInteractive = true;\n        // }\n    }\n\n    private checkForMaxBet(bet: number, denomination: number): boolean {\n        let buyBonusValue: number =\n            denomination *\n            bet *\n            (this.rootStore.settings.factors[this.rootStore.settings.factors.length - 1] /\n                this.rootStore.uiStore.units);\n\n        if (this.rootStore.settings.clientSettings?.maxBetLimits || this.rootStore.settings.maxBet) {\n            const maxBetForBonus: number = Math.min(\n                this.rootStore.settings.clientSettings?.maxBetLimits\n                    ? this.rootStore.settings.clientSettings?.maxBetLimits[Core.PLAYER_BALANCE.value.currency]\n                    : Infinity,\n                this.rootStore.settings.maxBet ?? Infinity,\n            );\n            if (maxBetForBonus && buyBonusValue > maxBetForBonus) {\n                buyBonusValue = maxBetForBonus;\n                return true;\n            }\n        }\n        return false;\n    }\n\n    private isInBonusOrGiftSpins() {\n        return this.rootStore.uiStore.STATE.value === UIState.BONUS_IDLE || this.feature.isInGiftSpins;\n    }\n}\n","import { BuyBonusModes } from '@egt/buy-bonus';\nimport Core, { Money } from '@egt/core';\nimport { Features, ISlotConfiguration, InitialSettings, RootStore, SlotComponents } from '@egt/slot';\nimport { ViewContainer } from '@egt/ui-lib';\nimport { gsap } from 'gsap';\nimport { Container, NineSlicePlane, Sprite, Text, TextStyle, Texture } from 'pixi.js';\nimport { BehaviorSubject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport BetSettingButtonCommon, { BetSettingsButtonTextures } from '../../../common/buttons/BetSettingButtonCommon';\nimport { IBetCalculatorComponentConfigurationDefault } from '../interfaces/InterfacesDefault';\n\n@injectable()\nexport default class BetCalculatorViewDefault extends ViewContainer {\n    public readonly UPDATE_BET: BehaviorSubject<BetSettingButtonCommon | null> = new BehaviorSubject(null);\n\n    public oneDenomView: boolean = false;\n\n    public mainContainer: Container;\n\n    public betButtons: Array<Array<BetSettingButtonCommon>> = [];\n\n    protected pressingAnimation: gsap.core.Timeline | null;\n\n    public globalPosition: { x: number; y: number } = { x: 0, y: 0 };\n\n    private betBtnTextures: Map<string, Texture> = new Map();\n\n    private rowsBackgrounds: Array<Container | NineSlicePlane> = [];\n    private rowsBackgroundsSelected: NineSlicePlane[] = [];\n    private betContainer: Sprite;\n    private balanceMoneyFormatter: Money;\n    private betMoneyFormatter: Money;\n    private animationTween: any;\n    private additionalNumber: Text[] = [];\n    private additionalText: Text[] = [];\n    private isMysteryJackpot: boolean = false;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected configuration: ISlotConfiguration,\n        @inject('BetCalculatorComponentConfiguration')\n        protected componentConfiguration: IBetCalculatorComponentConfigurationDefault,\n        @inject('InitialSettings') protected settings: InitialSettings,\n    ) {\n        super();\n        this.isMysteryJackpot =\n            Core.hasFeature(Features.MYSTERY_JACKPOT) ||\n            Core.game?.features?.filter((feature) => feature.featureType.includes('_JACKPOT')).length === 0;\n\n        if (this.rootStore.uiStore.bets.length > this.componentConfiguration.betBtnPositions.length) {\n            this.oneDenomView = true;\n        }\n    }\n\n    public init(): void {\n        // this.isOpened = false;\n        this.createBtnsTextures();\n        this.createDenominationPopUp();\n\n        Core.LEFT_HAND_MODE.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n\n        this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.changeBtnsTextures();\n            this.resetAllButtonsFontSize();\n            this.setOrientation();\n        });\n        Core.SELECTED_DENOMINATION.pipe(takeUntil(Core.ON_GAME_UNLOADED)).subscribe((denomination) => {\n            if (\n                this.rootStore.settings.numberOfLinesPerDenomination &&\n                this.rootStore.settings.numberOfLinesPerDenomination.length\n            ) {\n                this.changeNumberOfLines(denomination);\n            }\n        });\n    }\n\n    public destroy(): void {\n        this.killAllAnimations();\n\n        if (this.betButtons) {\n            this.betButtons.forEach((betBtns) => {\n                this.destroyArray(betBtns);\n            });\n            // @ts-ignore\n            this.betButtons = null;\n        }\n        this.destroyObjects();\n        this.destroyObject(this.animationTween);\n        this.removeChildren();\n        super.destroy();\n    }\n\n    private destroyObjects() {\n        this.destroyObject(this.betContainer);\n        this.destroyObject(this.balanceMoneyFormatter);\n        this.destroyObject(this.betMoneyFormatter);\n\n        this.destroyArray(this.additionalNumber);\n        this.destroyArray(this.additionalText);\n        this.destroyArray(this.rowsBackgrounds);\n        this.destroyArray(this.rowsBackgroundsSelected);\n    }\n\n    private createBtnsTextures(): void {\n        this.betBtnTextures.set('Normal', Core.assets.getAsset('svgDenominationPopUpNormal').texture);\n        this.betBtnTextures.set('Focus', Core.assets.getAsset('svgDenominationPopUpFocus').texture);\n        this.betBtnTextures.set('Selected', Core.assets.getAsset('svgDenominationPopUpSelected').texture);\n        this.betBtnTextures.set('Disabled', Core.assets.getAsset('svgDenominationPopUpNormal').texture);\n        this.betBtnTextures.set('Hover', Core.assets.getAsset('svgDenominationPopUpHover').texture);\n        this.betBtnTextures.set('Pressed', Core.assets.getAsset('svgDenominationPopUpPressed').texture);\n\n        if (Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS)) {\n            this.betBtnTextures.set('NormalSpecial', Core.assets.getAsset('svgDenominationPopUpNormalSpecial').texture);\n            this.betBtnTextures.set('FocusSpecial', Core.assets.getAsset('svgDenominationPopUpFocusSpecial').texture);\n            this.betBtnTextures.set(\n                'SelectedSpecial',\n                Core.assets.getAsset('svgDenominationPopUpSelectedSpecial').texture,\n            );\n            this.betBtnTextures.set(\n                'DisabledSpecial',\n                Core.assets.getAsset('svgDenominationPopUpNormalSpecial').texture,\n            );\n            this.betBtnTextures.set('HoverSpecial', Core.assets.getAsset('svgDenominationPopUpHoverSpecial').texture);\n            this.betBtnTextures.set(\n                'PressedSpecial',\n                Core.assets.getAsset('svgDenominationPopUpPressedSpecial').texture,\n            );\n        }\n    }\n\n    public changeBtnsTextures() {\n        const textureType: string = this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value\n            ? 'Special'\n            : '';\n        for (const betButtonRow of this.betButtons) {\n            for (const betButton of betButtonRow) {\n                betButton.updateTextures(\n                    this.betBtnTextures.get('Normal' + textureType) as Texture,\n                    this.betBtnTextures.get('Focus' + textureType) as Texture,\n                    this.betBtnTextures.get('Selected' + textureType) as Texture,\n                    this.betBtnTextures.get('Disabled' + textureType) as Texture,\n                    this.betBtnTextures.get('Hover' + textureType) as Texture,\n                    this.betBtnTextures.get('Pressed' + textureType) as Texture,\n                );\n            }\n        }\n    }\n\n    public onDenominationsChanged() {\n        // const wasOpen = this.isOpened;\n        this.removeChildren();\n        if (this.betButtons.length) {\n            this.betButtons.forEach((buttonRow) => {\n                buttonRow.length = 0;\n            });\n            this.betButtons.length = 0;\n        }\n        this.additionalNumber = [];\n        this.additionalText = [];\n        this.rowsBackgrounds = [];\n        this.rowsBackgroundsSelected = [];\n\n        this.createDenominationPopUp();\n\n        // if (wasOpen) {\n        //     this.open(false);\n        // } else {\n        //     this.close(false);\n        // }\n        this.setOrientation();\n        this.resetCalculatorPopUp();\n    }\n\n    public animateDownScaleBtn(betBtn: BetSettingButtonCommon) {\n        this.killPressingAnimation();\n\n        betBtn.scale.set(1);\n        betBtn.children[0].alpha = 0.4;\n        const scale = 0.9;\n\n        this.pressingAnimation = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/bet-calculator/src/egt/modes/default/views/BetCalculatorViewDefault.ts:183:34\",null]), gsap.timeline()).to(\n            betBtn.scale,\n            {\n                x: scale,\n                y: scale,\n                duration: 0.15,\n                ease: 'power4.out',\n            },\n            '<',\n        );\n    }\n\n    public animateUpScaleBtn(betBtn: BetSettingButtonCommon, _rowIndex: number) {\n        if (betBtn.scale.x === 1) {\n            return;\n        }\n        this.killPressingAnimation();\n\n        this.pressingAnimation = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/bet-calculator/src/egt/modes/default/views/BetCalculatorViewDefault.ts:201:34\",null]), gsap\n            .timeline())\n            .to(betBtn.children[0], {\n                alpha: 1,\n                duration: 0.15,\n            })\n            .to(\n                betBtn.scale,\n                {\n                    x: 1,\n                    y: 1,\n                    duration: 0.1,\n                    ease: 'power4.in',\n                    onComplete: () => {\n                        betBtn.children[0].alpha = 1;\n                        this.killPressingAnimation();\n                    },\n                },\n                '<',\n            );\n    }\n\n    public resetCalculatorPopUp(): void {\n        let denomIndex = this.rootStore.uiStore.denominations.indexOf(Core.SELECTED_DENOMINATION.value);\n        let betIndex = this.rootStore.uiStore.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value);\n        if (this.oneDenomView) {\n            const betLength = this.componentConfiguration.betBtnPositions.length;\n            denomIndex = Math.floor(betIndex / betLength);\n            betIndex = betIndex % betLength;\n        }\n        const button: BetSettingButtonCommon = this.betButtons[denomIndex][betIndex];\n        this.updateSelectedRow(denomIndex, button);\n        button.setSelected();\n        if (this.oneDenomView) {\n            button.setHilighted();\n            button.setSelected();\n        }\n    }\n\n    public updateSelectedRow(rowIndex: number, _betButton: BetSettingButtonCommon): void {\n        this.deselectAllRows();\n        this.deselectAllButtons();\n        this.rowsBackgrounds[rowIndex].visible = false;\n        if (!this.oneDenomView) {\n            for (const btn of this.betButtons[rowIndex]) {\n                btn.setHilighted();\n            }\n        }\n        if (!this.isMysteryJackpot) {\n            this.rowsBackgroundsSelected[rowIndex].visible = true;\n        }\n\n        this.setAdditionalTextSelectedFill(rowIndex);\n        this.setOrientation();\n    }\n\n    private setAdditionalTextSelectedFill(rowIndex: number) {\n        if (this.componentConfiguration.additionalText.hasAdditionalText) {\n            const valueStyle = new TextStyle(this.componentConfiguration.additionalText.valueStyle);\n            valueStyle.fill = this.componentConfiguration.additionalText.selectedFill;\n            this.additionalNumber[rowIndex].style = valueStyle;\n\n            const textStyle = new TextStyle(this.componentConfiguration.additionalText.textStyle);\n            textStyle.fill = this.componentConfiguration.additionalText.selectedFill;\n            this.additionalText[rowIndex].style = textStyle;\n        }\n    }\n\n    private createAdditionalText(denominationIndex: number, _selectedRow: boolean): void {\n        this.additionalNumber[denominationIndex] = new Text(\n            this.componentConfiguration.additionalText.lines\n                ? (this.rootStore.settings.numberOfLinesPerDenomination?.[denominationIndex][1] ??\n                      denominationIndex + 1)\n                : denominationIndex + 1,\n            this.componentConfiguration.additionalText.valueStyle,\n        );\n        this.additionalNumber[denominationIndex].resolution = 2;\n        this.additionalNumber[denominationIndex].anchor.set(0.5);\n        this.addChild(this.additionalNumber[denominationIndex]);\n\n        this.additionalText[denominationIndex] = new Text(\n            this.componentConfiguration.additionalText.lines\n                ? Core.translator.translate('LINES')\n                : Core.translator.translate('LEVEL'),\n            this.componentConfiguration.additionalText.textStyle,\n        );\n        this.additionalText[denominationIndex];\n        this.additionalText[denominationIndex].resolution = 2;\n        this.additionalText[denominationIndex].anchor.set(0.5);\n        this.addChild(this.additionalText[denominationIndex]);\n\n        this.setAdditionalTextSelectedFill(denominationIndex);\n\n        const rowsPositionOffset =\n            this.componentConfiguration.rowsBackgroundPositions.length - this.rowsBackgrounds.length;\n        const rowPosition =\n            this.componentConfiguration.rowsBackgroundPositions[denominationIndex + rowsPositionOffset].get('x');\n        const firstBetPosition = this.componentConfiguration.betBtnPositions[0].get('x');\n\n        if (this.additionalText[denominationIndex].width > firstBetPosition - rowPosition) {\n            this.additionalText[denominationIndex].scale.set(\n                (firstBetPosition - rowPosition) / this.additionalText[denominationIndex].width,\n            );\n        }\n    }\n\n    private createDenominationPopUp(): void {\n        let cols = this.rootStore.uiStore.bets.length;\n        let rows = this.rootStore.uiStore.denominations.length;\n        if (this.rootStore.uiStore.bets.length > this.componentConfiguration.betBtnPositions.length) {\n            const filteredBets = this.filterBets();\n            cols = this.componentConfiguration.betBtnPositions.length;\n            rows = Math.ceil(filteredBets.length / this.componentConfiguration.betBtnPositions.length);\n            this.oneDenomView = true;\n        }\n        for (let i: number = 0; i < rows; i++) {\n            let rowBackground;\n            if (this.isMysteryJackpot) {\n                rowBackground = new Container();\n            } else {\n                rowBackground = new NineSlicePlane(\n                    Core.assets.getTextureFromSpriteSheet('calculatorResources', 'popupFill.png'),\n                    25,\n                    25,\n                    25,\n                    25,\n                );\n            }\n            this.addChild(rowBackground);\n            this.rowsBackgrounds.push(rowBackground);\n            if (!this.isMysteryJackpot) {\n                const rowsBackgroundsSelected = new NineSlicePlane(\n                    Core.assets.getTextureFromSpriteSheet('calculatorResources', 'popupFillSelected.png'),\n                    25,\n                    25,\n                    25,\n                    25,\n                );\n                this.addChild(rowsBackgroundsSelected);\n                this.rowsBackgroundsSelected.push(rowsBackgroundsSelected);\n            }\n\n            let selectedRow: boolean = false;\n\n            if (Core.SELECTED_DENOMINATION.value === this.rootStore.uiStore.denominations[i]) {\n                selectedRow = true;\n                rowBackground.visible = false;\n                if (!this.isMysteryJackpot) {\n                    this.rowsBackgroundsSelected[i].visible = true;\n                }\n            } else {\n                rowBackground.visible = true;\n                if (!this.isMysteryJackpot) {\n                    this.rowsBackgroundsSelected[i].visible = false;\n                }\n            }\n\n            if (this.componentConfiguration.additionalText.hasAdditionalText) {\n                this.createAdditionalText(i, selectedRow);\n            }\n            this.betButtons.push([]);\n\n            const startIdx = this.oneDenomView ? i * cols : 0;\n            const endIdx = startIdx + cols;\n\n            for (let t: number = startIdx; t < endIdx && t < this.rootStore.uiStore.bets.length; t++) {\n                let selectedButton: boolean = false;\n                if (this.rootStore.uiStore.SELECTED_BET.value === this.rootStore.uiStore.bets[t] && selectedRow) {\n                    selectedButton = true;\n                }\n\n                const denomIndex = this.oneDenomView ? 0 : i;\n                this.createBetButtons(i, t, selectedRow, selectedButton, denomIndex);\n            }\n        }\n    }\n\n    private filterBets(): number[] {\n        return this.rootStore.uiStore.bets.filter((bet) => {\n            return (\n                (bet * this.rootStore.uiStore.denominations[0] * this.rootStore.settings.factor) /\n                    this.rootStore.settings.units <=\n                this.getMaxBet(this.rootStore.settings.factor)\n            );\n        });\n    }\n\n    private getMaxBet(factor: number): number {\n        const maxBetLimits = this.rootStore.settings.clientSettings?.maxBetLimits?.hasOwnProperty(\n            this.rootStore.settings.currency,\n        )\n            ? this.rootStore.settings.clientSettings.maxBetLimits[this.rootStore.settings.currency]\n            : undefined;\n        const isDoubleChanceFactor =\n            this.rootStore.settings.haveGameMode('DOUBLE_CHANCE') &&\n            factor === this.rootStore.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE');\n        const maxBet =\n            maxBetLimits && !isDoubleChanceFactor && this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value\n                ? maxBetLimits\n                : Infinity;\n        const maxJurisdictionalBet = this.rootStore.settings.maxBet ? this.rootStore.settings.maxBet : Infinity;\n\n        return Math.min(maxBet, maxJurisdictionalBet);\n    }\n\n    private createBetButtons(\n        rowIndex: number,\n        colIndex: number,\n        selectedRow: boolean,\n        selectedButton: boolean,\n        denomIndex: number,\n    ): void {\n        const textureType: string = this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value\n            ? 'Special'\n            : '';\n\n        const btnTextures: BetSettingsButtonTextures = new BetSettingsButtonTextures(\n            this.betBtnTextures.get('Normal' + textureType) as Texture,\n            this.betBtnTextures.get('Focus' + textureType) as Texture,\n            this.betBtnTextures.get('Selected' + textureType) as Texture,\n            this.betBtnTextures.get('Disabled' + textureType) as Texture,\n            this.betBtnTextures.get('Hover' + textureType) as Texture,\n            this.betBtnTextures.get('Pressed' + textureType) as Texture,\n        );\n\n        const factor = this.componentConfiguration.additionalText.lines\n            ? (this.rootStore.settings.numberOfLinesPerDenomination?.[rowIndex][1] ?? this.rootStore.settings.factor)\n            : this.rootStore.settings.factor;\n\n        const maxBetLimits =\n            this.rootStore.settings.settings.settings?.clientSettings?.maxBetLimits &&\n            Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS)\n                ? this.rootStore.settings.settings.settings.clientSettings.maxBetLimits[\n                      this.rootStore.settings.currency\n                  ]\n                : undefined;\n\n        const buyBonusDenominations = this.settings.buyBonusDenominations ?? undefined;\n\n        const button = new BetSettingButtonCommon(\n            this.rootStore.uiStore.denominations[denomIndex],\n            this.rootStore.uiStore.bets[colIndex],\n            factor,\n            btnTextures,\n            this.componentConfiguration.popUpButtonsText.valueOffset.valueOf(),\n            this.componentConfiguration.popUpButtonsText.currencyOffset.valueOf(),\n            Object.assign({}, this.componentConfiguration.popUpButtonsText.normalTextStyle),\n            Object.assign({}, this.componentConfiguration.popUpButtonsText.currencyNormalTextStyle),\n            Object.assign({}, this.componentConfiguration.popUpButtonsText.currencyHilightedTextStyle),\n            Object.assign({}, this.componentConfiguration.popUpButtonsText.hilightedTextStyle),\n            this.componentConfiguration.popUpButtonsText.width.valueOf(),\n            this.componentConfiguration.popUpButtonsText.height.valueOf(),\n            this.createJpStamp(colIndex),\n            this.componentConfiguration.jackpotStampConfig?.offset,\n            this.rootStore.settings.maxBet,\n            maxBetLimits,\n            buyBonusDenominations,\n        );\n\n        button.buyBonusActivated = this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value;\n\n        if (selectedRow) {\n            button.setHilighted();\n        }\n        if (selectedButton) {\n            button.setSelected();\n        }\n\n        button.interactive = true;\n        button.pivot.set(button.width / 2, button.height / 2);\n        this.addChild(button);\n\n        this.betButtons[rowIndex].push(button);\n    }\n\n    private createJpStamp(betIndex: number): Sprite | undefined {\n        if (this.componentConfiguration.jackpotStampConfig && betIndex === this.rootStore.uiStore.bets.length - 1) {\n            const jackpotStamp = new Sprite(\n                Core.assets.getTextureFromSpriteSheet('calculatorResources', 'jackpot.png'),\n            );\n            return jackpotStamp;\n        } else {\n            return undefined;\n        }\n    }\n\n    private killAllAnimations(): void {\n        if (this.animationTween) {\n            this.animationTween.kill();\n            this.animationTween = null;\n        }\n\n        this.killPressingAnimation();\n    }\n\n    private setOrientation(): void {\n        this.killAllAnimations();\n        const currencyValueGap = this.componentConfiguration.popUpButtonsText.currencyValueGap;\n        const oldBtnTextFontSize = this.componentConfiguration.popUpButtonsText.normalTextStyle.fontSize as number;\n        const btnTextFontSize = this.findProperFontSize(\n            this.componentConfiguration.popUpButtonsText.normalTextStyle.fontSize as number,\n        );\n        for (let i: number = 0; i < this.betButtons.length; i++) {\n            const rowsPositionOffset =\n                this.componentConfiguration.rowsBackgroundPositions.length - this.rowsBackgrounds.length;\n\n            for (let t: number = 0; t < this.betButtons[i].length; t++) {\n                const scale = this.betButtons[i][t].scale.x;\n                this.betButtons[i][t].scale.set(1);\n\n                this.betButtons[i][t].scale.set(scale);\n                this.betButtons[i][t].getBtnText().style.fontSize =\n                    btnTextFontSize !== 0 ? btnTextFontSize : (this.getBtnTextStyle(i, t).fontSize as number);\n                this.betButtons[i][t].getBtnText().style.lineHeight =\n                    btnTextFontSize !== 0 ? btnTextFontSize : (this.getBtnTextStyle(i, t).fontSize as number);\n                if (oldBtnTextFontSize !== btnTextFontSize) {\n                    this.betButtons[i][t].updateTextsLayout(currencyValueGap, btnTextFontSize, oldBtnTextFontSize);\n                } else {\n                    this.betButtons[i][t].restoreTextsDefaultLayout(oldBtnTextFontSize);\n                }\n\n                this.betButtons[i][t].pivot.set(this.betButtons[i][t].width / 2, this.betButtons[i][t].height / 2);\n                this.betButtons[i][t].x =\n                    this.componentConfiguration.betBtnPositions[t].get('x') + this.betButtons[i][t].width / 2;\n                this.betButtons[i][t].y =\n                    this.componentConfiguration.rowsBackgroundPositions[i + rowsPositionOffset].get('y') +\n                    4 +\n                    this.betButtons[i][t].height / 2;\n            }\n        }\n\n        for (let i: number = 0; i < this.rowsBackgrounds.length; i++) {\n            const rowsPositionOffset =\n                this.componentConfiguration.rowsBackgroundPositions.length - this.rowsBackgrounds.length;\n            const rowHeight = this.componentConfiguration.rowsBackgroundPositions[i + rowsPositionOffset].get('height');\n            this.rowsBackgrounds[i].x =\n                this.componentConfiguration.rowsBackgroundPositions[i + rowsPositionOffset].get('x');\n            this.rowsBackgrounds[i].y =\n                this.componentConfiguration.rowsBackgroundPositions[i + rowsPositionOffset].get('y');\n            this.rowsBackgrounds[i].width =\n                this.componentConfiguration.rowsBackgroundPositions[i + rowsPositionOffset].get('width');\n            this.rowsBackgrounds[i].height =\n                this.componentConfiguration.rowsBackgroundPositions[i + rowsPositionOffset].get('height');\n\n            if (!this.isMysteryJackpot) {\n                this.rowsBackgroundsSelected[i].x =\n                    this.componentConfiguration.selectedRowsBackgroundPositions[i + rowsPositionOffset].get('x');\n                this.rowsBackgroundsSelected[i].y =\n                    this.componentConfiguration.selectedRowsBackgroundPositions[i + rowsPositionOffset].get('y');\n                this.rowsBackgroundsSelected[i].width =\n                    this.componentConfiguration.selectedRowsBackgroundPositions[i + rowsPositionOffset].get('width');\n                this.rowsBackgroundsSelected[i].height =\n                    this.componentConfiguration.selectedRowsBackgroundPositions[i + rowsPositionOffset].get('height');\n            }\n            if (this.componentConfiguration.additionalText.hasAdditionalText) {\n                const diff = this.additionalNumber[i].height - this.additionalText[i].height;\n                const additionalTextYOffset = this.componentConfiguration.additionalText.textYOffset;\n\n                this.additionalNumber[i].x = this.componentConfiguration.additionalText.x;\n                this.additionalNumber[i].y =\n                    this.rowsBackgrounds[i].y +\n                    rowHeight / 2 -\n                    this.additionalNumber[i].height / 2 +\n                    diff / 2 +\n                    additionalTextYOffset;\n\n                this.additionalText[i].x = this.componentConfiguration.additionalText.x;\n                this.additionalText[i].y =\n                    this.rowsBackgrounds[i].y +\n                    rowHeight / 2 +\n                    this.additionalText[i].height / 2 +\n                    diff / 2 +\n                    additionalTextYOffset;\n            }\n        }\n\n        this.globalPosition = { x: this.rowsBackgrounds[0].x, y: this.rowsBackgrounds[0].y };\n    }\n\n    private resetAllButtonsFontSize(): void {\n        const originalFontSize = this.componentConfiguration.popUpButtonsText.normalTextStyle.fontSize as number;\n        for (const row of this.betButtons) {\n            for (const btn of row) {\n                btn.getBtnText().style.fontSize = originalFontSize;\n                btn.getBtnText().style.lineHeight = originalFontSize;\n            }\n        }\n    }\n\n    protected findProperFontSize(defaultFontSize: number): number {\n        if (!this.componentConfiguration.popUpButtonsText.shouldFitInBounds) {\n            return 0;\n        }\n\n        let minFontSize: number = defaultFontSize;\n\n        for (const denomBetButton of this.betButtons) {\n            for (const betButton of denomBetButton) {\n                let fontSize: number = betButton.getBtnText().style.fontSize as number;\n                if (betButton.getBtnText().width > this.componentConfiguration.popUpButtonsText.widthBounds) {\n                    fontSize = Math.round(\n                        fontSize *\n                            (this.componentConfiguration.popUpButtonsText.widthBounds / betButton.getBtnText().width),\n                    );\n                }\n                minFontSize = Math.min(minFontSize, fontSize);\n            }\n        }\n        if (defaultFontSize > minFontSize) {\n            return minFontSize;\n        }\n        return defaultFontSize;\n    }\n\n    private deselectAllButtons(): void {\n        for (const row of this.betButtons) {\n            for (const btn of row) {\n                btn.setNormal();\n                btn.scale.set(1);\n                btn.pivot.set(btn.width / 2, btn.height / 2);\n                btn.alpha = 1;\n                btn.children[0].alpha = 1;\n            }\n        }\n    }\n\n    private deselectAllRows(): void {\n        for (let i: number = 0; i < this.rowsBackgrounds.length; i++) {\n            this.rowsBackgrounds[i].visible = true;\n            if (!this.isMysteryJackpot) {\n                this.rowsBackgroundsSelected[i].visible = false;\n            }\n            if (this.componentConfiguration.additionalText.hasAdditionalText) {\n                this.additionalNumber[i].style = this.componentConfiguration.additionalText.valueStyle;\n                this.additionalText[i].style = this.componentConfiguration.additionalText.textStyle;\n            }\n        }\n    }\n\n    private getBtnTextStyle(denomIndex: number, betIndex: number): TextStyle {\n        return !this.isSelected(denomIndex, betIndex) && this.componentConfiguration.popUpButtonsText.hilightedTextStyle\n            ? this.componentConfiguration.popUpButtonsText.hilightedTextStyle\n            : this.componentConfiguration.popUpButtonsText.normalTextStyle;\n    }\n\n    private isSelected(denomIndex: number, betIndex: number): boolean {\n        return (\n            Core.SELECTED_DENOMINATION.value === this.rootStore.uiStore.denominations[denomIndex] &&\n            this.rootStore.uiStore.SELECTED_BET.value === this.rootStore.uiStore.bets[betIndex]\n        );\n    }\n\n    private killPressingAnimation(): void {\n        if (this.pressingAnimation && this.pressingAnimation !== null) {\n            this.pressingAnimation.totalProgress(1, true);\n            this.pressingAnimation.kill();\n            // @ts-ignore\n            this.pressingAnimation = null;\n        }\n    }\n\n    private destroyArray(arr: any[]) {\n        arr.forEach((child) => {\n            this.destroyObject(child);\n        });\n        // @ts-ignore\n        arr = null;\n    }\n\n    private destroyObject(obj: any) {\n        obj?.destroy?.();\n        // @ts-ignore\n        obj = null;\n    }\n\n    private changeNumberOfLines(denomination: number): void {\n        if (\n            this.rootStore.settings.numberOfLinesPerDenomination &&\n            this.rootStore.settings.numberOfLinesPerDenomination.length\n        ) {\n            const [, numberOfLines] = this.rootStore.settings.numberOfLinesPerDenomination.find(\n                ([denominationConfig]) => denominationConfig === denomination,\n            )!;\n\n            if (this.rootStore.uiStore.LINES.value !== numberOfLines) {\n                this.rootStore.uiStore.LINES.next(numberOfLines!);\n            }\n        }\n    }\n}\n","import {\n    AssetPriority,\n    AssetsCollection,\n    BaseComponentConfiguration,\n    DefaultAssets,\n    DefaultValue,\n    DynamicPositionObject,\n} from '@egt/core';\nimport { TextStyle } from 'pixi.js';\nimport {\n    IAdditionalText,\n    IDenominationPopUpBtnsText,\n    IDenominationPopUpPositions,\n    IBetsLayoutConfig,\n    IRowsBackgroundPositions,\n} from '../../../common/interfaces/InterfacesCommon';\nimport { IBetCalculatorComponentConfigurationTurtle } from '../interfaces/InterfacesTurtle';\n\nexport default class BetCalculatorComponentConfigurationTurtle extends BaseComponentConfiguration {}\nexport function BetCalculatorComponentConfigurationFactoryTurtle(): any {\n    class BetCalculatorComponentConfigurationTurtleInternalClass\n        extends BetCalculatorComponentConfigurationTurtle\n        implements IBetCalculatorComponentConfigurationTurtle\n    {\n        public buttonsToHide = ['betButtons', 'denominationButton'];\n\n        public mainViewComponentsToHide = ['balanceContainer', 'winContainer'];\n\n        @DefaultAssets([\n            {\n                id: 'calculatorResources',\n                url: '../assets/components/slot/bet-calculator/common/calculatorResources.json',\n                priority: AssetPriority.HIGHEST,\n                type: 'texture',\n            },\n            {\n                id: 'svgDenominationPopUpNormal',\n                url: '../assets/components/slot/bet-calculator/turtle/ui-svg/denominationPopUpNormal.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n            },\n            {\n                id: 'svgDenominationPopUpPressed',\n                url: '../assets/components/slot/bet-calculator/turtle/ui-svg/denominationPopUpPressed.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n            },\n            {\n                id: 'svgDenominationPopUpFocus',\n                url: '../assets/components/slot/bet-calculator/turtle/ui-svg/denominationPopUpFocus.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n            },\n            {\n                id: 'svgDenominationPopUpSelected',\n                url: '../assets/components/slot/bet-calculator/turtle/ui-svg/denominationPopUpSelected.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n            },\n            {\n                id: 'svgDenominationPopUpHover',\n                url: '../assets/components/slot/bet-calculator/turtle/ui-svg/denominationPopUpHover.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n            },\n        ])\n        public assets: AssetsCollection;\n\n        @DefaultValue<IAdditionalText>({\n            defaults: {\n                x: 503,\n                hasAdditionalText: false,\n                lines: false,\n                valueStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold',\n                    fontSize: 32,\n                    lineHeight: 32,\n                    fill: '#A3A3A3',\n                    align: 'center',\n                }),\n                textStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold',\n                    fontSize: 17,\n                    lineHeight: 17,\n                    fill: '#A3A3A3',\n                    align: 'center',\n                }),\n                selectedFill: '#FFFFFF',\n                textYOffset: -2,\n            },\n            portrait: {\n                x: 70,\n            },\n        })\n        public additionalText: DynamicPositionObject<IAdditionalText> & IAdditionalText;\n\n        @DefaultValue<IDenominationPopUpBtnsText>({\n            defaults: {\n                x: 0,\n                y: 0,\n                width: 134,\n                height: 78,\n                widthBounds: 120,\n                shouldFitInBounds: true,\n                valueOffset: 10,\n                currencyOffset: 25.5,\n                currencyValueGap: 10,\n                normalTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    fontSize: 47,\n                    lineHeight: 47,\n                    fill: '#C6C5C5',\n                    align: 'center',\n                    trim: true,\n                    stroke: '#FFFFFF',\n                    strokeThickness: 0.17,\n                }),\n                hilightedTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    fontSize: 47,\n                    lineHeight: 47,\n                    fill: '#FFFFFF',\n                    align: 'center',\n                    trim: true,\n                }),\n                currencyNormalTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                    fontSize: 20,\n                    lineHeight: 20,\n                    fill: '#FFD200',\n                    align: 'center',\n                    letterSpacing: 0.4,\n                    trim: true,\n                }),\n                currencyHilightedTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                    fontSize: 20,\n                    lineHeight: 20,\n                    fill: '#FFD200',\n                    align: 'center',\n                    letterSpacing: 0.4,\n                    trim: true,\n                }),\n                normalTextures: ['svgBet', 'svgBetPressed', 'svgBet', 'svgBet'],\n                hilightedTextures: ['svgBetBlue', 'svgBetBluePressed', 'svgBetBlue', 'svgBetBlue'],\n            },\n        })\n        public popUpButtonsText: DynamicPositionObject<IDenominationPopUpBtnsText> & IDenominationPopUpBtnsText;\n\n        /**\n         * Positions are based on 6 denomination preview.\n         * When there are fewer than 6 denominations the prop mainContainerPosition is used to move the whole container.\n         */\n        public rowsBackgroundPositions: Array<DynamicPositionObject<IRowsBackgroundPositions>> = [\n            new DynamicPositionObject<IRowsBackgroundPositions>({\n                defaults: { x: 466, y: 83, width: 704, height: 86 },\n                portrait: { x: 30, y: 259, width: 704, height: 86 },\n            }),\n            new DynamicPositionObject<IRowsBackgroundPositions>({\n                defaults: { x: 466, y: 171, width: 704, height: 86 },\n                portrait: { x: 30, y: 347, width: 704, height: 86 },\n            }),\n            new DynamicPositionObject<IRowsBackgroundPositions>({\n                defaults: { x: 466, y: 259, width: 704, height: 86 },\n                portrait: { x: 30, y: 435, width: 704, height: 86 },\n            }),\n            new DynamicPositionObject<IRowsBackgroundPositions>({\n                defaults: { x: 466, y: 347, width: 704, height: 86 },\n                portrait: { x: 30, y: 523, width: 704, height: 86 },\n            }),\n            new DynamicPositionObject<IRowsBackgroundPositions>({\n                defaults: { x: 466, y: 435, width: 704, height: 86 },\n                portrait: { x: 30, y: 611, width: 704, height: 86 },\n            }),\n            new DynamicPositionObject<IRowsBackgroundPositions>({\n                defaults: { x: 466, y: 523, width: 704, height: 86 },\n                portrait: { x: 30, y: 699, width: 704, height: 86 },\n            }),\n            new DynamicPositionObject<IRowsBackgroundPositions>({\n                defaults: { x: 466, y: 611, width: 704, height: 86 },\n                portrait: { x: 30, y: 787, width: 704, height: 86 },\n            }),\n        ];\n\n        public selectedRowsBackgroundPositions: Array<DynamicPositionObject<IRowsBackgroundPositions>> = [\n            new DynamicPositionObject<IRowsBackgroundPositions>({\n                defaults: { x: 466, y: 83, width: 704, height: 86 },\n                portrait: { x: 30, y: 259, width: 704, height: 86 },\n            }),\n            new DynamicPositionObject<IRowsBackgroundPositions>({\n                defaults: { x: 466, y: 171, width: 704, height: 86 },\n                portrait: { x: 30, y: 347, width: 704, height: 86 },\n            }),\n            new DynamicPositionObject<IRowsBackgroundPositions>({\n                defaults: { x: 466, y: 259, width: 704, height: 86 },\n                portrait: { x: 30, y: 435, width: 704, height: 86 },\n            }),\n            new DynamicPositionObject<IRowsBackgroundPositions>({\n                defaults: { x: 466, y: 347, width: 704, height: 86 },\n                portrait: { x: 30, y: 523, width: 704, height: 86 },\n            }),\n            new DynamicPositionObject<IRowsBackgroundPositions>({\n                defaults: { x: 466, y: 435, width: 704, height: 86 },\n                portrait: { x: 30, y: 611, width: 704, height: 86 },\n            }),\n            new DynamicPositionObject<IRowsBackgroundPositions>({\n                defaults: { x: 466, y: 523, width: 704, height: 86 },\n                portrait: { x: 30, y: 699, width: 704, height: 86 },\n            }),\n            new DynamicPositionObject<IRowsBackgroundPositions>({\n                defaults: { x: 466, y: 611, width: 704, height: 86 },\n                portrait: { x: 30, y: 787, width: 704, height: 86 },\n            }),\n        ];\n\n        public betBtnPositions: Array<DynamicPositionObject<IDenominationPopUpPositions>> = [\n            new DynamicPositionObject<IDenominationPopUpPositions>({\n                defaults: { x: 469 },\n                portrait: { x: 31 },\n            }),\n            new DynamicPositionObject<IDenominationPopUpPositions>({\n                defaults: { x: 611 },\n                portrait: { x: 173 },\n            }),\n            new DynamicPositionObject<IDenominationPopUpPositions>({\n                defaults: { x: 753 },\n                portrait: { x: 315 },\n            }),\n            new DynamicPositionObject<IDenominationPopUpPositions>({\n                defaults: { x: 895 },\n                portrait: { x: 457 },\n            }),\n            new DynamicPositionObject<IDenominationPopUpPositions>({\n                defaults: { x: 1037 },\n                portrait: { x: 599 },\n            }),\n        ];\n\n        @DefaultValue<IBetsLayoutConfig>({\n            defaults: {\n                betsBase: 5,\n                dynamicLayoutThreshold: 25,\n                maxSideBetCount: 7,\n                betsPositionOffset: 72,\n            },\n            portrait: {\n                betsPositionOffset: 94,\n            },\n        })\n        public betsLayoutConfig: DynamicPositionObject<IBetsLayoutConfig> & IBetsLayoutConfig;\n\n        public useBetsPerLineFromConfiguration = false;\n    }\n    return BetCalculatorComponentConfigurationTurtleInternalClass;\n}\n","import { BuyBonusModes } from '@egt/buy-bonus';\nimport Core, { BaseController, Timers } from '@egt/core';\nimport { FeatureController, ISlotConfiguration, RootStore, SlotComponents, UIState } from '@egt/slot';\nimport { fromEvent } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport BetCalculatorViewTurtle from '../views/BetCalculatorViewTurtle';\nimport BetSettingButtonCommon, { BetSettingsButtonStatesCommon } from '../../../common/buttons/BetSettingButtonCommon';\nimport { IBetCalculatorComponentConfigurationTurtle } from '../interfaces/InterfacesTurtle';\n\n@injectable()\nexport default class BetCalculatorControllerTurtle extends BaseController {\n    constructor(\n        @inject('BetCalculator') protected betCalculator: BetCalculatorViewTurtle,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('BetCalculatorComponentConfiguration')\n        protected componentConfiguration: IBetCalculatorComponentConfigurationTurtle,\n        @inject('FeatureController') protected feature: FeatureController,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n    ) {\n        super(betCalculator);\n    }\n\n    public destroy(): void {\n        super.destroy();\n    }\n\n    public init(): void {\n        this.attachEventListeners();\n    }\n\n    public attachEventListeners(): void {\n        this.addBetButtonsEventListeners();\n\n        this.rootStore.subjects.DENOMINATIONS_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onDenominationsChanged.bind(this),\n        );\n\n        this.rootStore.uiStore.SELECTED_BET.pipe(takeUntil(this.DESTROY)).subscribe(this.onBetChanged.bind(this));\n        this.rootStore.subjects.SETTINGS_DENOMINATION_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onDenominationChanged.bind(this, true),\n        );\n\n        this.rootStore.subjects.FACTOR_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(this.onFactorChanged.bind(this));\n        this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onExtendedMultipleBuyBonusActivated.bind(this),\n        );\n\n        this.rootStore.uiStore.STATE.pipe(takeUntil(this.DESTROY)).subscribe(this.stateChanged.bind(this));\n    }\n\n    protected onFactorChanged(): void {\n        if (this.componentConfiguration.additionalText.lines) {\n            return;\n        }\n        // this.betCalculator.updateBetValue();\n        for (const betButton of this.betCalculator.betButtons) {\n            // for (const betButton of betButtons) {\n            betButton.button.factor = this.rootStore.settings.factor;\n            // }\n        }\n    }\n\n    protected onExtendedMultipleBuyBonusActivated(value: boolean): void {\n        if (\n            this.rootStore.settings.haveGameMode('DOUBLE_CHANCE') &&\n            this.rootStore.settings.factor === this.rootStore.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE')\n        ) {\n            value = false;\n        }\n        for (const betButton of this.betCalculator.betButtons) {\n            // for (const betButton of betButtons) {\n            betButton.button.buyBonusActivated = value;\n            // }\n        }\n    }\n\n    protected updateBet(betBtn: BetSettingButtonCommon, dispatchedFromPopup: boolean) {\n        if (betBtn) {\n            Core.SELECTED_DENOMINATION.next(betBtn.denominationLevel);\n            this.rootStore.uiStore.SELECTED_BET.next(betBtn.betLevel);\n\n            if (\n                !(\n                    this.rootStore.uiStore.CURRENT_BET_LEVEL.value.betLevel === betBtn.betLevel &&\n                    this.rootStore.uiStore.CURRENT_BET_LEVEL.value.denomLevel === betBtn.denominationLevel\n                )\n            ) {\n                this.rootStore.uiStore.CURRENT_BET_LEVEL.next({\n                    betLevel: this.rootStore.uiStore.SELECTED_BET.value,\n                    denomLevel: Core.SELECTED_DENOMINATION.value,\n                });\n            }\n            this.rootStore.subjects.CHANGE_SELECTED_BET_BTN_EXTERNALLY.next({\n                betVal: this.rootStore.uiStore.SELECTED_BET.value,\n                changedFromPopUp: true,\n            });\n\n            if (dispatchedFromPopup) {\n                Timers.setTimeout(() => {\n                    this.rootStore.subjects.CLOSE_DENOMINATION_POPUP.next();\n                    Core.UI_BLOCKER.next(false);\n                }, 300);\n            }\n        }\n    }\n\n    protected stateChanged(): void {\n        for (const betButton of this.betCalculator.betButtons) {\n            // for (const betButton of betButtons) {\n            betButton.button.enabled = !this.feature.isInGiftSpins;\n\n            if (betButton.button.state === BetSettingsButtonStatesCommon.Selected) {\n                betButton.button.enabled = true;\n            }\n            // }\n        }\n    }\n\n    private onDenominationsChanged(): void {\n        this.betCalculator.onDenominationsChanged();\n        this.addBetButtonsEventListeners();\n    }\n\n    private addBetButtonsEventListeners() {\n        for (const betButton of this.betCalculator.betButtons) {\n            // for (const betButton of betButtons) {\n            betButton.button.CLICK.pipe(takeUntil(this.DESTROY)).subscribe((btn: BetSettingButtonCommon) => {\n                Core.sounds.play('changeBetSound');\n                this.onBetOptionButtonClicked(btn, true);\n            });\n\n            (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/bet-calculator/src/egt/modes/turtle/controllers/BetCalculatorControllerTurtle.ts:133:13\",(betButton.button),\"pointerup\"]), fromEvent(betButton.button, 'pointerup'))\n                .pipe(takeUntil(this.DESTROY))\n                .subscribe(this.onBetOptionButtonReleased.bind(this));\n\n            (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/bet-calculator/src/egt/modes/turtle/controllers/BetCalculatorControllerTurtle.ts:137:13\",(betButton.button),\"pointerupoutside\"]), fromEvent(betButton.button, 'pointerupoutside'))\n                .pipe(takeUntil(this.DESTROY))\n                .subscribe(this.onBetOptionButtonReleased.bind(this));\n\n            fromEvent(betButton.button, 'pointerout')\n                .pipe(takeUntil(this.DESTROY))\n                .subscribe(this.onBetOptionButtonReleased.bind(this));\n\n            (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/bet-calculator/src/egt/modes/turtle/controllers/BetCalculatorControllerTurtle.ts:145:13\",(betButton.button),\"pointerdown\"]), fromEvent(betButton.button, 'pointerdown'))\n                .pipe(takeUntil(this.DESTROY))\n                .subscribe(this.onBetOptionButtonPressed.bind(this));\n            // }\n        }\n    }\n\n    private onDenominationChanged(_dispatchedFromSettings: boolean = false, data: any): void {\n        if (data.playDenomChangeSound) {\n            Core.sounds.play('changeDenominationSound');\n        }\n        Core.SELECTED_DENOMINATION.next(this.rootStore.uiStore.denominations[data.denomination - 1]);\n        // this.rootStore.uiStore.CURRENT_BET_LEVEL.next({\n        //     betLevel: this.rootStore.uiStore.SELECTED_BET.value,\n        //     denomLevel: Core.SELECTED_DENOMINATION.value,\n        // });\n        this.onExtendedMultipleBuyBonusActivated(this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value);\n    }\n\n    private onBetChanged(): void {\n        this.betCalculator.resetCalculatorPopUp();\n    }\n\n    private onBetOptionButtonPressed(betButton: any): void {\n        for (const betBtn of this.betCalculator.betButtons) {\n            // for (const betBtn of this.betCalculator.betButtons[i]) {\n            if (betButton.currentTarget === betBtn) {\n                this.betCalculator.animateDownScaleBtn(betBtn.button);\n            }\n            // }\n        }\n    }\n\n    private onBetOptionButtonReleased(betButton: any): void {\n        for (const betBtn of this.betCalculator.betButtons) {\n            // for (const betBtn of this.betCalculator.betButtons[i]) {\n            if (betButton.currentTarget === betBtn) {\n                this.betCalculator.animateUpScaleBtn(betBtn.button);\n            }\n            // }\n        }\n    }\n\n    private onBetOptionButtonClicked(betButton: BetSettingButtonCommon, dispatchedFromPopup: boolean): void {\n        if (this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_RESPONSE || this.isInBonusOrGiftSpins()) {\n            return;\n        }\n        Core.UI_BLOCKER.next(true);\n        if (dispatchedFromPopup) {\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'spinSpeedButton',\n                actions: 'visible',\n                values: true,\n            });\n\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'spinSpeedButtonDisabled',\n                actions: 'visible',\n                values: false,\n            });\n        }\n        for (const betBtn of this.betCalculator.betButtons) {\n            // for (const betBtn of this.betCalculator.betButtons[i]) {\n            if (betButton === betBtn.button) {\n                if (!Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS)) {\n                    this.rootStore.subjects.DISABLED_BUY_BONUS.next({\n                        disabled: this.checkForMaxBet(betBtn.button.betLevel, betBtn.button.denominationLevel),\n                        doNotChangeVisual: false,\n                    });\n                }\n                Timers.setTimeout(() => {\n                    this.betCalculator.updateSelectedRow(betBtn.row, betBtn.button);\n                    betBtn.button.setPressed();\n                }, 10);\n\n                Timers.setTimeout(() => {\n                    if (this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_RESPONSE) {\n                        return;\n                    }\n                    betBtn.button.setSelected();\n                    this.updateBet(betButton, dispatchedFromPopup);\n                }, 100);\n            }\n            // }\n        }\n        // if (!this.betCalculator.isInteractive) {\n        //     this.betCalculator.isInteractive = true;\n        // }\n    }\n\n    private checkForMaxBet(bet: number, denomination: number): boolean {\n        let buyBonusValue: number =\n            denomination *\n            bet *\n            (this.rootStore.settings.factors[this.rootStore.settings.factors.length - 1] /\n                this.rootStore.uiStore.units);\n\n        if (this.rootStore.settings.clientSettings?.maxBetLimits || this.rootStore.settings.maxBet) {\n            const maxBetForBonus: number = Math.min(\n                this.rootStore.settings.clientSettings?.maxBetLimits\n                    ? this.rootStore.settings.clientSettings?.maxBetLimits[Core.PLAYER_BALANCE.value.currency]\n                    : Infinity,\n                this.rootStore.settings.maxBet ?? Infinity,\n            );\n            if (maxBetForBonus && buyBonusValue > maxBetForBonus) {\n                buyBonusValue = maxBetForBonus;\n                return true;\n            }\n        }\n        return false;\n    }\n\n    private isInBonusOrGiftSpins() {\n        return this.rootStore.uiStore.STATE.value === UIState.BONUS_IDLE || this.feature.isInGiftSpins;\n    }\n}\n","import { BuyBonusModes } from '@egt/buy-bonus';\nimport Core, { Money } from '@egt/core';\nimport { Features, ISlotConfiguration, InitialSettings, RootStore, SlotComponents } from '@egt/slot';\nimport { ViewContainer } from '@egt/ui-lib';\nimport { gsap } from 'gsap';\nimport { Container, NineSlicePlane, Sprite, Text, TextStyle, Texture } from 'pixi.js';\nimport { BehaviorSubject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport BetSettingButtonCommon, { BetSettingsButtonTextures } from '../../../common/buttons/BetSettingButtonCommon';\nimport { IBetCalculatorComponentConfigurationTurtle } from '../interfaces/InterfacesTurtle';\n\n@injectable()\nexport default class BetCalculatorViewTurtle extends ViewContainer {\n    public readonly UPDATE_BET: BehaviorSubject<BetSettingButtonCommon | null> = new BehaviorSubject(null);\n\n    public oneDenomView: boolean = false;\n\n    public mainContainer: Container;\n\n    public betButtons: { button: BetSettingButtonCommon; row: number; denom: number; bet: number }[] = [];\n    // public rolls: number;\n\n    protected pressingAnimation: gsap.core.Timeline | null;\n\n    public globalPosition: { x: number; y: number } = { x: 0, y: 0 };\n\n    private betBtnTextures: Map<string, Texture> = new Map();\n\n    private rowsBackgrounds: Array<Container | NineSlicePlane> = [];\n    private rowsBackgroundsSelected: NineSlicePlane[] = [];\n    private betContainer: Sprite;\n    private balanceMoneyFormatter: Money;\n    private betMoneyFormatter: Money;\n    private animationTween: any;\n    private additionalNumber: Text[] = [];\n    private additionalText: Text[] = [];\n    private isMysteryOrPremiumJackpot: boolean = false;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected configuration: ISlotConfiguration,\n        @inject('BetCalculatorComponentConfiguration')\n        protected componentConfiguration: IBetCalculatorComponentConfigurationTurtle,\n        @inject('InitialSettings') protected settings: InitialSettings,\n    ) {\n        super();\n        this.isMysteryOrPremiumJackpot =\n            Core.hasFeature(Features.MYSTERY_JACKPOT) ||\n            Core.hasFeature(Features.PREMIUM_LINK_JACKPOT) ||\n            Core.game?.features?.filter((feature) => feature.featureType.includes('_JACKPOT')).length === 0;\n    }\n\n    public init(): void {\n        // this.isOpened = false;\n        this.createBtnsTextures();\n        this.createDenominationPopUp();\n\n        Core.LEFT_HAND_MODE.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n\n        this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.changeBtnsTextures();\n            this.resetAllButtonsFontSize();\n            this.setOrientation();\n        });\n        Core.SELECTED_DENOMINATION.pipe(takeUntil(Core.ON_GAME_UNLOADED)).subscribe((denomination) => {\n            if (\n                this.rootStore.settings.numberOfLinesPerDenomination &&\n                this.rootStore.settings.numberOfLinesPerDenomination.length\n            ) {\n                this.changeNumberOfLines(denomination);\n            }\n        });\n    }\n\n    public destroy(): void {\n        this.killAllAnimations();\n\n        if (this.betButtons) {\n            this.destroyArray(this.betButtons);\n        }\n        this.destroyObjects();\n        this.destroyObject(this.animationTween);\n        this.removeChildren();\n        super.destroy();\n    }\n\n    private destroyObjects() {\n        this.destroyObject(this.betContainer);\n        this.destroyObject(this.balanceMoneyFormatter);\n        this.destroyObject(this.betMoneyFormatter);\n\n        this.destroyArray(this.additionalNumber);\n        this.destroyArray(this.additionalText);\n        this.destroyArray(this.rowsBackgrounds);\n        this.destroyArray(this.rowsBackgroundsSelected);\n    }\n\n    private createBtnsTextures(): void {\n        this.betBtnTextures.set('Normal', Core.assets.getAsset('svgDenominationPopUpNormal').texture);\n        this.betBtnTextures.set('Focus', Core.assets.getAsset('svgDenominationPopUpFocus').texture);\n        this.betBtnTextures.set('Selected', Core.assets.getAsset('svgDenominationPopUpSelected').texture);\n        this.betBtnTextures.set('Disabled', Core.assets.getAsset('svgDenominationPopUpNormal').texture);\n        this.betBtnTextures.set('Hover', Core.assets.getAsset('svgDenominationPopUpHover').texture);\n        this.betBtnTextures.set('Pressed', Core.assets.getAsset('svgDenominationPopUpPressed').texture);\n\n        if (Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS)) {\n            this.betBtnTextures.set('NormalSpecial', Core.assets.getAsset('svgDenominationPopUpNormalSpecial').texture);\n            this.betBtnTextures.set('FocusSpecial', Core.assets.getAsset('svgDenominationPopUpFocusSpecial').texture);\n            this.betBtnTextures.set(\n                'SelectedSpecial',\n                Core.assets.getAsset('svgDenominationPopUpSelectedSpecial').texture,\n            );\n            this.betBtnTextures.set(\n                'DisabledSpecial',\n                Core.assets.getAsset('svgDenominationPopUpNormalSpecial').texture,\n            );\n            this.betBtnTextures.set('HoverSpecial', Core.assets.getAsset('svgDenominationPopUpHoverSpecial').texture);\n            this.betBtnTextures.set(\n                'PressedSpecial',\n                Core.assets.getAsset('svgDenominationPopUpPressedSpecial').texture,\n            );\n        }\n    }\n\n    public changeBtnsTextures() {\n        const textureType: string = this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value\n            ? 'Special'\n            : '';\n        for (const betButton of this.betButtons) {\n            // for (const betButton of betButtonRow) {\n            betButton.button.updateTextures(\n                this.betBtnTextures.get('Normal' + textureType) as Texture,\n                this.betBtnTextures.get('Focus' + textureType) as Texture,\n                this.betBtnTextures.get('Selected' + textureType) as Texture,\n                this.betBtnTextures.get('Disabled' + textureType) as Texture,\n                this.betBtnTextures.get('Hover' + textureType) as Texture,\n                this.betBtnTextures.get('Pressed' + textureType) as Texture,\n            );\n            // }\n        }\n    }\n\n    public onDenominationsChanged() {\n        // const wasOpen = this.isOpened;\n        this.removeChildren();\n        if (this.betButtons.length) {\n            // this.betButtons.forEach((buttonRow) => {\n            //     buttonRow.length = 0;\n            // });\n            this.betButtons.length = 0;\n        }\n        this.additionalNumber = [];\n        this.additionalText = [];\n        this.rowsBackgrounds = [];\n        this.rowsBackgroundsSelected = [];\n\n        this.createDenominationPopUp();\n\n        // if (wasOpen) {\n        //     this.open(false);\n        // } else {\n        //     this.close(false);\n        // }\n        this.setOrientation();\n        this.resetCalculatorPopUp();\n    }\n\n    public animateDownScaleBtn(betBtn: BetSettingButtonCommon) {\n        this.killPressingAnimation();\n\n        betBtn.scale.set(1);\n        betBtn.children[0].alpha = 0.4;\n        const scale = 0.9;\n\n        this.pressingAnimation = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/bet-calculator/src/egt/modes/turtle/views/BetCalculatorViewTurtle.ts:177:34\",null]), gsap.timeline()).to(\n            betBtn.scale,\n            {\n                x: scale,\n                y: scale,\n                duration: 0.15,\n                ease: 'power4.out',\n            },\n            '<',\n        );\n    }\n\n    public animateUpScaleBtn(betBtn: BetSettingButtonCommon) {\n        if (betBtn.scale.x === 1) {\n            return;\n        }\n        this.killPressingAnimation();\n\n        this.pressingAnimation = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/bet-calculator/src/egt/modes/turtle/views/BetCalculatorViewTurtle.ts:195:34\",null]), gsap\n            .timeline())\n            .to(betBtn.children[0], {\n                alpha: 1,\n                duration: 0.15,\n            })\n            .to(\n                betBtn.scale,\n                {\n                    x: 1,\n                    y: 1,\n                    duration: 0.1,\n                    ease: 'power4.in',\n                    onComplete: () => {\n                        betBtn.children[0].alpha = 1;\n                        this.killPressingAnimation();\n                    },\n                },\n                '<',\n            );\n    }\n\n    public resetCalculatorPopUp(): void {\n        // const denomIndex = this.rootStore.uiStore.denominations.indexOf(Core.SELECTED_DENOMINATION.value);\n        const rowIndex = this.findCurrentRow(\n            Core.SELECTED_DENOMINATION.value,\n            this.rootStore.uiStore.SELECTED_BET.value,\n        );\n        // let betIndex = this.rootStore.uiStore.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value);\n        // if (this.oneDenomView && !this.componentConfiguration.useBetsPerLineFromConfiguration) {\n        //     const betLength = this.componentConfiguration.betBtnPositions.length;\n        //     denomIndex = Math.floor(betIndex / betLength);\n        //     betIndex = betIndex % betLength;\n        // }\n        const button: BetSettingButtonCommon = this.findBetButtonByDenominationAndBet(\n            Core.SELECTED_DENOMINATION.value,\n            this.rootStore.uiStore.SELECTED_BET.value,\n        );\n        this.updateSelectedRow(rowIndex, button);\n        if (button) {\n            button.setHilighted();\n            button.setSelected();\n        }\n    }\n\n    public findCurrentRow(denomIndex: number, betIndex: number): number {\n        const betButton = this.betButtons.find((item) => item.denom === denomIndex && item.bet === betIndex);\n\n        return betButton?.row as number;\n    }\n\n    public findBetButtonByDenominationAndBet(denomIndex: number, betIndex: number): BetSettingButtonCommon {\n        const found = this.betButtons.find((item) => item.denom === denomIndex && item.bet === betIndex);\n\n        return found?.button as BetSettingButtonCommon;\n    }\n\n    public updateSelectedRow(rowIndex: number, _betButton: BetSettingButtonCommon): void {\n        this.deselectAllRows();\n        this.deselectAllButtons();\n        this.rowsBackgrounds[rowIndex].visible = false;\n        if (Core.hasFeature(Features.PREMIUM_LINK_JACKPOT)) {\n            const highestBetButton = this.betButtons.reduce((highest, current) =>\n                current.bet > highest.bet ? current : highest,\n            );\n            highestBetButton.button.setHilighted();\n        }\n        if (!this.isMysteryOrPremiumJackpot) {\n            this.rowsBackgroundsSelected[rowIndex].visible = true;\n        }\n\n        if (this.shouldHighlightButtonsInSelectedRow()) {\n            this.betButtons.filter((item) => item.row === rowIndex).forEach((item) => item.button.setHilighted());\n        }\n\n        this.setAdditionalTextSelectedFill(rowIndex);\n        this.setOrientation();\n    }\n\n    private setAdditionalTextSelectedFill(rowIndex: number) {\n        if (this.componentConfiguration.additionalText.hasAdditionalText) {\n            const valueStyle = new TextStyle(this.componentConfiguration.additionalText.valueStyle);\n            valueStyle.fill = this.componentConfiguration.additionalText.selectedFill;\n            this.additionalNumber[rowIndex].style = valueStyle;\n\n            const textStyle = new TextStyle(this.componentConfiguration.additionalText.textStyle);\n            textStyle.fill = this.componentConfiguration.additionalText.selectedFill;\n            this.additionalText[rowIndex].style = textStyle;\n        }\n    }\n\n    private createAdditionalText(denominationIndex: number, _selectedRow: boolean): void {\n        this.additionalNumber[denominationIndex] = new Text(\n            this.componentConfiguration.additionalText.lines\n                ? (this.rootStore.settings.numberOfLinesPerDenomination?.[denominationIndex][1] ??\n                      denominationIndex + 1)\n                : denominationIndex + 1,\n            this.componentConfiguration.additionalText.valueStyle,\n        );\n        this.additionalNumber[denominationIndex].resolution = 2;\n        this.additionalNumber[denominationIndex].anchor.set(0.5);\n        this.addChild(this.additionalNumber[denominationIndex]);\n\n        this.additionalText[denominationIndex] = new Text(\n            this.componentConfiguration.additionalText.lines\n                ? Core.translator.translate('LINES')\n                : Core.translator.translate('LEVEL'),\n            this.componentConfiguration.additionalText.textStyle,\n        );\n        this.additionalText[denominationIndex];\n        this.additionalText[denominationIndex].resolution = 2;\n        this.additionalText[denominationIndex].anchor.set(0.5);\n        this.addChild(this.additionalText[denominationIndex]);\n\n        this.setAdditionalTextSelectedFill(denominationIndex);\n\n        const rowsPositionOffset =\n            this.componentConfiguration.rowsBackgroundPositions.length - this.rowsBackgrounds.length;\n        const rowPosition =\n            this.componentConfiguration.rowsBackgroundPositions[denominationIndex + rowsPositionOffset].get('x');\n        const firstBetPosition = this.componentConfiguration.betBtnPositions[0].get('x');\n        const availableWidth = firstBetPosition - rowPosition;\n\n        this.additionalText[denominationIndex].scale.set(1);\n\n        if (availableWidth > 0 && this.additionalText[denominationIndex].width > availableWidth) {\n            this.additionalText[denominationIndex].scale.set(\n                availableWidth / this.additionalText[denominationIndex].width,\n            );\n        }\n    }\n\n    private createDenominationPopUp(): void {\n        this.oneDenomView = this.rootStore.uiStore.denominations.length === 1;\n        // allow more than one denomination setup for bell link, bell link boost and gods and kings games, ON-149027\n        if (!this.oneDenomView && Core.hasFeature(Features.MYSTERY_JACKPOT)) {\n            return;\n        }\n        const cols = this.calculateBetsRowsOrCols('cols');\n        const rows = this.calculateBetsRowsOrCols('rows');\n        // if (this.rootStore.uiStore.bets.length > this.componentConfiguration.betBtnPositions.length && !this.componentConfiguration.useBetsPerLineFromConfiguration) {\n        //     const filteredBets = this.filterBets();\n        //     cols = this.componentConfiguration.betBtnPositions.length;\n        //     rows = Math.ceil(filteredBets.length / this.componentConfiguration.betBtnPositions.length);\n        //     this.oneDenomView = true;\n        // }\n        for (let i: number = 0; i < rows; i++) {\n            let rowBackground;\n            if (this.isMysteryOrPremiumJackpot) {\n                rowBackground = new Container();\n            } else {\n                rowBackground = new NineSlicePlane(\n                    Core.assets.getTextureFromSpriteSheet('calculatorResources', 'popupFill.png'),\n                    25,\n                    25,\n                    25,\n                    25,\n                );\n            }\n            this.addChild(rowBackground);\n            this.rowsBackgrounds.push(rowBackground);\n            if (!this.isMysteryOrPremiumJackpot) {\n                const rowsBackgroundsSelected = new NineSlicePlane(\n                    Core.assets.getTextureFromSpriteSheet('calculatorResources', 'popupFillSelected.png'),\n                    25,\n                    25,\n                    25,\n                    25,\n                );\n                this.addChild(rowsBackgroundsSelected);\n                this.rowsBackgroundsSelected.push(rowsBackgroundsSelected);\n            }\n\n            let selectedRow: boolean = false;\n\n            if (Core.SELECTED_DENOMINATION.value === this.rootStore.uiStore.denominations[i]) {\n                selectedRow = true;\n                rowBackground.visible = false;\n                if (!this.isMysteryOrPremiumJackpot) {\n                    this.rowsBackgroundsSelected[i].visible = true;\n                }\n            } else {\n                rowBackground.visible = true;\n                if (!this.isMysteryOrPremiumJackpot) {\n                    this.rowsBackgroundsSelected[i].visible = false;\n                }\n            }\n\n            if (this.componentConfiguration.additionalText.hasAdditionalText) {\n                this.createAdditionalText(i, selectedRow);\n            }\n            // this.betButtons.push([]);\n\n            const startIdx = i * cols;\n            const endIdx = startIdx + cols;\n\n            for (\n                let t: number = startIdx;\n                t < endIdx && t < this.rootStore.uiStore.bets.length * this.rootStore.uiStore.denominations.length;\n                t++\n            ) {\n                let selectedButton: boolean = false;\n                const betIndex = this.oneDenomView ? t : t % this.rootStore.uiStore.bets.length;\n                if (\n                    this.rootStore.uiStore.SELECTED_BET.value === this.rootStore.uiStore.bets[betIndex] &&\n                    selectedRow\n                ) {\n                    selectedButton = true;\n                }\n\n                const denomIndex = this.oneDenomView ? 0 : Math.floor(t / this.rootStore.uiStore.bets.length);\n\n                this.createBetButtons(i, betIndex, selectedRow, selectedButton, denomIndex);\n            }\n        }\n    }\n\n    private calculateBetsRowsOrCols(returnValue: 'cols' | 'rows'): number {\n        const bets = this.rootStore.uiStore.bets.length;\n        const denominations = this.rootStore.uiStore.denominations.length;\n        const numberOfAllBets = bets * denominations;\n        const { betsBase, dynamicLayoutThreshold } = this.componentConfiguration.betsLayoutConfig;\n\n        let cols = bets;\n        let rows = denominations;\n\n        if (this.oneDenomView) {\n            cols = betsBase;\n            rows = Math.ceil(numberOfAllBets / betsBase);\n        }\n\n        if (!Core.ORIENTATION.value.isPortrait && numberOfAllBets > dynamicLayoutThreshold) {\n            cols = Math.ceil(numberOfAllBets / betsBase);\n            rows = betsBase;\n        }\n\n        return returnValue === 'cols' ? cols : rows;\n    }\n\n    private calculateLayoutCompensationOffset(rows: number, cols: number): number {\n        const layoutConfig = this.componentConfiguration.betsLayoutConfig;\n        const sideSize = Core.ORIENTATION.value.isPortrait ? rows : cols;\n        const offset = (layoutConfig.maxSideBetCount - sideSize) * layoutConfig.betsPositionOffset;\n\n        return offset;\n    }\n\n    private createBetButtons(\n        rowIndex: number,\n        betIndex: number,\n        selectedRow: boolean,\n        selectedButton: boolean,\n        denomIndex: number,\n    ): void {\n        const textureType: string = this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value\n            ? 'Special'\n            : '';\n\n        const btnTextures: BetSettingsButtonTextures = new BetSettingsButtonTextures(\n            this.betBtnTextures.get('Normal' + textureType) as Texture,\n            this.betBtnTextures.get('Focus' + textureType) as Texture,\n            this.betBtnTextures.get('Selected' + textureType) as Texture,\n            this.betBtnTextures.get('Disabled' + textureType) as Texture,\n            this.betBtnTextures.get('Hover' + textureType) as Texture,\n            this.betBtnTextures.get('Pressed' + textureType) as Texture,\n        );\n\n        const factor = this.componentConfiguration.additionalText.lines\n            ? (this.rootStore.settings.numberOfLinesPerDenomination?.[rowIndex][1] ?? this.rootStore.settings.factor)\n            : this.rootStore.settings.factor;\n\n        const maxBetLimits =\n            this.rootStore.settings.settings.settings?.clientSettings?.maxBetLimits &&\n            Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS)\n                ? this.rootStore.settings.settings.settings.clientSettings.maxBetLimits[\n                      this.rootStore.settings.currency\n                  ]\n                : undefined;\n        const buyBonusDenominations = this.settings.buyBonusDenominations ?? undefined;\n        const oneDenom = this.rootStore.uiStore.denominations.length === 1;\n        const denom: number = oneDenom\n            ? this.rootStore.uiStore.denominations[0]\n            : this.rootStore.uiStore.denominations[denomIndex];\n        // TODO: When the turtle layout flag is available in the load response,\n        // update the initial settings logic to:\n        // - stop filtering bets by jurisdictional maxBet\n        // - use uiStore.bets instead of settings.allBets for the +/- layout\n        const bet: number = this.rootStore.uiStore.bets[betIndex];\n\n        const button = new BetSettingButtonCommon(\n            denom,\n            bet,\n            factor,\n            btnTextures,\n            this.componentConfiguration.popUpButtonsText.valueOffset.valueOf(),\n            this.componentConfiguration.popUpButtonsText.currencyOffset.valueOf(),\n            Object.assign({}, this.componentConfiguration.popUpButtonsText.normalTextStyle),\n            Object.assign({}, this.componentConfiguration.popUpButtonsText.currencyNormalTextStyle),\n            Object.assign({}, this.componentConfiguration.popUpButtonsText.currencyHilightedTextStyle),\n            Object.assign({}, this.componentConfiguration.popUpButtonsText.hilightedTextStyle),\n            this.componentConfiguration.popUpButtonsText.width.valueOf(),\n            this.componentConfiguration.popUpButtonsText.height.valueOf(),\n            this.createJpStamp(betIndex),\n            this.componentConfiguration.jackpotStampConfig?.offset,\n            this.rootStore.settings.maxBet,\n            maxBetLimits,\n            buyBonusDenominations,\n        );\n\n        button.buyBonusActivated = this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value;\n\n        // if (selectedRoll) {\n        //     button.setHilighted();\n        // }\n        if (selectedRow && this.shouldHighlightButtonsInSelectedRow()) {\n            button.setHilighted();\n        }\n        if (selectedButton) {\n            button.setSelected();\n        }\n\n        button.interactive = true;\n        button.pivot.set(button.width / 2, button.height / 2);\n        this.addChild(button);\n\n        this.betButtons.push({ button: button, row: rowIndex, denom, bet });\n    }\n\n    private createJpStamp(betIndex: number): Sprite | undefined {\n        if (this.componentConfiguration.jackpotStampConfig && betIndex === this.rootStore.uiStore.bets.length - 1) {\n            const jackpotStamp = new Sprite(\n                Core.assets.getTextureFromSpriteSheet('calculatorResources', 'jackpot.png'),\n            );\n            jackpotStamp.name = 'jackpotStamp';\n            return jackpotStamp;\n        } else {\n            return undefined;\n        }\n    }\n\n    private killAllAnimations(): void {\n        if (this.animationTween) {\n            this.animationTween.kill();\n            this.animationTween = null;\n        }\n\n        this.killPressingAnimation();\n    }\n\n    private setOrientation(): void {\n        const cols = this.calculateBetsRowsOrCols('cols');\n        const rows = this.calculateBetsRowsOrCols('rows');\n        this.killAllAnimations();\n        const currencyValueGap = this.componentConfiguration.popUpButtonsText.currencyValueGap;\n        const oldBtnTextFontSize = this.componentConfiguration.popUpButtonsText.normalTextStyle.fontSize as number;\n        const btnTextFontSize = this.findProperFontSize(\n            this.componentConfiguration.popUpButtonsText.normalTextStyle.fontSize as number,\n        );\n        let line: number = 0;\n        let betsPerLine: number = 0;\n        const layoutCompensationOffset = this.calculateLayoutCompensationOffset(rows, cols);\n\n        for (const betButton of this.betButtons) {\n            const rowsPositionOffset = this.componentConfiguration.useBetsPerLineFromConfiguration\n                ? 0\n                : this.componentConfiguration.rowsBackgroundPositions.length - this.rowsBackgrounds.length;\n\n            // for (let t: number = 0; t < this.betButtons[i].length; t++) {\n            const scale = betButton.button.scale.x;\n            betButton.button.scale.set(1);\n\n            betButton.button.scale.set(scale);\n            betButton.button.getBtnText().style.fontSize =\n                btnTextFontSize !== 0 ? btnTextFontSize : (this.getBtnTextStyle(line, betsPerLine).fontSize as number);\n            betButton.button.getBtnText().style.lineHeight =\n                btnTextFontSize !== 0 ? btnTextFontSize : (this.getBtnTextStyle(line, betsPerLine).fontSize as number);\n            if (oldBtnTextFontSize !== btnTextFontSize) {\n                betButton.button.updateTextsLayout(currencyValueGap, btnTextFontSize, oldBtnTextFontSize);\n            } else {\n                betButton.button.restoreTextsDefaultLayout(oldBtnTextFontSize);\n            }\n\n            betButton.button.pivot.set(betButton.button.width / 2, betButton.button.height / 2);\n            betButton.button.x =\n                this.componentConfiguration.betBtnPositions[betsPerLine].get('x') +\n                betButton.button.width / 2 +\n                (!Core.ORIENTATION.value.isPortrait ? layoutCompensationOffset : 0);\n            betButton.button.y =\n                this.componentConfiguration.rowsBackgroundPositions[line + rowsPositionOffset].get('y') +\n                4 +\n                betButton.button.height / 2 +\n                (Core.ORIENTATION.value.isPortrait ? layoutCompensationOffset : 0);\n\n            betsPerLine++;\n            if (betsPerLine === cols) {\n                betsPerLine = 0;\n                line++;\n            }\n            // }\n        }\n\n        for (let i: number = 0; i < this.rowsBackgrounds.length; i++) {\n            const rowsPositionOffset =\n                this.componentConfiguration.useBetsPerLineFromConfiguration && !Core.ORIENTATION.value.isPortrait\n                    ? 0\n                    : this.componentConfiguration.rowsBackgroundPositions.length - this.rowsBackgrounds.length;\n            const rowHeight = this.componentConfiguration.rowsBackgroundPositions[i + rowsPositionOffset].get('height');\n            this.rowsBackgrounds[i].x =\n                this.componentConfiguration.rowsBackgroundPositions[i + rowsPositionOffset].get('x');\n            this.rowsBackgrounds[i].y =\n                this.componentConfiguration.rowsBackgroundPositions[i + rowsPositionOffset].get('y');\n            this.rowsBackgrounds[i].width =\n                this.componentConfiguration.rowsBackgroundPositions[i + rowsPositionOffset].get('width');\n            this.rowsBackgrounds[i].height =\n                this.componentConfiguration.rowsBackgroundPositions[i + rowsPositionOffset].get('height');\n\n            if (!this.isMysteryOrPremiumJackpot) {\n                this.rowsBackgroundsSelected[i].x =\n                    this.componentConfiguration.selectedRowsBackgroundPositions[i + rowsPositionOffset].get('x');\n                this.rowsBackgroundsSelected[i].y =\n                    this.componentConfiguration.selectedRowsBackgroundPositions[i + rowsPositionOffset].get('y');\n                this.rowsBackgroundsSelected[i].width =\n                    this.componentConfiguration.selectedRowsBackgroundPositions[i + rowsPositionOffset].get('width');\n                this.rowsBackgroundsSelected[i].height =\n                    this.componentConfiguration.selectedRowsBackgroundPositions[i + rowsPositionOffset].get('height');\n            }\n            if (this.componentConfiguration.additionalText.hasAdditionalText) {\n                const diff = this.additionalNumber[i].height - this.additionalText[i].height;\n                const additionalTextYOffset = this.componentConfiguration.additionalText.textYOffset;\n\n                this.additionalNumber[i].x = this.componentConfiguration.additionalText.x;\n                this.additionalNumber[i].y =\n                    this.rowsBackgrounds[i].y +\n                    rowHeight / 2 -\n                    this.additionalNumber[i].height / 2 +\n                    diff / 2 +\n                    additionalTextYOffset;\n\n                this.additionalText[i].x = this.componentConfiguration.additionalText.x;\n                this.additionalText[i].y =\n                    this.rowsBackgrounds[i].y +\n                    rowHeight / 2 +\n                    this.additionalText[i].height / 2 +\n                    diff / 2 +\n                    additionalTextYOffset;\n            }\n        }\n\n        this.globalPosition = { x: this.rowsBackgrounds[0].x, y: this.rowsBackgrounds[0].y };\n    }\n\n    private resetAllButtonsFontSize(): void {\n        const originalFontSize = this.componentConfiguration.popUpButtonsText.normalTextStyle.fontSize as number;\n        for (const btn of this.betButtons) {\n            // for (const btn of row) {\n            btn.button.getBtnText().style.fontSize = originalFontSize;\n            btn.button.getBtnText().style.lineHeight = originalFontSize;\n            // }\n        }\n    }\n\n    protected findProperFontSize(defaultFontSize: number): number {\n        if (!this.componentConfiguration.popUpButtonsText.shouldFitInBounds) {\n            return 0;\n        }\n\n        let minFontSize: number = defaultFontSize;\n\n        for (const betButton of this.betButtons) {\n            // for (const betButton of denomBetButton) {\n            let fontSize: number = betButton.button.getBtnText().style.fontSize as number;\n            if (betButton.button.getBtnText().width > this.componentConfiguration.popUpButtonsText.widthBounds) {\n                fontSize = Math.round(\n                    fontSize *\n                        (this.componentConfiguration.popUpButtonsText.widthBounds /\n                            betButton.button.getBtnText().width),\n                );\n            }\n            minFontSize = Math.min(minFontSize, fontSize);\n            // }\n        }\n        if (defaultFontSize > minFontSize) {\n            return minFontSize;\n        }\n        return defaultFontSize;\n    }\n\n    private deselectAllButtons(): void {\n        for (const btn of this.betButtons) {\n            // for (const btn of roll) {\n            btn.button.setNormal();\n            btn.button.scale.set(1);\n            btn.button.pivot.set(btn.button.width / 2, btn.button.height / 2);\n            btn.button.alpha = 1;\n            btn.button.children[0].alpha = 1;\n            // }\n        }\n    }\n\n    private deselectAllRows(): void {\n        for (let i: number = 0; i < this.rowsBackgrounds.length; i++) {\n            this.rowsBackgrounds[i].visible = true;\n            if (!this.isMysteryOrPremiumJackpot) {\n                this.rowsBackgroundsSelected[i].visible = false;\n            }\n            if (this.componentConfiguration.additionalText.hasAdditionalText) {\n                this.additionalNumber[i].style = this.componentConfiguration.additionalText.valueStyle;\n                this.additionalText[i].style = this.componentConfiguration.additionalText.textStyle;\n            }\n        }\n    }\n\n    private getBtnTextStyle(denomIndex: number, betIndex: number): TextStyle {\n        return !this.isSelected(denomIndex, betIndex) && this.componentConfiguration.popUpButtonsText.hilightedTextStyle\n            ? this.componentConfiguration.popUpButtonsText.hilightedTextStyle\n            : this.componentConfiguration.popUpButtonsText.normalTextStyle;\n    }\n\n    private isSelected(denomIndex: number, betIndex: number): boolean {\n        return (\n            Core.SELECTED_DENOMINATION.value === this.rootStore.uiStore.denominations[denomIndex] &&\n            this.rootStore.uiStore.SELECTED_BET.value === this.rootStore.uiStore.bets[betIndex]\n        );\n    }\n\n    private shouldHighlightButtonsInSelectedRow(): boolean {\n        return !this.oneDenomView && this.componentConfiguration.additionalText.hasAdditionalText;\n    }\n\n    private killPressingAnimation(): void {\n        if (this.pressingAnimation && this.pressingAnimation !== null) {\n            this.pressingAnimation.totalProgress(1, true);\n            this.pressingAnimation.kill();\n            // @ts-ignore\n            this.pressingAnimation = null;\n        }\n    }\n\n    private destroyArray(arr: any[]) {\n        for (let i: number = 0; i < arr.length; i++) {\n            this.destroyObject(arr[i]);\n        }\n        // @ts-ignore\n        arr = null;\n    }\n\n    private destroyObject(obj: any) {\n        obj?.destroy?.();\n        // @ts-ignore\n        obj = null;\n    }\n\n    private changeNumberOfLines(denomination: number): void {\n        if (\n            this.rootStore.settings.numberOfLinesPerDenomination &&\n            this.rootStore.settings.numberOfLinesPerDenomination.length\n        ) {\n            const [, numberOfLines] = this.rootStore.settings.numberOfLinesPerDenomination.find(\n                ([denominationConfig]) => denominationConfig === denomination,\n            )!;\n\n            if (this.rootStore.uiStore.LINES.value !== numberOfLines) {\n                this.rootStore.uiStore.LINES.next(numberOfLines!);\n            }\n        }\n    }\n}\n","import Core, { AssetPriority, BaseComponent, IModeConfig } from '@egt/core';\nimport { ReelsOverlayView, ReelsOverlayZOrders } from '@egt/reels-overlay';\nimport { ISlotConfiguration, SlotComponents, ZOrders } from '@egt/slot';\nimport { Lifecycle } from 'tsyringe';\nimport BackgroundAnimationModesConfigurations, { BackgroundAnimationModes } from './BackgroundAnimationModeFactory';\nimport { BackgroundAnimationComponentConfigurationFactoryDefault } from './modes/default/configuration/BackgroundAnimationComponentConfigurationDefault';\nimport { IBackgroundAnimationComponentConfigurationDefault } from './modes/default/configuration/IBackgroundAnimationComponentConfigurationDefault';\nimport { BackgroundAnimationComponentConfigurationFactoryDesktopForLandscape } from './modes/desktopForLandscape/configuration/BackgroundAnimationComponentConfigurationDesktopForLandscape';\n\nexport default class BackgroundAnimationComponent extends BaseComponent {\n    public static configurationName = 'BackgroundAnimationComponent';\n\n    public backgroundAnimationView: any;\n    public componentType = SlotComponents.BG_ANIMATION;\n    public configuration: IBackgroundAnimationComponentConfigurationDefault;\n    public rootView: any;\n    public gameSettings: any;\n    public slotConfig: ISlotConfiguration;\n    private assetLoaded: boolean = false;\n\n    constructor(modeConfig: IModeConfig) {\n        super();\n        const baseConfigs = {\n            [BackgroundAnimationModes.DEFAULT]: BackgroundAnimationComponentConfigurationFactoryDefault,\n            [BackgroundAnimationModes.DESKTOP_FOR_LANDSCAPE]:\n                BackgroundAnimationComponentConfigurationFactoryDesktopForLandscape,\n        };\n\n        this.modeFactory = this.initMode<BackgroundAnimationModesConfigurations>(modeConfig, {\n            defaultModeType: BackgroundAnimationModes.DEFAULT,\n            baseConfigs,\n            defaultFactory: BackgroundAnimationModesConfigurations,\n        });\n    }\n\n    public destroy(): void {\n        this.backgroundAnimationView.destroy();\n        // @ts-ignore\n        this.backgroundAnimationView = null;\n\n        (this.configuration as any).destroy();\n        // @ts-ignore\n        this.configuration = null;\n        // @ts-ignore\n        this.rootView = null;\n        // @ts-ignore\n        this.slotConfig = null;\n\n        super.destroy();\n    }\n\n    public onAfterGameConfigurationCreated(): void {\n        super.onAfterGameConfigurationCreated();\n        this.slotConfig = this.dependencyContainer.resolve('ISlotConfiguration');\n        this.configuration = this.dependencyContainer.resolve('BackgroundAnimationComponentConfiguration');\n    }\n\n    public onRegisterDependencies(container: any): void {\n        super.onRegisterDependencies(container);\n        // if (!this.dependencyContainer.isRegistered('BackgroundAnimationView')) {\n        this.dependencyContainer.register(\n            'BackgroundAnimationView',\n            { useClass: this.mode.view },\n            { lifecycle: Lifecycle.Singleton },\n        );\n        // }\n        this.dependencyContainer.register('BackgroundAnimationComponentConfiguration', this.mode.configuration);\n    }\n\n    public onResolveDependencies(container: any): void {\n        super.onResolveDependencies(container);\n\n        this.rootView = this.dependencyContainer.resolve('RootView');\n        this.backgroundAnimationView = this.dependencyContainer.resolve('BackgroundAnimationView');\n        if (this.assetLoaded) {\n            this.backgroundAnimationView.onComponentReady();\n        }\n        this.backgroundAnimationView.name = 'BackgroundAnimationView';\n\n        if (!this.configuration.positionOverSlices) {\n            this.backgroundAnimationView.zIndex = ZOrders.REELS_LEVEL - 2;\n            this.rootView.addChild(this.backgroundAnimationView);\n        } else {\n            const reelsOverlay: ReelsOverlayView = this.dependencyContainer.resolve('ReelsOverlay');\n            this.backgroundAnimationView.zIndex = ReelsOverlayZOrders.BACKGROUND_ANIMATIONS;\n            reelsOverlay.addChild(this.backgroundAnimationView);\n        }\n    }\n\n    public onPrepareResources(): void {\n        const game = this.gameSettings.game;\n        let priority: AssetPriority = this.configuration.backgroundAnimationAssetPriority;\n        if (game && game.state && game.state.rounds) {\n            const rounds = this.gameSettings.game.state.rounds;\n            if (rounds && rounds.length && rounds[0].type === 'RESPIN') {\n                priority = AssetPriority.HIGH;\n            }\n        }\n        const bgAsset = this.configuration?.assets?.toArray().find((a) => a.id === 'backgroundAnimation');\n        if (bgAsset && bgAsset.priority < priority) {\n            bgAsset.priority = priority;\n        }\n        Core.assets.addAssets(this.configuration?.assets?.toArray() || []);\n    }\n\n    public onIndividualAssetLoaded(asset: any): void {\n        super.onIndividualAssetLoaded.apply(this, arguments);\n        if (asset.asset.id === 'backgroundAnimation') {\n            this.assetLoaded = true;\n            this.backgroundAnimationView?.onComponentReady();\n        }\n    }\n\n    public onGameSettings(gameSettings: any): void {\n        this.gameSettings = gameSettings;\n    }\n}\n","import { BaseModesConfigurations, IForceSetConfig, IModes } from '@egt/core';\nimport { BackgroundAnimationComponentConfigurationFactoryDefault } from './modes/default/configuration/BackgroundAnimationComponentConfigurationDefault';\nimport BackgroundAnimationViewDefault from './modes/default/views/BackgroundAnimationViewDefault';\nimport { BackgroundAnimationComponentConfigurationFactoryDesktopForLandscape } from './modes/desktopForLandscape/configuration/BackgroundAnimationComponentConfigurationDesktopForLandscape';\n\nexport default class BackgroundAnimationModesConfigurations extends BaseModesConfigurations<BackgroundAnimationModes> {\n    constructor(modeType: BackgroundAnimationModes, forceSetConfig?: IForceSetConfig) {\n        super(modeType, forceSetConfig);\n    }\n\n    protected createBaseModesConfig(modeType: BackgroundAnimationModes): IModes {\n        switch (modeType) {\n            case BackgroundAnimationModes.DESKTOP_FOR_LANDSCAPE:\n                return {\n                    view: BackgroundAnimationViewDefault,\n                    configuration: BackgroundAnimationComponentConfigurationFactoryDesktopForLandscape(),\n                };\n            default:\n                return {\n                    view: BackgroundAnimationViewDefault,\n                    configuration: BackgroundAnimationComponentConfigurationFactoryDefault(),\n                };\n        }\n    }\n}\n\nexport enum BackgroundAnimationModes {\n    DEFAULT = 'default',\n    DESKTOP_FOR_LANDSCAPE = 'desktopForLandscape',\n}\n","import BackgroundAnimationComponent from './BackgroundAnimationComponent';\nimport BackgroundAnimationComponentConfigurationDefault from './modes/default/configuration/BackgroundAnimationComponentConfigurationDefault';\nimport { IBackgroundAnimationComponentConfigurationDefault } from './modes/default/configuration/IBackgroundAnimationComponentConfigurationDefault';\nimport BackgroundAnimationViewDefault from './modes/default/views/BackgroundAnimationViewDefault';\nimport { BackgroundAnimationModes } from './BackgroundAnimationModeFactory';\nimport { IBackgroundAnimationComponentConfigurationDesktopForLandscape } from './modes/desktopForLandscape/configuration/IBackgroundAnimationComponentConfigurationDesktopForLandscape';\nimport BackgroundAnimationComponentConfigurationDesktopForLandscape from './modes/desktopForLandscape/configuration/BackgroundAnimationComponentConfigurationDesktopForLandscape';\n\nexport {\n    BackgroundAnimationViewDefault,\n    IBackgroundAnimationComponentConfigurationDefault,\n    BackgroundAnimationComponentConfigurationDefault,\n    IBackgroundAnimationComponentConfigurationDesktopForLandscape,\n    BackgroundAnimationComponentConfigurationDesktopForLandscape,\n    BackgroundAnimationModes,\n};\nexport default BackgroundAnimationComponent;\n","import Core, { AssetPriority, AssetsCollection, BaseComponentConfiguration, DefaultAssets } from '@egt/core';\nimport { IBackgroundAnimationComponentConfigurationDefault } from './IBackgroundAnimationComponentConfigurationDefault';\n\nexport default class BackgroundAnimationComponentConfigurationDefault extends BaseComponentConfiguration {\n    public positionOverSlices: boolean = true;\n    public backgroundAnimationAssetPriority: AssetPriority = AssetPriority.LOW;\n}\n\nexport function BackgroundAnimationComponentConfigurationFactoryDefault(): any {\n    class BackgroundAnimationComponentConfigurationInternalClass\n        extends BackgroundAnimationComponentConfigurationDefault\n        implements IBackgroundAnimationComponentConfigurationDefault\n    {\n        @DefaultAssets([\n            {\n                id: 'backgroundAnimation',\n                url: '../assets/' + Core.configuration.gameKey + '/mainResources/backgroundAnimation.json',\n                priority: AssetPriority.LOW,\n                type: 'spineAnimation',\n            },\n        ])\n        public assets: AssetsCollection;\n\n        public useDesktopAnimForLandscape: boolean = false;\n\n        public x: number = 0;\n        public y: number = 0;\n        /* in seconds - appearance duration of background animation after it is loaded */\n        public fadeInDuration: number = 1;\n    }\n    return BackgroundAnimationComponentConfigurationInternalClass;\n}\n","import Core, { Timers } from '@egt/core';\nimport { ISlotConfiguration, RootStore } from '@egt/slot';\nimport { IBackgroundAssets, ViewContainer } from '@egt/ui-lib';\nimport { gsap } from 'gsap';\nimport { Sprite } from 'pixi.js';\nimport { merge } from 'rxjs';\nimport { skip, takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { IBackgroundAnimationComponentConfigurationDefault } from '../configuration/IBackgroundAnimationComponentConfigurationDefault';\n\n@injectable()\nexport default class BackgroundAnimationViewDefault extends ViewContainer {\n    public backgroundAnimation: any;\n    // portrait, landscape textures loaded until background animation is done\n    // if we have backgroundAnimationStaticLandscape / Portrait - this is shown until animation is loaded\n    // the this sprite is deleted and animation shown imediatly without duration\n    protected staticBackgroundSprite: Sprite;\n    protected fadeTween: any;\n    protected backgroundAnimationListener: any;\n    protected prevAnimType: string;\n    protected nextAnimType: string;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('BackgroundAnimationComponentConfiguration')\n        protected componentConfiguration: IBackgroundAnimationComponentConfigurationDefault,\n    ) {\n        super();\n        this.rootStore.subjects.CHANGE_BACKGROUND.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onBackgroundChanged.bind(this),\n        );\n        this.rootStore.subjects.SHOW_BACKGROUND.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onShowBackground.bind(this),\n        );\n        this.rootStore.subjects.SET_BACKGROUND_ANIMATION.pipe(takeUntil(this.DESTROY), skip(1)).subscribe(\n            this.setBackgroundAnimation.bind(this),\n        );\n\n        const orientation = merge(Core.ORIENTATION, this.rootStore.subjects.PLAY_FS_BACKGROUND_ANIMATIONS);\n        orientation.pipe(takeUntil(this.DESTROY)).subscribe(this.backgroundAnimSetOrientation.bind(this));\n\n        if (slotConfiguration.backgroundAnimationShouldPauseOnGamePause) {\n            Core.ON_GAME_PAUSED.pipe(takeUntil(this.DESTROY)).subscribe((paused) => {\n                this.visible = paused === 'NONE';\n            });\n        }\n    }\n\n    public onComponentReady(): void {\n        this.initialRender();\n    }\n\n    public destroy(): void {\n        if (this.backgroundAnimation) {\n            this.backgroundAnimation.destroy();\n            this.removeChild(this.backgroundAnimation);\n            this.backgroundAnimation = null;\n        }\n\n        if (this.staticBackgroundSprite) {\n            this.removeChild(this.staticBackgroundSprite);\n            this.staticBackgroundSprite.destroy();\n            // @ts-ignore\n            this.staticBackgroundSprite = null;\n        }\n\n        this.killFadeTween();\n        super.destroy();\n    }\n\n    public setStaticTextures(): void {\n        // remove current if any\n        if (this.staticBackgroundSprite) {\n            this.removeChild(this.staticBackgroundSprite);\n            this.staticBackgroundSprite.destroy();\n            // @ts-ignore\n            this.staticBackgroundSprite = null;\n        }\n        // if animation is loaded - do not create static sprite\n        if (this.backgroundAnimation) {\n            return;\n        }\n        const texture = Core.assets.getTextureFromSpriteSheet(\n            'mainResources',\n            `backgroundAnimationStatic${Core.ORIENTATION.value.orientation}.png`,\n        );\n        if (texture) {\n            this.staticBackgroundSprite = new Sprite(texture);\n            this.addChild(this.staticBackgroundSprite);\n        }\n    }\n\n    public initialRender(customAssetId?: string): void {\n        const asset: string = customAssetId ? customAssetId : 'backgroundAnimation';\n        this.setAnimation(asset);\n        this.playTween();\n    }\n\n    public playTween(): void {\n        this.fadeTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/bg-animation/src/egt/modes/default/views/BackgroundAnimationViewDefault.ts:101:26\",null]), gsap.timeline({\n            onComplete: () => {\n                this.killFadeTween();\n            },\n        }));\n        this.fadeTween.to(this.backgroundAnimation, {\n            duration: this.componentConfiguration.fadeInDuration,\n            alpha: 1,\n        });\n        this.fadeTween.play();\n    }\n\n    public onShowBackground(show: boolean = true): void {\n        if (this.backgroundAnimation) {\n            this.backgroundAnimation.visible = Number(show);\n        }\n    }\n\n    public killAnimation(): void {\n        if (this.backgroundAnimation) {\n            this.backgroundAnimation.destroy();\n            this.removeChild(this.backgroundAnimation);\n            this.backgroundAnimation = null;\n        }\n    }\n\n    public setAnimation(asset): void {\n        const animAsset = Core.assets.getAsset(asset);\n        if (this.backgroundAnimation || !animAsset) {\n            return;\n        }\n\n        this.backgroundAnimation = Core.spineAnimations.createSpineAnimations(asset);\n        if (!this.backgroundAnimation) {\n            return;\n        }\n\n        const baseAnimType = 'backgroundAnimation';\n        this.prevAnimType = this.setBackgroundAnimationType();\n\n        if (\n            Core.isDesktopMode &&\n            !this.backgroundAnimation.skeleton.data.animations.find((a) => a.name === this.prevAnimType)\n        ) {\n            const animationPrefix: string = this.rootStore.subjects.PLAY_FS_BACKGROUND_ANIMATIONS.value\n                ? 'FreeSpins'\n                : '';\n            this.prevAnimType = 'backgroundAnimation' + animationPrefix + 'Landscape';\n        }\n        this.backgroundAnimation.x = Core.display.stage.width / 2;\n        this.backgroundAnimation.y = Core.display.stage.height / 2;\n        this.backgroundAnimation.alpha = 0;\n        this.addChild(this.backgroundAnimation);\n        this.backgroundAnimation.state.setAnimation(0, ((window as any).__SLN=(this.prevAnimType), ((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"spine:packages/components/slot/bg-animation/src/egt/modes/default/views/BackgroundAnimationViewDefault.ts:154:9\",(window as any).__SLN]), (window as any).__SLN), true);\n        this.rootStore.subjects.BACKGROUND_ANIMATION_STARTED.next(this.prevAnimType);\n        if (this.backgroundAnimationListener) {\n            this.backgroundAnimation.state.removeListener(this.backgroundAnimationListener);\n        }\n        this.backgroundAnimationListener = {\n            complete: () => {\n                this.rootStore.subjects.BACKGROUND_ANIMATION_FINISHED.next(this.prevAnimType);\n                if (this.rootStore.subjects.SET_BACKGROUND_ANIMATION.value.type !== baseAnimType) {\n                    this.backgroundAnimation.state.setAnimation(0, ((window as any).__SLN=(this.setBackgroundAnimationType()), ((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"spine:packages/components/slot/bg-animation/src/egt/modes/default/views/BackgroundAnimationViewDefault.ts:163:21\",(window as any).__SLN]), (window as any).__SLN), true);\n                    this.prevAnimType = this.setBackgroundAnimationType();\n                    this.rootStore.subjects.BACKGROUND_ANIMATION_STARTED.next(this.setBackgroundAnimationType());\n                }\n            },\n        };\n        this.backgroundAnimation.state.addListener(this.backgroundAnimationListener);\n        Timers.setTimeout(() => {\n            this.setStaticTextures();\n        }, 0);\n    }\n\n    public onBackgroundChanged(param: IBackgroundAssets): void {\n        this.killAnimation();\n        this.initialRender(param.backgroundAnimation);\n    }\n\n    public setBackgroundAnimation(): void {\n        if (!this.backgroundAnimation) {\n            return;\n        }\n        this.nextAnimType = this.setNextAnimationType(this.rootStore.subjects.SET_BACKGROUND_ANIMATION.value.type);\n        const duration = this.rootStore.subjects.SET_BACKGROUND_ANIMATION.value.duration;\n        this.backgroundAnimation.stateData.setMix(this.prevAnimType, this.nextAnimType, duration ? duration : 0.2);\n        this.backgroundAnimation.state.setAnimation(0, ((window as any).__SLN=(this.nextAnimType), ((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"spine:packages/components/slot/bg-animation/src/egt/modes/default/views/BackgroundAnimationViewDefault.ts:187:9\",(window as any).__SLN]), (window as any).__SLN), false);\n        this.prevAnimType = this.nextAnimType;\n        this.rootStore.subjects.BACKGROUND_ANIMATION_STARTED.next(this.nextAnimType);\n    }\n\n    public setNextAnimationType(type: string): string {\n        let animationType = type + 'Landscape';\n        if (Core.ORIENTATION.value.isPortrait) {\n            animationType = type + 'Portrait';\n        }\n\n        return animationType;\n    }\n\n    public backgroundAnimSetOrientation(): void {\n        this.setStaticTextures();\n        if (!this.backgroundAnimation) {\n            return;\n        }\n        const animType = this.setBackgroundAnimationType();\n\n        const trackTime = this.backgroundAnimation.state.getCurrent(0).trackTime;\n        this.backgroundAnimation.x = Core.display.stage.width / 2;\n        this.backgroundAnimation.y = Core.display.stage.height / 2;\n        this.backgroundAnimation.state.setAnimation(0, ((window as any).__SLN=(animType), ((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"spine:packages/components/slot/bg-animation/src/egt/modes/default/views/BackgroundAnimationViewDefault.ts:211:9\",(window as any).__SLN]), (window as any).__SLN), true);\n        this.backgroundAnimation.state.getCurrent(0).trackTime = trackTime;\n        this.killFadeTween();\n        this.backgroundAnimation.alpha = 1;\n    }\n\n    public setBackgroundAnimationType(): string {\n        let animationType: string;\n        let animationPrefix: string = this.rootStore.subjects.PLAY_FS_BACKGROUND_ANIMATIONS.value ? 'FreeSpins' : '';\n\n        if (\n            animationPrefix === 'FreeSpins' &&\n            this.rootStore.settings.haveGameMode(this.slotConfiguration.superBuyBonusGameMode) &&\n            this.rootStore.domainStore.betResponse?.gameState.bet.factor ===\n                this.rootStore.settings.getFactorByUniqueGameMode(this.slotConfiguration.superBuyBonusGameMode)\n        ) {\n            animationPrefix = 'SuperFreeSpins';\n        }\n\n        const animType = this.componentConfiguration.useDesktopAnimForLandscape ? 'Desktop' : 'Landscape';\n        animationType = 'backgroundAnimation' + animationPrefix + animType;\n        if (\n            Core.isDesktopMode &&\n            this.backgroundAnimation.skeleton.data.animations.find(\n                (a) => a.name === 'backgroundAnimation' + animationPrefix + 'Desktop',\n            )\n        ) {\n            animationType = 'backgroundAnimation' + animationPrefix + 'Desktop';\n        } else {\n            if (Core.ORIENTATION.value.isPortrait) {\n                animationType = 'backgroundAnimation' + animationPrefix + 'Portrait';\n            }\n        }\n        return animationType;\n    }\n\n    protected killFadeTween(): void {\n        if (this.fadeTween) {\n            this.fadeTween.kill();\n            this.fadeTween = null;\n        }\n    }\n}\n","import Core, { AssetPriority, AssetsCollection, BaseComponentConfiguration, DefaultAssets } from '@egt/core';\nimport { IBackgroundAnimationComponentConfigurationDesktopForLandscape } from './IBackgroundAnimationComponentConfigurationDesktopForLandscape';\n\nexport default class BackgroundAnimationComponentConfigurationDesktopForLandscape extends BaseComponentConfiguration {\n    public positionOverSlices: boolean = true;\n    public backgroundAnimationAssetPriority: AssetPriority = AssetPriority.LOW;\n}\n\nexport function BackgroundAnimationComponentConfigurationFactoryDesktopForLandscape(): any {\n    class InternalClass\n        extends BackgroundAnimationComponentConfigurationDesktopForLandscape\n        implements IBackgroundAnimationComponentConfigurationDesktopForLandscape\n    {\n        @DefaultAssets([\n            {\n                id: 'backgroundAnimation',\n                url: '../assets/' + Core.configuration.gameKey + '/mainResources/backgroundAnimation.json',\n                priority: AssetPriority.LOW,\n                type: 'spineAnimation',\n            },\n        ])\n        public assets: AssetsCollection;\n\n        public useDesktopAnimForLandscape: boolean = true;\n\n        public x: number = 0;\n        public y: number = 0;\n        /* in seconds - appearance duration of background animation after it is loaded */\n        public fadeInDuration: number = 1;\n    }\n    return InternalClass;\n}\n","import Core, { BaseComponent, FeatureFlags, type IModeConfig } from '@egt/core';\nimport { type ISlotConfiguration, SlotComponents, ZOrders } from '@egt/slot';\nimport { Lifecycle } from 'tsyringe';\nimport BuyBonusModesConfigurations, { BuyBonusModes } from './BuyBonusModeFactory';\nimport { DoubleChanceComponentConfigurationFactoryCommon } from './common/double-chance/configuration/DoubleChanceComponentConfigurationCommon';\nimport DoubleChanceControllerCommon from './common/double-chance/controllers/DoubleChanceControllerCommon';\nimport DoubleChanceViewCommon from './common/double-chance/views/DoubleChanceViewCommon';\nimport { BuyBonusComponentConfigurationFactoryDefault } from './modes/default/configuration/BuyBonusComponentConfigurationDefault';\nimport { BuyBonusComponentConfigurationFactoryExtendedMultipleBuyBonus } from './modes/extended-multiple-buy-bonus/configuration/BuyBonusComponentConfigurationExtendedMultipleBuyBonus';\nimport { BuyBonusComponentConfigurationFactoryMultipleBuyBonus } from './modes/multiple-buy-bonus/configuration/BuyBonusComponentConfigurationMultipleBuyBonus';\nimport type { IDoubleChanceComponentConfigurationCommon } from './common/double-chance/interfaces/InterfacesDoubleChanceCommon';\nimport type { IBuyBonusComponentConfigurationDefault } from './modes/default/interfaces/InterfacesDefault';\nimport type { IBuyBonusComponentConfigurationExtendedMultipleBuyBonus } from './modes/extended-multiple-buy-bonus/configuration/IBuyBonusComponentConfigurationExtendedMultipleBuyBonus';\nimport type { IBuyBonusComponentConfigurationMultipleBuyBonus } from './modes/multiple-buy-bonus/configuration/IBuyBonusComponentConfigurationMultipleBuyBonus';\n\nexport interface IBuyBonusModeConfig extends IModeConfig {\n    // The double chance sub-part is not a mode: it is always part of the DEFAULT and MULTIPLE_BUY_BONUS\n    // modes (the noDoubleChance jurisdiction restriction skips it at runtime). In\n    // EXTENDED_MULTIPLE_BUY_BONUS it is built into the view itself.\n    // Its configuration and view are passed through IModeConfig.secondConfiguration / secondView\n    // (both merged between template and game entries like the primary configuration / view). The\n    // controller custom key below does NOT merge - state it explicitly at game creation sites.\n    doubleChanceController?: { [modeType: string]: any };\n}\n\nexport default class BuyBonusComponent extends BaseComponent {\n    public static configurationName = 'BuyBonusComponent';\n    public static doubleChanceConfigurationName = 'DoubleChanceComponent';\n\n    public buyBonusView: any;\n    public doubleChanceView: any;\n    public componentType = SlotComponents.BUY_BONUS;\n    public configuration:\n        | IBuyBonusComponentConfigurationDefault\n        | IBuyBonusComponentConfigurationMultipleBuyBonus\n        | IBuyBonusComponentConfigurationExtendedMultipleBuyBonus;\n    public doubleChanceConfiguration: IDoubleChanceComponentConfigurationCommon;\n    public rootView;\n    // jurisdiction restrictions no longer remove the component - the affected part is skipped instead\n    public hasBuyBonusPart: boolean = true;\n    public hasDoubleChancePart: boolean = false;\n\n    private buyBonusController: any;\n    private doubleChanceController: any;\n    private initialSettings: any;\n    private modeConfig: IBuyBonusModeConfig = {};\n    private hasCustomConfiguration: boolean = false;\n    // resolved EXTENDED no-double-chance configuration (from secondConfiguration); registered instead of\n    // the primary configuration when the noDoubleChance jurisdiction restriction is active\n    private extendedNoDoubleChanceConfiguration: any;\n\n    constructor(configOrModeConfig?: IBuyBonusModeConfig | ((base: any) => any)) {\n        super();\n\n        const baseConfigs = {\n            [BuyBonusModes.DEFAULT]: BuyBonusComponentConfigurationFactoryDefault,\n            [BuyBonusModes.MULTIPLE_BUY_BONUS]: BuyBonusComponentConfigurationFactoryMultipleBuyBonus,\n            [BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS]: BuyBonusComponentConfigurationFactoryExtendedMultipleBuyBonus,\n        };\n\n        // backward compatibility: old call sites pass a configuration factory function\n        if (typeof configOrModeConfig === 'function') {\n            this.modeConfig = {\n                modeType: BuyBonusModes.DEFAULT,\n                configuration: { [BuyBonusModes.DEFAULT]: configOrModeConfig },\n            };\n        } else if (configOrModeConfig) {\n            this.modeConfig = configOrModeConfig;\n        }\n\n        const modeType = this.modeConfig.forceMode ?? this.modeConfig.modeType ?? BuyBonusModes.DEFAULT;\n        this.hasCustomConfiguration = !!this.modeConfig.configuration?.[modeType];\n\n        // in EXTENDED mode the secondConfiguration holds the no-double-chance variant of the buy bonus\n        // configuration (resolved over the same base as the primary one); it is registered instead of the\n        // primary configuration when the noDoubleChance restriction is active (see onRegisterDependencies)\n        if (modeType === BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS) {\n            const secondConfigFactory = this.modeConfig.secondConfiguration?.[modeType];\n            if (secondConfigFactory) {\n                this.extendedNoDoubleChanceConfiguration = secondConfigFactory(baseConfigs[modeType]());\n            }\n        }\n\n        this.modeFactory = this.initMode<BuyBonusModesConfigurations>(this.modeConfig, {\n            defaultModeType: BuyBonusModes.DEFAULT,\n            baseConfigs,\n            defaultFactory: BuyBonusModesConfigurations,\n        });\n    }\n\n    public destroy(): void {\n        this.buyBonusController?.destroy();\n        this.buyBonusController = null;\n        this.buyBonusView = null;\n        this.doubleChanceController?.destroy();\n        this.doubleChanceController = null;\n        this.doubleChanceView = null;\n        // @ts-ignore\n        this.configuration?.destroy?.();\n        // @ts-ignore\n        this.configuration = null;\n        // @ts-ignore\n        this.doubleChanceConfiguration = null;\n        this.extendedNoDoubleChanceConfiguration = null;\n        // @ts-ignore\n        this.rootView = null;\n        this.initialSettings = null;\n        // @ts-ignore\n        this.modeConfig = null;\n\n        super.destroy();\n    }\n\n    public onAfterGameConfigurationCreated(): void {\n        super.onAfterGameConfigurationCreated();\n        if (this.hasBuyBonusPart) {\n            this.configuration = this.dependencyContainer.resolve('BuyBonusComponentConfiguration');\n        }\n        if (this.hasDoubleChancePart) {\n            const slotConfig: ISlotConfiguration = this.dependencyContainer.resolve('ISlotConfiguration');\n            this.doubleChanceConfiguration = this.dependencyContainer.resolve('DoubleChanceComponentConfiguration');\n            if (slotConfig.componentsConfiguration.hasOwnProperty(BuyBonusComponent.doubleChanceConfigurationName)) {\n                Object.keys(\n                    slotConfig.componentsConfiguration[BuyBonusComponent.doubleChanceConfigurationName],\n                ).forEach((key) => {\n                    this.doubleChanceConfiguration[key] =\n                        slotConfig.componentsConfiguration[BuyBonusComponent.doubleChanceConfigurationName][key];\n                });\n            }\n        }\n    }\n\n    public onRegisterDependencies(container: any): void {\n        super.onRegisterDependencies(container);\n        this.resolveParts();\n\n        if (this.hasBuyBonusPart) {\n            if (!this.dependencyContainer.isRegistered('BuyBonusView')) {\n                this.dependencyContainer.register(\n                    'BuyBonusView',\n                    { useClass: this.mode.view },\n                    { lifecycle: Lifecycle.Singleton },\n                );\n            }\n            this.dependencyContainer.register(\n                'BuyBonusController',\n                { useClass: this.mode.controller },\n                { lifecycle: Lifecycle.Singleton },\n            );\n\n            const configuration =\n                this.modeFactory.modeType === BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS &&\n                this.extendedNoDoubleChanceConfiguration &&\n                Core.flags.isActive(FeatureFlags.HIDE_DOUBLE_CHANCE)\n                    ? this.extendedNoDoubleChanceConfiguration\n                    : this.mode.configuration;\n            if (\n                this.modeFactory.modeType === BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS &&\n                this.hasCustomConfiguration\n            ) {\n                // should be singleton because we want to change some properties based on load game response\n                this.dependencyContainer.registerSingleton('BuyBonusComponentConfiguration', configuration);\n            } else {\n                this.dependencyContainer.register('BuyBonusComponentConfiguration', configuration);\n            }\n        }\n\n        if (this.hasDoubleChancePart) {\n            const modeType = this.modeFactory.modeType;\n            if (!this.dependencyContainer.isRegistered('DoubleChanceView')) {\n                this.dependencyContainer.register(\n                    'DoubleChanceView',\n                    { useClass: this.mode.secondView ?? DoubleChanceViewCommon },\n                    { lifecycle: Lifecycle.Singleton },\n                );\n            }\n            this.dependencyContainer.register(\n                'DoubleChanceController',\n                { useClass: this.modeConfig.doubleChanceController?.[modeType] ?? DoubleChanceControllerCommon },\n                { lifecycle: Lifecycle.Singleton },\n            );\n            const doubleChanceConfigOverride = this.modeConfig.secondConfiguration?.[modeType];\n            this.dependencyContainer.register(\n                'DoubleChanceComponentConfiguration',\n                doubleChanceConfigOverride\n                    ? doubleChanceConfigOverride(DoubleChanceComponentConfigurationFactoryCommon(modeType))\n                    : DoubleChanceComponentConfigurationFactoryCommon(modeType),\n            );\n        }\n    }\n\n    public onResolveDependencies(container: any): void {\n        super.onResolveDependencies(container);\n\n        this.rootView = this.dependencyContainer.resolve('RootView');\n        if (this.hasBuyBonusPart) {\n            this.buyBonusView = this.dependencyContainer.resolve('BuyBonusView');\n            this.buyBonusView.zIndex = ZOrders.MESSAGES_LEVEL + 3;\n            this.rootView.addChild(this.buyBonusView);\n            this.buyBonusController = this.dependencyContainer.resolve('BuyBonusController');\n            this.buyBonusController.ready = this.ready.bind(this);\n        }\n        if (this.hasDoubleChancePart) {\n            this.doubleChanceView = this.dependencyContainer.resolve('DoubleChanceView');\n            this.doubleChanceView.zIndex = ZOrders.SPIN_BUTTONS_LEVEL + 1;\n            this.rootView.addChild(this.doubleChanceView);\n            this.doubleChanceController = this.dependencyContainer.resolve('DoubleChanceController');\n            this.doubleChanceController.ready = this.ready.bind(this);\n        }\n    }\n\n    // the assets are described in the mode / double chance configurations (@DefaultAssets) and can be\n    // overridden per template / game with @ModifyAssets / @RemoveAssets\n    public onPrepareResources(_container: any): void {\n        if (this.hasBuyBonusPart) {\n            // addAsset keeps the first url registered per id, so translatableAssets wins over assets\n            const assets = (this.configuration?.translatableAssets || []).concat(\n                this.configuration?.assets?.toArray() || [],\n            );\n            Core.assets.addAssets(assets);\n        }\n        if (this.hasDoubleChancePart) {\n            const assets = (this.doubleChanceConfiguration?.translatableAssets || []).concat(\n                this.doubleChanceConfiguration?.assets?.toArray() || [],\n            );\n            Core.assets.addAssets(assets);\n        }\n    }\n\n    public onGameStarted(): void {\n        if (this.hasBuyBonusPart) {\n            this.buyBonusController.onGameStarted(this.initialSettings);\n        }\n        if (this.hasDoubleChancePart) {\n            this.doubleChanceController.onGameStarted();\n        }\n    }\n\n    public onGameSettings(settings: any): void {\n        this.initialSettings = settings;\n    }\n\n    private resolveParts(): void {\n        const modeType = this.modeFactory.modeType;\n\n        if (modeType === BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS) {\n            // double chance is built into the extended view; restrictions only switch its assets/configuration\n            this.hasBuyBonusPart = true;\n            this.hasDoubleChancePart = false;\n            return;\n        }\n\n        // double chance is always part of the DEFAULT and MULTIPLE_BUY_BONUS modes\n        this.hasBuyBonusPart = !Core.flags.isActive(FeatureFlags.HIDE_BUY_BONUS);\n        this.hasDoubleChancePart = !Core.flags.isActive(FeatureFlags.HIDE_DOUBLE_CHANCE);\n    }\n}\n","import { BaseModesConfigurations, IForceSetConfig, IModes } from '@egt/core';\nimport { BuyBonusComponentConfigurationFactoryDefault } from './modes/default/configuration/BuyBonusComponentConfigurationDefault';\nimport BuyBonusControllerDefault from './modes/default/controllers/BuyBonusControllerDefault';\nimport BuyBonusViewDefault from './modes/default/views/BuyBonusViewDefault';\nimport { BuyBonusComponentConfigurationFactoryExtendedMultipleBuyBonus } from './modes/extended-multiple-buy-bonus/configuration/BuyBonusComponentConfigurationExtendedMultipleBuyBonus';\nimport BuyBonusControllerExtendedMultipleBuyBonus from './modes/extended-multiple-buy-bonus/controllers/BuyBonusControllerExtendedMultipleBuyBonus';\nimport BuyBonusViewExtendedMultipleBuyBonus from './modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus';\nimport { BuyBonusComponentConfigurationFactoryMultipleBuyBonus } from './modes/multiple-buy-bonus/configuration/BuyBonusComponentConfigurationMultipleBuyBonus';\nimport BuyBonusControllerMultipleBuyBonus from './modes/multiple-buy-bonus/controllers/BuyBonusControllerMultipleBuyBonus';\nimport BuyBonusViewMultipleBuyBonus from './modes/multiple-buy-bonus/views/BuyBonusViewMultipleBuyBonus';\n\nexport default class BuyBonusModesConfigurations extends BaseModesConfigurations<BuyBonusModes> {\n    constructor(modeType: BuyBonusModes, forceSetConfig?: IForceSetConfig) {\n        super(modeType, forceSetConfig);\n    }\n\n    protected createBaseModesConfig(modeType: BuyBonusModes): IModes {\n        switch (modeType) {\n            case BuyBonusModes.MULTIPLE_BUY_BONUS:\n                return {\n                    controller: BuyBonusControllerMultipleBuyBonus,\n                    view: BuyBonusViewMultipleBuyBonus,\n                    configuration: BuyBonusComponentConfigurationFactoryMultipleBuyBonus(),\n                };\n            case BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS:\n                return {\n                    controller: BuyBonusControllerExtendedMultipleBuyBonus,\n                    view: BuyBonusViewExtendedMultipleBuyBonus,\n                    configuration: BuyBonusComponentConfigurationFactoryExtendedMultipleBuyBonus(),\n                };\n            default:\n                return {\n                    controller: BuyBonusControllerDefault,\n                    view: BuyBonusViewDefault,\n                    configuration: BuyBonusComponentConfigurationFactoryDefault(),\n                };\n        }\n    }\n}\n\nexport enum BuyBonusModes {\n    DEFAULT = 'default',\n    MULTIPLE_BUY_BONUS = 'multiple-buy-bonus',\n    EXTENDED_MULTIPLE_BUY_BONUS = 'extended-multiple-buy-bonus',\n}\n","import Core, {\n    AssetPriority,\n    AssetsCollection,\n    BaseComponentConfiguration,\n    DefaultAssets,\n    DefaultValue,\n    DynamicPositionObject,\n    IAsset,\n} from '@egt/core';\n\nimport { TextStyle } from 'pixi.js';\nimport { BuyBonusModes } from '../../../BuyBonusModeFactory';\nimport {\n    IDoubleChanceButtonInterface,\n    IDoubleChanceButtonTextInterface,\n    IDoubleChanceComponentConfigurationCommon,\n    IDoubleChanceHitAreaInterface,\n    IDoubleChanceNumericValue,\n} from '../interfaces/InterfacesDoubleChanceCommon';\nimport { IDoubleChanceTileType } from '../interfaces/InterfacesDoubleChanceCommon';\n\nexport default class DoubleChanceComponentConfigurationCommon extends BaseComponentConfiguration {}\n\nexport function DoubleChanceComponentConfigurationFactoryCommon(modeType: BuyBonusModes = BuyBonusModes.DEFAULT): any {\n    // the mode enum values match the game asset mode folder names (default / multiple-buy-bonus / ...)\n    const modeAssetsFolder = modeType;\n\n    class DoubleChanceComponentConfigurationInternalClass\n        extends DoubleChanceComponentConfigurationCommon\n        implements IDoubleChanceComponentConfigurationCommon\n    {\n        @DefaultAssets([\n            {\n                id: 'doubleChanceSounds',\n                url: '../assets/components/slot/buy-bonus/sounds/doubleChanceSounds.mp3',\n                priority: AssetPriority.LOW,\n                type: 'sound',\n                sprite: {\n                    doubleChance: [0, 500],\n                    doubleChanceNo: [2000, 500],\n                },\n            } as IAsset,\n        ])\n        public assets: AssetsCollection;\n\n        public get translatableAssets(): IAsset[] {\n            return [\n                {\n                    id: 'doubleChance',\n                    url:\n                        '../assets/' +\n                        Core.configuration.gameKey +\n                        '/components/buy-bonus/' +\n                        modeAssetsFolder +\n                        '/doubleChance_' +\n                        Core.configuration.language.toLowerCase() +\n                        '.json',\n                    priority: AssetPriority.HIGHEST,\n                    type: 'texture',\n                },\n            ];\n        }\n\n        public tileInactiveOpacity: number = 0.7;\n\n        @DefaultValue<IDoubleChanceButtonInterface>({\n            defaults: {\n                x: 0,\n                y: 0,\n                anchor: 0.5,\n                leftHandX: 0,\n                leftHandY: 0,\n                scale: 1,\n                visible: true,\n            },\n            landscape: { x: 89, y: 481, leftHandX: 1268, leftHandY: 481 },\n            portrait: { x: 140, y: 1157 },\n            desktop: { x: 101, y: 523 },\n        })\n        public doubleChanceButtonPosition: DynamicPositionObject<IDoubleChanceButtonInterface> &\n            IDoubleChanceButtonInterface;\n\n        @DefaultValue<IDoubleChanceTileType>({\n            defaults: { type: 'vertical' },\n            portrait: { type: 'horizontal' },\n        })\n        public doubleChanceTileType: DynamicPositionObject<IDoubleChanceTileType> & IDoubleChanceTileType;\n\n        @DefaultValue<IDoubleChanceHitAreaInterface>({\n            defaults: {\n                x: 0,\n                y: 0,\n                width: 261,\n                height: 358,\n                alpha: 0.5,\n                color: 0xff0000,\n                radius: 0,\n            },\n            landscape: { x: -127, y: -178, width: 261, height: 358 },\n            portrait: { x: -236, y: -100, width: 473, height: 218 },\n        })\n        public buttonHitAreaPosition: DynamicPositionObject<IDoubleChanceHitAreaInterface> &\n            IDoubleChanceHitAreaInterface;\n\n        @DefaultValue<IDoubleChanceButtonTextInterface>({\n            defaults: {\n                x: 0,\n                y: 0,\n                offSetX: 0,\n                anchor: 0.5,\n                textStyle: new TextStyle({\n                    fontFamily: 'Arial',\n                    align: 'center',\n                    fill: '#fde126',\n                    fontSize: 66,\n                    fontWeight: 'bold',\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    strokeThickness: 7,\n                }),\n            },\n            landscape: { x: 0, y: 63 },\n            portrait: { x: 0, y: 18 },\n            desktop: { x: 0, y: 63 },\n        })\n        public buttonTextValue: DynamicPositionObject<IDoubleChanceButtonTextInterface> &\n            IDoubleChanceButtonTextInterface;\n\n        @DefaultValue<IDoubleChanceNumericValue>({\n            defaults: { value: 400 },\n            landscape: { value: 400 },\n        })\n        public buttonMoneyTextBounds: DynamicPositionObject<IDoubleChanceNumericValue> & IDoubleChanceNumericValue;\n\n        @DefaultValue<IDoubleChanceButtonTextInterface>({\n            defaults: {\n                x: 0,\n                y: 0,\n                offSetX: 0,\n                anchor: 0.5,\n                textStyle: new TextStyle({\n                    fontFamily: 'Arial',\n                    align: 'center',\n                    fill: '#D3D2D1',\n                    fontSize: 28,\n                    fontWeight: 'bold',\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    strokeThickness: 5,\n                }),\n            },\n            landscape: { x: 0, y: 19 },\n            portrait: { y: 31, offSetX: 35 },\n            desktop: { x: 0, y: 19 },\n        })\n        public buttonTextCurrency: DynamicPositionObject<IDoubleChanceButtonTextInterface> &\n            IDoubleChanceButtonTextInterface;\n    }\n    return DoubleChanceComponentConfigurationInternalClass;\n}\n","import Core, { BaseController } from '@egt/core';\nimport {\n    BonusTypes,\n    FeatureController,\n    ISlotConfiguration,\n    InitialSettings,\n    MessBarTypes,\n    RootStore,\n    ServerState,\n    Subjects,\n    UIState,\n} from '@egt/slot';\nimport { fromEvent } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport DoubleChanceViewCommon from '../views/DoubleChanceViewCommon';\n\n@injectable()\nexport default class DoubleChanceControllerCommon extends BaseController {\n    public ready: () => Promise<void>;\n\n    constructor(\n        @inject('DoubleChanceView') protected view: DoubleChanceViewCommon,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('SlotSubjects') public readonly subjects: Subjects,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('FeatureController') protected featureController: FeatureController,\n    ) {\n        super(view);\n    }\n\n    public destroy(): void {\n        if (this.slotConfiguration) {\n            // @ts-ignore\n            this.slotConfiguration = null;\n        }\n        if (this.rootStore) {\n            // @ts-ignore\n            this.rootStore = null;\n        }\n        if (this.subjects) {\n            // @ts-ignore\n            this.subjects = null;\n        }\n        super.destroy();\n    }\n    public async onGameStarted(): Promise<void> {\n        this.subjects.REELS_START.pipe(takeUntil(this.DESTROY)).subscribe(this.onReelsStart.bind(this));\n        // this.rootStore.subjects.REELS_STOPPED.pipe(takeUntil(this.DESTROY)).subscribe(this.onReelsStop.bind(this));\n        this.subjects.GAMBLE_OPENED.pipe(takeUntil(this.DESTROY)).subscribe(this.onDisabledDoubleChance.bind(this));\n        this.subjects.DISABLED_DOUBLE_CHANCE.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onDisabledDoubleChance.bind(this),\n        );\n        this.subjects.DOUBLE_CHANCE_ACTIVATED.pipe(takeUntil(this.DESTROY)).subscribe((e) => {\n            if (e) {\n                this.view.state = 'On';\n            } else {\n                this.view.state = 'Off';\n            }\n            this.updateFactor();\n        });\n        Core.ON_SERVER_MESSAGE.pipe(takeUntil(this.DESTROY)).subscribe(this.onServerMessage.bind(this));\n        this.subjects.BUY_BONUS_AND_DOUBLE_CHANCE_VISIBLE.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.hideWhenRecovery.bind(this),\n        );\n        this.rootStore.domainStore.COLLECT_RESPONSE.pipe(takeUntil(this.DESTROY)).subscribe(this.onCollect.bind(this));\n        this.rootStore.domainStore.SERVER_STATE.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onServerStateChanged.bind(this),\n        );\n\n        if (this.settings.state === ServerState.IDLE) {\n            this.view.activeState = 'active';\n        } else {\n            this.view.activeState = 'inactive';\n            this.view.state = 'Off';\n        }\n        this.rootStore.uiStore.STATE.pipe(takeUntil(this.DESTROY)).subscribe(this.onStateChanged.bind(this));\n        Core.SELECTED_DENOMINATION.pipe(takeUntil(Core.ON_GAME_UNLOADED)).subscribe(\n            this.onDenominationOrBetChanged.bind(this),\n        );\n        this.rootStore.uiStore.SELECTED_BET.pipe(takeUntil(Core.ON_GAME_UNLOADED)).subscribe(\n            this.onDenominationOrBetChanged.bind(this),\n        );\n\n        this.view.init();\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/common/double-chance/controllers/DoubleChanceControllerCommon.ts:88:9\",(this.view.btnHitArea),\"pointertap\"]), fromEvent(this.view.btnHitArea, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onDoubleChanceClicked.bind(this));\n\n        if (\n            this.settings.state === ServerState.FREESPIN &&\n            this.settings.settings.game.state.rounds.filter((round) => round.type === 'FREESPIN')[0]?.count !==\n                this.settings.settings.game.state.rounds.filter((round) => round.type === 'FREESPIN')[0]?.remain\n        ) {\n            this.view.activeState = 'inactive';\n            this.view.state = 'Off';\n\n            await this.ready();\n            this.view.visible = false;\n        }\n\n        await this.ready();\n        if (\n            ((this.rootStore.settings.haveGameMode('DOUBLE_CHANCE') &&\n                this.settings.factor === this.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE')) ||\n                (this.settings.settings.game &&\n                    this.settings.settings.game.state &&\n                    this.settings.settings.game.state.bet &&\n                    this.rootStore.settings.haveGameMode('DOUBLE_CHANCE') &&\n                    this.settings.settings.game.state.bet.factor ===\n                        this.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE') &&\n                    this.settings.settings.bonus?.type !== BonusTypes.BUY_BONUS &&\n                    !this.settings.settings.game.result?.bonusSummary)) &&\n            !this.featureController.isInGiftSpins\n        ) {\n            this.view.state = 'On';\n            this.rootStore.subjects.DOUBLE_CHANCE_ACTIVATED.next(true);\n        } else {\n            this.view.state = 'Off';\n            this.rootStore.subjects.DOUBLE_CHANCE_ACTIVATED.next(false);\n        }\n        this.updateFactor();\n    }\n\n    public onDenominationOrBetChanged(): void {\n        this.view.onDenominationOrBetChanged();\n        this.onStateChanged();\n    }\n\n    private onDoubleChanceClicked(): void {\n        if (this.view.activeState === 'inactive') {\n            return;\n        }\n        if (this.view.state === 'On') {\n            this.view.state = 'Off';\n            this.rootStore.subjects.DOUBLE_CHANCE_ACTIVATED.next(false);\n            Core.sounds.play('doubleChanceNo');\n        } else {\n            this.view.state = 'On';\n            this.rootStore.subjects.DOUBLE_CHANCE_ACTIVATED.next(true);\n            Core.sounds.play('doubleChance');\n        }\n        this.updateFactor();\n\n        // ON-58718 - when turn of X2 and there is message for inssufficient funds but enogh money -remove message\n        if (\n            this.view.state === 'Off' &&\n            this.rootStore.uiStore.STATE.value === UIState.IDLE &&\n            this.rootStore.subjects.SHOW_DIRECT_MESSAGEBAR_TEXT.value &&\n            this.rootStore.subjects.SHOW_DIRECT_MESSAGEBAR_TEXT.value[0] === MessBarTypes.INSUFFICIENT &&\n            this.rootStore.uiStore.BALANCE.value >= this.rootStore.getBetAmount()\n        ) {\n            this.rootStore.subjects.SHOW_DIRECT_MESSAGEBAR_TEXT.next(false);\n        }\n    }\n\n    private updateFactor(): void {\n        if (this.view.state === 'On') {\n            this.settings.factor = this.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE');\n            this.settings.gameMode = 'DOUBLE_CHANCE';\n        } else {\n            this.settings.factor = this.settings.getFactorByUniqueGameMode('NORMAL_MODE');\n            this.settings.gameMode = 'NORMAL_MODE';\n        }\n        this.subjects.FACTOR_CHANGED.next();\n        this.updateDenominations();\n    }\n\n    private updateDenominations(): void {\n        if (this.settings.maxBet) {\n            this.rootStore.uiStore.denominations = this.settings.denominations;\n            this.rootStore.uiStore.bets = this.settings.bets;\n            if (this.rootStore.uiStore.STATE.value !== UIState.BONUS_IDLE) {\n                this.subjects.DENOMINATIONS_CHANGED.next();\n            }\n        }\n    }\n\n    private onReelsStart(): void {\n        this.view.activeState = 'inactive';\n    }\n\n    // private onReelsStop(): void {\n    //     this.setButtonState();\n    // }\n    // private setButtonState(): void {\n    //     const hasMultiplier = this.rootStore.domainStore.betResponse?.result?.multiplier > 1;\n    //     if (\n    //         (this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value === 0 ||\n    //             this.cascadeSubjects.SPECIAL_STOP_CONDITION_REACHED.value) &&\n    //         this.rootStore.domainStore.betResponse.state !== ServerState.BONUS_IDLE &&\n    //         this.rootStore.domainStore.betResponse.state !== ServerState.MYSTERY &&\n    //         !this.rootStore.uiStore.fastSpinMode &&\n    //         !this.rootStore.domainStore.betResponse?.bonus &&\n    //         !this.rootStore.isCascadeGreatWin &&\n    //         !hasMultiplier\n    //     ) {\n    //         this.view.activeState = 'active';\n    //     }\n    // }\n\n    private onStateChanged(): void {\n        if (\n            (this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value === 0 ||\n                this.rootStore.subjects.SPECIAL_STOP_CONDITION_REACHED.value) &&\n            this.rootStore.domainStore.SERVER_STATE.value !== ServerState.BONUS_SUMMARY &&\n            (this.rootStore.uiStore.STATE.value === UIState.IDLE ||\n                this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT) &&\n            !this.rootStore.uiStore.fastSpinMode &&\n            (!this.rootStore.domainStore.betResponse?.bonus ||\n                this.rootStore.domainStore.betResponse?.bonus?.remaining === 0)\n        ) {\n            this.view.activeState = 'active';\n        } else {\n            this.view.activeState = 'inactive';\n        }\n        // if (this.rootStore.domainStore.SERVER_STATE.value === ServerState.BONUS_IDLE) {\n        //     this.view.state = 'Off';\n        //     this.updateFactor();\n        // }\n    }\n\n    private onCollect(): void {\n        if (this.rootStore.domainStore.SERVER_STATE.value === ServerState.IDLE) {\n            this.view.activeState = 'active';\n        }\n    }\n\n    private onServerStateChanged(): void {\n        if (\n            this.rootStore.domainStore.SERVER_STATE.value === ServerState.BONUS_IDLE &&\n            this.settings.factor !== this.settings.getFactorByUniqueGameMode('NORMAL_MODE')\n        ) {\n            this.view.state = 'Off';\n            this.view.activeState = 'inactive';\n            this.settings.factor = this.settings.getFactorByUniqueGameMode('NORMAL_MODE');\n            this.settings.gameMode = 'NORMAL_MODE';\n            this.subjects.FACTOR_CHANGED.next();\n            this.updateDenominations();\n        }\n    }\n\n    private onDisabledDoubleChance(value: boolean): void {\n        if (value || this.rootStore.domainStore.SERVER_STATE.value === ServerState.BONUS_IDLE) {\n            this.view.activeState = 'inactive';\n        } else {\n            this.view.activeState = 'active';\n        }\n    }\n\n    private onServerMessage(response): void {\n        if (response.event === 'spin') {\n            if (response.state === ServerState.WIN) {\n                this.view.activeState = 'active';\n            }\n        }\n        if (this.rootStore.domainStore.SERVER_STATE.value === ServerState.BONUS_IDLE) {\n            this.view.activeState = 'inactive';\n        }\n    }\n\n    private hideWhenRecovery(zOrder: number): void {\n        this.view.visible = Boolean(zOrder);\n    }\n}\n","import Core, { Money } from '@egt/core';\nimport { ISlotConfiguration, RootStore } from '@egt/slot';\nimport { ViewContainer } from '@egt/ui-lib';\n// import 'pixi-spine';\nimport { Graphics, Sprite, Text, TextStyle } from 'pixi.js';\nimport { merge } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { IDoubleChanceComponentConfigurationCommon } from '../interfaces/InterfacesDoubleChanceCommon';\n\n@injectable()\nexport default class DoubleChanceViewCommon extends ViewContainer {\n    public btnHitArea: Graphics;\n    protected buttonTextTextStyle1: TextStyle;\n    protected buttonTextTextStyle2: TextStyle;\n    protected doubleChanceButton: Sprite;\n    protected buttonText1: Text;\n    protected buttonText2: Text;\n    private _state: 'On' | 'Off';\n    private _activeState: 'active' | 'inactive';\n    private money: Money;\n\n    public set state(value: 'On' | 'Off') {\n        this._state = value;\n        this.setState();\n    }\n\n    public get state(): 'On' | 'Off' {\n        return this._state;\n    }\n\n    public set activeState(value: 'active' | 'inactive') {\n        this._activeState = value;\n        if (value == 'active') {\n            this.maxBetCheck();\n        }\n        this.setState();\n    }\n\n    public get activeState(): 'active' | 'inactive' {\n        return this._activeState;\n    }\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('DoubleChanceComponentConfiguration')\n        protected componentConfig: IDoubleChanceComponentConfigurationCommon,\n    ) {\n        super();\n    }\n\n    public destroy(): void {\n        super.destroy();\n    }\n\n    public init(): void {\n        const orientation = merge(Core.ORIENTATION, Core.LEFT_HAND_MODE, this.rootStore.subjects.ACTIVE_FEATURE);\n        orientation.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n\n        Core.MONEY_MODE_IN_CREDITS.pipe(takeUntil(Core.ON_GAME_UNLOADED)).subscribe(\n            this.onDenominationOrBetChanged.bind(this),\n        );\n\n        this.createButton();\n        this.createTextBtn();\n        this.setOrientation();\n        this.state = 'Off';\n        // if (Core.isDesktopMode) {\n        //     this.x = 10;\n        //     this.y = 42;\n        // }\n        // Core.UI_BLOCKER.pipe(takeUntil(this.DESTROY)).subscribe(isUiBlocked => {\n        //     if (isUiBlocked) {\n        //         this.btnHitArea.cursor = 'normal';\n        //         this.btnHitArea.interactive = false;\n        //         this.doubleChanceButton.alpha = 0.7;\n        //     } else {\n        //         this.btnHitArea.cursor = 'pointer';\n        //         this.btnHitArea.interactive = true;\n        //         this.doubleChanceButton.alpha = 1;\n        //     }\n        // });\n    }\n\n    public maxBetCheck(): void {\n        if (this.rootStore.settings.maxBet && this.money?.amountMoney > this.rootStore.settings.maxBet) {\n            this.activeState = 'inactive';\n        }\n    }\n\n    public onDenominationOrBetChanged(): void {\n        const buyBonusValue: number =\n            this.rootStore.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE') *\n            Core.SELECTED_DENOMINATION.value *\n            this.rootStore.uiStore.SELECTED_BET.value;\n        this.money = new Money(buyBonusValue);\n        if (this.buttonText1) {\n            // if (Core.MONEY_MODE_IN_CREDITS.value) {\n            //     this.buttonText1.text = this.money.stringCredits;\n            //     this.buttonText2.visible = false;\n            // } else {\n            this.buttonText1.text = this.money.stringMoney;\n            this.buttonText2.visible = true;\n            // }\n        }\n        this.setOrientation();\n    }\n\n    protected createTextStyles(): void {\n        this.buttonTextTextStyle1 = this.componentConfig.buttonTextValue.textStyle;\n\n        this.buttonTextTextStyle2 = this.componentConfig.buttonTextCurrency.textStyle;\n    }\n\n    protected setOrientation(): void {\n        if (!this.doubleChanceButton) {\n            return;\n        }\n\n        this.doubleChanceButton.scale.set(0.5);\n        this.scale.set(this.componentConfig.doubleChanceButtonPosition.scale);\n\n        this.doubleChanceButton.x = this.componentConfig.doubleChanceButtonPosition.x;\n        this.doubleChanceButton.y = this.componentConfig.doubleChanceButtonPosition.y;\n        this.doubleChanceButton.visible = this.componentConfig.doubleChanceButtonPosition.visible !== false;\n        this.buttonText1.x = this.componentConfig.buttonTextValue.x;\n        this.buttonText1.y = this.componentConfig.buttonTextValue.y;\n\n        this.buttonText2.y = this.componentConfig.buttonTextCurrency.y;\n        if (this.buttonText1.getLocalBounds().width > this.componentConfig.buttonMoneyTextBounds.value / 2) {\n            const scale =\n                this.componentConfig.buttonMoneyTextBounds.value / 2 / this.buttonText1.getLocalBounds().width;\n            this.buttonText1.scale.set(scale);\n            this.buttonText1.y =\n                this.componentConfig.doubleChanceTileType.type === 'horizontal'\n                    ? this.buttonText2.y +\n                      this.buttonText2.getBounds().height / 2 -\n                      this.buttonText1.getBounds().height / 2\n                    : this.componentConfig.buttonTextValue.y;\n        } else {\n            this.buttonText1.scale.set(1);\n        }\n        this.buttonText2.x = this.componentConfig.buttonTextCurrency.offSetX\n            ? this.buttonText1.x + this.buttonText1.width / 2 + this.componentConfig.buttonTextCurrency.offSetX\n            : this.componentConfig.buttonTextCurrency.x;\n        this.setState();\n    }\n\n    protected createHitArea(): void {\n        if (this.btnHitArea) {\n            this.btnHitArea.clear();\n        } else {\n            this.btnHitArea = new Graphics();\n            this.btnHitArea.name = 'Button hit area';\n        }\n\n        this.btnHitArea\n            .beginFill(\n                this.componentConfig.buttonHitAreaPosition.color,\n                this.componentConfig.buttonHitAreaPosition.alpha,\n            )\n            .drawRoundedRect(\n                this.componentConfig.buttonHitAreaPosition.x,\n                this.componentConfig.buttonHitAreaPosition.y,\n                this.componentConfig.buttonHitAreaPosition.width,\n                this.componentConfig.buttonHitAreaPosition.height,\n                this.componentConfig.buttonHitAreaPosition.radius,\n            )\n            .endFill();\n\n        this.btnHitArea.cursor = 'pointer';\n        this.btnHitArea.interactive = true;\n        this.btnHitArea.alpha = 0;\n        this.doubleChanceButton.addChild(this.btnHitArea);\n    }\n\n    private createButton(): void {\n        this.doubleChanceButton = new Sprite();\n        this.doubleChanceButton.name = 'Double chance button';\n        this.addChild(this.doubleChanceButton);\n        this.doubleChanceButton.anchor.set(this.componentConfig.doubleChanceButtonPosition.anchor);\n    }\n\n    private createTextBtn(): void {\n        this.createTextStyles();\n        this.buttonText1 = new Text(this.money.stringMoney, this.buttonTextTextStyle1);\n        this.buttonText1.name = 'Money cost';\n        this.buttonText1.anchor.set(this.componentConfig.buttonTextValue.anchor);\n        // this.buttonText1.resolution = 2;\n        this.doubleChanceButton.addChild(this.buttonText1);\n\n        this.buttonText2 = new Text(this.rootStore.uiStore.currency, this.buttonTextTextStyle2);\n        this.buttonText2.name = 'Currency';\n        this.buttonText2.anchor.set(this.componentConfig.buttonTextCurrency.anchor);\n        // this.buttonText2.resolution = 2;\n        this.doubleChanceButton.addChild(this.buttonText2);\n    }\n\n    private setState(): void {\n        if (!this.doubleChanceButton) {\n            return;\n        }\n        if (Core.ORIENTATION.value.isLandscape) {\n            this.doubleChanceButton.texture = Core.assets.getTextureFromSpriteSheet(\n                'doubleChance',\n                'doubleChance' + this._state + 'Landscape.png',\n            );\n        } else {\n            this.doubleChanceButton.texture = Core.assets.getTextureFromSpriteSheet(\n                'doubleChance',\n                'doubleChance' + this._state + 'Portrait.png',\n            );\n        }\n\n        if (this.state === 'Off') {\n            this.buttonText1.visible = true;\n            this.buttonText2.visible = true;\n        } else {\n            this.buttonText1.visible = false;\n            this.buttonText2.visible = false;\n        }\n\n        this.createHitArea();\n\n        if (this._activeState === 'active') {\n            this.alpha = 1;\n            this.btnHitArea.cursor = 'pointer';\n            this.btnHitArea.interactive = true;\n        } else {\n            this.alpha = this.componentConfig.tileInactiveOpacity;\n            this.btnHitArea.cursor = 'normal';\n            this.btnHitArea.interactive = false;\n            // this.buttonText1.visible = false;\n        }\n    }\n}\n","import BuyBonusComponent from './BuyBonusComponent';\nimport BuyBonusModesConfigurations, { BuyBonusModes } from './BuyBonusModeFactory';\nimport DoubleChanceComponentConfigurationCommon, {\n    DoubleChanceComponentConfigurationFactoryCommon,\n} from './common/double-chance/configuration/DoubleChanceComponentConfigurationCommon';\nimport DoubleChanceControllerCommon from './common/double-chance/controllers/DoubleChanceControllerCommon';\nimport {\n    IDoubleChanceButtonInterface,\n    IDoubleChanceButtonTextInterface,\n    IDoubleChanceComponentConfigurationCommon,\n    IDoubleChanceHitAreaInterface,\n    IDoubleChanceNumericValue,\n    IDoubleChanceTileType,\n} from './common/double-chance/interfaces/InterfacesDoubleChanceCommon';\nimport DoubleChanceViewCommon from './common/double-chance/views/DoubleChanceViewCommon';\nimport BuyBonusComponentConfigurationDefault, {\n    BuyBonusComponentConfigurationFactoryDefault,\n} from './modes/default/configuration/BuyBonusComponentConfigurationDefault';\nimport BuyBonusControllerDefault from './modes/default/controllers/BuyBonusControllerDefault';\nimport {\n    IBuyBonusBitmapStyle,\n    IBuyBonusComponentConfigurationDefault,\n    IBuyBonusFontType,\n    IBuyBonusHitArea,\n    IBuyBonusMaxBetTextOffset,\n    IBuyBonusOverlaySettings,\n    IBuyBonusPopupHitAreaGraphics,\n    IBuyBonusTextStyle,\n    IBuyBonusTileOpacity,\n    IBuyBonusTileType,\n    INumericValue,\n    ISquare,\n    ITranslatableTextSprite,\n} from './modes/default/interfaces/InterfacesDefault';\nimport BuyBonusViewDefault from './modes/default/views/BuyBonusViewDefault';\nimport BuyBonusComponentConfigurationExtendedMultipleBuyBonus, {\n    BuyBonusComponentConfigurationFactoryExtendedMultipleBuyBonus,\n    getExtendedMultipleBuyBonusGameAssets,\n} from './modes/extended-multiple-buy-bonus/configuration/BuyBonusComponentConfigurationExtendedMultipleBuyBonus';\nimport { IBuyBonusComponentConfigurationExtendedMultipleBuyBonus } from './modes/extended-multiple-buy-bonus/configuration/IBuyBonusComponentConfigurationExtendedMultipleBuyBonus';\nimport BuyBonusControllerExtendedMultipleBuyBonus from './modes/extended-multiple-buy-bonus/controllers/BuyBonusControllerExtendedMultipleBuyBonus';\nimport ExtendedMultipleBuyBonusContext from './modes/extended-multiple-buy-bonus/data/ExtendedMultipleBuyBonusContext';\nimport {\n    IBalancePositions,\n    IBannerConfig,\n    IBannerInnerPositions,\n    IBBBannerPoint,\n    IBBBtnConfig,\n    IBBPoint,\n    IBBPopUpTitle,\n    IBBXBoundsPoint,\n    IBetOutsidePanelPositions,\n    IBetPanelPositions,\n    ICloseButtonPoint,\n    IDenominationContainer,\n    IInfoTextPositions,\n    IPopUpBackgroundPosition,\n    IToggleTextPositions,\n} from './modes/extended-multiple-buy-bonus/interfaces/InterfacesExtendedMultipleBuyBonus';\nimport BuyBonusViewExtendedMultipleBuyBonus from './modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus';\nimport BuyBonusComponentConfigurationMultipleBuyBonus, {\n    BuyBonusComponentConfigurationFactoryMultipleBuyBonus,\n} from './modes/multiple-buy-bonus/configuration/BuyBonusComponentConfigurationMultipleBuyBonus';\nimport { IBuyBonusComponentConfigurationMultipleBuyBonus } from './modes/multiple-buy-bonus/configuration/IBuyBonusComponentConfigurationMultipleBuyBonus';\nimport BuyBonusControllerMultipleBuyBonus from './modes/multiple-buy-bonus/controllers/BuyBonusControllerMultipleBuyBonus';\nimport {\n    IMultipleBuyBonusPositionPoint,\n    IMultipleBuyBonusTextInterface,\n    ITilePositionPoint,\n} from './modes/multiple-buy-bonus/interfaces/InterfacesMultipleBuyBonus';\nimport BuyBonusViewMultipleBuyBonus from './modes/multiple-buy-bonus/views/BuyBonusViewMultipleBuyBonus';\n\nexport type { IBuyBonusModeConfig } from './BuyBonusComponent';\nexport {\n    BuyBonusModes,\n    BuyBonusModesConfigurations,\n    // default mode\n    BuyBonusComponentConfigurationDefault,\n    BuyBonusComponentConfigurationFactoryDefault,\n    BuyBonusControllerDefault,\n    BuyBonusViewDefault,\n    IBuyBonusComponentConfigurationDefault,\n    // double chance sub-part\n    DoubleChanceComponentConfigurationCommon,\n    DoubleChanceComponentConfigurationFactoryCommon,\n    DoubleChanceControllerCommon,\n    DoubleChanceViewCommon,\n    IDoubleChanceComponentConfigurationCommon,\n    // multiple buy bonus mode\n    BuyBonusComponentConfigurationMultipleBuyBonus,\n    BuyBonusComponentConfigurationFactoryMultipleBuyBonus,\n    BuyBonusControllerMultipleBuyBonus,\n    BuyBonusViewMultipleBuyBonus,\n    IBuyBonusComponentConfigurationMultipleBuyBonus,\n    // extended multiple buy bonus mode\n    BuyBonusComponentConfigurationExtendedMultipleBuyBonus,\n    BuyBonusComponentConfigurationFactoryExtendedMultipleBuyBonus,\n    BuyBonusControllerExtendedMultipleBuyBonus,\n    BuyBonusViewExtendedMultipleBuyBonus,\n    ExtendedMultipleBuyBonusContext,\n    getExtendedMultipleBuyBonusGameAssets,\n    IBuyBonusComponentConfigurationExtendedMultipleBuyBonus,\n    // interfaces\n    IBuyBonusBitmapStyle,\n    IBuyBonusFontType,\n    IBuyBonusHitArea,\n    IBuyBonusMaxBetTextOffset,\n    IBuyBonusOverlaySettings,\n    IBuyBonusPopupHitAreaGraphics,\n    IBuyBonusTextStyle,\n    IBuyBonusTileOpacity,\n    IBuyBonusTileType,\n    INumericValue,\n    ISquare,\n    ITranslatableTextSprite,\n    IMultipleBuyBonusPositionPoint,\n    IMultipleBuyBonusTextInterface,\n    ITilePositionPoint,\n    IBalancePositions,\n    IBannerConfig,\n    IBannerInnerPositions,\n    IBBBannerPoint,\n    IBBBtnConfig,\n    IBBPoint,\n    IBBPopUpTitle,\n    IBBXBoundsPoint,\n    IBetOutsidePanelPositions,\n    IBetPanelPositions,\n    ICloseButtonPoint,\n    IDenominationContainer,\n    IInfoTextPositions,\n    IPopUpBackgroundPosition,\n    IToggleTextPositions,\n    IDoubleChanceButtonInterface,\n    IDoubleChanceButtonTextInterface,\n    IDoubleChanceHitAreaInterface,\n    IDoubleChanceNumericValue,\n    IDoubleChanceTileType,\n};\n\nexport default BuyBonusComponent;\n","import Core, {\n    AssetPriority,\n    AssetsCollection,\n    BaseComponentConfiguration,\n    DefaultAssets,\n    DefaultValue,\n    DynamicPositionObject,\n    IAsset,\n    IPositionPoint,\n} from '@egt/core';\nimport { IPointData, TextStyle } from 'pixi.js';\nimport {\n    IBuyBonusBitmapStyle,\n    IBuyBonusComponentConfigurationDefault,\n    IBuyBonusFontType,\n    IBuyBonusHitArea,\n    IBuyBonusMaxBetTextOffset,\n    IBuyBonusOverlaySettings,\n    IBuyBonusPopupHitAreaGraphics,\n    IBuyBonusTextStyle,\n    IBuyBonusTileOpacity,\n    IBuyBonusTileType,\n    INumericValue,\n    ISquare,\n    ITranslatableTextSprite,\n} from '../interfaces/InterfacesDefault';\n\nexport default class BuyBonusComponentConfigurationDefault extends BaseComponentConfiguration {}\n\nexport function BuyBonusComponentConfigurationFactoryDefault(): any {\n    class BuyBonusConfigurationInternalClass\n        extends BuyBonusComponentConfigurationDefault\n        implements IBuyBonusComponentConfigurationDefault\n    {\n        @DefaultAssets([])\n        public assets: AssetsCollection;\n\n        public get translatableAssets(): IAsset[] {\n            return [\n                {\n                    id: 'buyBonus',\n                    url:\n                        '../assets/' +\n                        Core.configuration.gameKey +\n                        '/components/buy-bonus/default/buyBonus_' +\n                        Core.configuration.language.toLowerCase() +\n                        '.json',\n                    priority: AssetPriority.HIGHEST,\n                    type: 'texture',\n                    hasDesktopVersion: true,\n                },\n            ];\n        }\n\n        @DefaultValue<IBuyBonusTileType>({\n            defaults: { type: 'vertical' },\n            portrait: { type: 'horizontal' },\n        })\n        public buyBonusTileType: DynamicPositionObject<IBuyBonusTileType> & IBuyBonusTileType;\n\n        @DefaultValue<IBuyBonusTileOpacity>({\n            defaults: {\n                textOn: 1,\n                textOff: 0.7,\n                textActivated: 0,\n                tileOn: 1,\n                tileOff: 1,\n                tileActivated: 1,\n            },\n        })\n        public tileOpacity: DynamicPositionObject<IBuyBonusTileOpacity> & IBuyBonusTileOpacity;\n\n        @DefaultValue<IPositionPoint>({\n            defaults: {\n                x: 625,\n                y: 1157,\n                visible: true,\n                scale: 0.5,\n                width: 0,\n                height: 0,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n            },\n            landscape: { x: 89, y: 287, leftHandX: 1268, leftHandY: 287 },\n            desktop: { x: 99, y: 329 },\n        })\n        public tilePosition: DynamicPositionObject<IPositionPoint> & IPositionPoint;\n\n        @DefaultValue<IPositionPoint>({\n            defaults: {\n                x: 0,\n                y: 54,\n                visible: true,\n                scale: 2.5,\n                width: 0,\n                height: 0,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n            },\n            landscape: { x: 0, y: 49, leftHandX: 0, leftHandY: 49, scale: 2 },\n            desktop: { x: 0, y: 49, scale: 2 },\n        })\n        public textHolderPossition: DynamicPositionObject<IPositionPoint> & IPositionPoint;\n\n        @DefaultValue<IPositionPoint>({\n            defaults: {\n                x: 0,\n                y: -3,\n                visible: true,\n                scale: 0.5,\n                width: 0,\n                height: 0,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n            },\n            landscape: { x: 0, y: -32, leftHandX: 0, leftHandY: -32 },\n            desktop: { x: 0, y: -32 },\n        })\n        public maxBetTextPossition: DynamicPositionObject<IPositionPoint> & IPositionPoint;\n\n        @DefaultValue<IPositionPoint>({\n            defaults: {\n                x: 0,\n                y: 2,\n                visible: true,\n                scale: 0.5,\n                width: 0,\n                height: 0,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n            },\n            landscape: { x: 0, y: 2, leftHandX: 0, leftHandY: 2 },\n            desktop: { x: 0, y: 2 },\n        })\n        public currencyOffset: DynamicPositionObject<IPositionPoint> & IPositionPoint;\n        @DefaultValue<IBuyBonusMaxBetTextOffset>({\n            defaults: {\n                normalText: 20,\n                wrapedText: 40,\n            },\n        })\n        public maxBetTextOffset: DynamicPositionObject<IBuyBonusMaxBetTextOffset> & IBuyBonusMaxBetTextOffset;\n\n        @DefaultValue<IBuyBonusPopupHitAreaGraphics>({\n            defaults: {\n                color: 0x000000,\n                rectangleAlpha: 0,\n                x: 0,\n                y: 0,\n                width: 0,\n                height: 0,\n                alpha: 0,\n            },\n        })\n        public popupHitAreaGraphics: DynamicPositionObject<IBuyBonusPopupHitAreaGraphics> &\n            IBuyBonusPopupHitAreaGraphics;\n\n        @DefaultValue<IPositionPoint>({\n            defaults: {\n                x: 62,\n                y: 160,\n                visible: true,\n                scale: 1,\n                width: 150,\n                height: 115,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n            },\n            landscape: { x: 85, y: 75, width: 150, height: 115 },\n            desktop: { x: 78, y: 88, width: 120, height: 90 },\n        })\n        public yesButtonPosition: DynamicPositionObject<IPositionPoint> & IPositionPoint;\n\n        @DefaultValue<IPositionPoint>({\n            defaults: {\n                x: -214,\n                y: 160,\n                visible: true,\n                scale: 1,\n                width: 150,\n                height: 115,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n            },\n            landscape: { x: -234, y: 75, width: 150, height: 115 }, // V\n            desktop: { x: -198, y: 88, width: 120, height: 90 }, // V\n        })\n        public noButtonPosition: DynamicPositionObject<IPositionPoint> & IPositionPoint;\n\n        @DefaultValue<IPositionPoint>({\n            defaults: {\n                x: 0,\n                y: 605,\n                visible: true,\n                scale: 1,\n                width: 150,\n                height: 115,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n            },\n            landscape: { y: 358 },\n            desktop: { y: 356 },\n        })\n        public popupContainerPosition: DynamicPositionObject<IPositionPoint> & IPositionPoint;\n\n        @DefaultValue<IBuyBonusHitArea>({\n            defaults: {\n                x: -147,\n                y: -184,\n                width: 262,\n                height: 358,\n                radius: 80,\n            },\n            portrait: { x: -236, y: -119, width: 478, height: 230, radius: 80 },\n        })\n        public btnHitArea: DynamicPositionObject<IBuyBonusHitArea> & IBuyBonusHitArea;\n\n        @DefaultValue<IBuyBonusOverlaySettings>({\n            defaults: {\n                color: 0x000000,\n                opacity: 0.6,\n            },\n        })\n        public overlay: DynamicPositionObject<IBuyBonusOverlaySettings> & IBuyBonusOverlaySettings;\n\n        public buttonTextMoneyTextStyle: TextStyle = new TextStyle({\n            fontFamily: 'Arial',\n            align: 'center',\n            trim: true,\n            fill: '#fde126',\n            fontSize: 34,\n            fontWeight: 'bold',\n            lineJoin: 'round',\n            miterLimit: 0,\n            strokeThickness: 5,\n        });\n        public buttonTextCurrencyTextStyle: TextStyle = new TextStyle({\n            fontFamily: 'Arial',\n            align: 'center',\n            fill: '#D3D2D1',\n            fontSize: 14,\n            trim: true,\n            fontWeight: 'bold',\n            lineJoin: 'round',\n            miterLimit: 0,\n            strokeThickness: 3,\n            stroke: '#052a8c',\n        });\n\n        public buttonTextMaxBetTextStyle: TextStyle = new TextStyle({\n            fontFamily: 'Arial',\n            align: 'center',\n            fill: '#5698E5',\n            fontSize: 32,\n            fontWeight: 'bold',\n            lineJoin: 'round',\n            miterLimit: 0,\n            strokeThickness: 8,\n            stroke: '#052a8c',\n            wordWrap: true,\n            wordWrapWidth: 230,\n            lineHeight: 35,\n        });\n\n        // ---------- POPUP AMOUNT TEXT STYLE CONFIGURATION ----------\n        @DefaultValue<IBuyBonusFontType>({\n            defaults: { type: 'text' },\n        })\n        public moneyFontType: DynamicPositionObject<IBuyBonusFontType> & IBuyBonusFontType;\n\n        @DefaultValue<IBuyBonusTextStyle>({\n            defaults: {\n                align: 'center',\n                dropShadowAlpha: 0.9,\n                dropShadowAngle: 10.6,\n                dropShadowColor: '#761369',\n                dropShadowDistance: 0,\n                fill: ['white'],\n                fontWeight: 'normal',\n                lineJoin: 'miter',\n                fontFamily: 'Junegull',\n                fontSize: 85,\n                miterLimit: 0,\n                stroke: '#9D0C16',\n                strokeThickness: 6,\n                whiteSpace: 'normal',\n            },\n            portrait: { fontSize: 82 },\n        })\n        public popUpTextMoneyTextStyle: DynamicPositionObject<IBuyBonusTextStyle> & IBuyBonusTextStyle;\n\n        @DefaultValue<IBuyBonusBitmapStyle>({\n            defaults: {\n                fontName: '',\n                fontSize: 10,\n                align: 'center',\n            },\n        })\n        public popUpTextMoneyBitmapStyle: DynamicPositionObject<IBuyBonusBitmapStyle> & IBuyBonusBitmapStyle;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: -8, y: 65 },\n        })\n        public popUpTextMoneyRelativePosition: DynamicPositionObject<IPointData> & IPointData;\n\n        // max width of the amount and currency texts together, 0 means no limit\n        @DefaultValue<INumericValue>({\n            defaults: { value: 0 },\n        })\n        public popUpMoneyTextBounds: DynamicPositionObject<INumericValue> & INumericValue;\n        // ---------- END OF POPUP AMOUNT TEXT STYLE CONFIGURATION ----------\n\n        // ---------- POPUP CURRENCY TEXT STYLE CONFIGURATION ----------\n        @DefaultValue<IBuyBonusFontType>({\n            defaults: { type: 'text' },\n        })\n        public currencyFontType: DynamicPositionObject<IBuyBonusFontType> & IBuyBonusFontType;\n\n        @DefaultValue<IBuyBonusTextStyle>({\n            defaults: {\n                align: 'center',\n                dropShadowAlpha: 0.9,\n                dropShadowAngle: 10.6,\n                dropShadowColor: '#761369',\n                dropShadowDistance: 0,\n                fill: ['white'],\n                lineJoin: 'miter',\n                fontWeight: 'normal',\n                fontFamily: 'Junegull',\n                fontSize: 45,\n                miterLimit: 0,\n                stroke: '#9D0C16',\n                strokeThickness: 6,\n                whiteSpace: 'normal',\n            },\n            portrait: { fontSize: 55 },\n        })\n        public popUpTextCurrencyTextStyle: DynamicPositionObject<IBuyBonusTextStyle> & IBuyBonusTextStyle;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 2, y: -14 },\n        })\n        public popUpTextCurrencyRelativePosition: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IBuyBonusBitmapStyle>({\n            defaults: {\n                fontName: '',\n                fontSize: 10,\n                align: 'center',\n            },\n        })\n        public popUpTextCurrencyBitmapStyle: DynamicPositionObject<IBuyBonusBitmapStyle> & IBuyBonusBitmapStyle;\n        // ---------- END OF POPUP CURRENCY TEXT STYLE CONFIGURATION ----------\n\n        @DefaultValue<INumericValue>({\n            defaults: { value: 320 },\n            landscape: { value: 200 },\n        })\n        public buttonMoneyTextBounds: DynamicPositionObject<INumericValue> & INumericValue;\n\n        @DefaultValue<ISquare>({\n            defaults: {\n                x: 0,\n                y: 0,\n                width: 230,\n                height: 45,\n            },\n        })\n        public buttonMaxBetTextBounds: DynamicPositionObject<ISquare> & ISquare;\n\n        @DefaultValue<ITranslatableTextSprite>({\n            defaults: {\n                x: 0,\n                y: -135,\n                hasTranslatableTextAsset: false,\n            },\n        })\n        public translatableText: DynamicPositionObject<ITranslatableTextSprite> & ITranslatableTextSprite;\n    }\n    return BuyBonusConfigurationInternalClass;\n}\n","import Core, { AnalyticsDispatcher, BaseController } from '@egt/core';\nimport {\n    BonusTypes,\n    FeatureController,\n    ISlotConfiguration,\n    InitialSettings,\n    RootStore,\n    ServerState,\n    SlotComponents,\n    Subjects,\n    UIState,\n} from '@egt/slot';\nimport { fromEvent } from 'rxjs';\nimport { filter, mapTo, takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport BuyBonusViewDefault from '../views/BuyBonusViewDefault';\n@injectable()\nexport default class BuyBonusControllerDefault extends BaseController {\n    public ready: () => Promise<void>;\n\n    constructor(\n        @inject('BuyBonusView') protected view: BuyBonusViewDefault,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('SlotSubjects') public readonly subjects: Subjects,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('FeatureController') protected featureController: FeatureController,\n    ) {\n        super(view);\n    }\n\n    public async onGameStarted(_initialSettings: any): Promise<void> {\n        this.subjects.FACTOR_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(this.onBuyBonusDisable.bind(this));\n        this.subjects.DISABLED_BUY_BONUS.pipe(takeUntil(this.DESTROY)).subscribe(this.onBuyBonusDisable.bind(this));\n        this.subjects.REELS_START.pipe(takeUntil(this.DESTROY)).subscribe(this.onReelsStart.bind(this));\n        // this.subjects.REELS_STOPPED.pipe(takeUntil(this.DESTROY)).subscribe(this.onReelsStop.bind(this));\n        this.subjects.GAMBLE_OPENED.pipe(takeUntil(this.DESTROY)).subscribe(this.onSettingsPopupOpened.bind(this));\n        this.rootStore.subjects.OPEN_SETTINGS_POPUP.pipe(takeUntil(this.DESTROY), mapTo(true)).subscribe(\n            this.onSettingsPopupOpened.bind(this, true),\n        );\n        this.rootStore.subjects.CLOSE_SETTINGS_POPUP.pipe(takeUntil(this.DESTROY), mapTo(false)).subscribe(\n            this.onSettingsPopupOpened.bind(this, false),\n        );\n        this.rootStore.subjects.KEY_UP.pipe(takeUntil(this.DESTROY)).subscribe(this.onKeyPressed.bind(this));\n        this.subjects.BUY_BONUS_AND_DOUBLE_CHANCE_VISIBLE.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.hideWhenRecovery.bind(this),\n        );\n        Core.ON_SERVER_MESSAGE.pipe(takeUntil(this.DESTROY)).subscribe(this.onServerMessage.bind(this));\n        // this.rootStore.domainStore.COLLECT_RESPONSE.pipe(takeUntil(this.DESTROY)).subscribe(this.onCollect.bind(this));\n\n        // This is breaking logic in lines after not-winning gamble, the logic here is changed a lot and look like it is not needed anymore\n        /*   if (initialSettings.game) {\n            this.rootStore.domainStore.betResponse = new BetResponse(initialSettings, 0);\n        } */\n        this.onBuyBonusDisable();\n        this.view.init();\n        this.rootStore.uiStore.STATE.pipe(takeUntil(this.DESTROY)).subscribe(this.onStateChanged.bind(this));\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/default/controllers/BuyBonusControllerDefault.ts:58:9\",(this.view.btnHitArea),\"pointertap\"]), fromEvent(this.view.btnHitArea, 'pointertap'))\n            .pipe(\n                filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.onBuyFeatureClicked.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/default/controllers/BuyBonusControllerDefault.ts:65:9\",(this.view.yesButton),\"pointertap\"]), fromEvent(this.view.yesButton, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onBuyConfirmed.bind(this));\n\n        if (Core.isReplayer) {\n            Core.REPLAYER_ACTION.pipe(\n                filter((p) => p.module === SlotComponents.BUY_BONUS),\n                takeUntil(this.DESTROY),\n            ).subscribe((params) => {\n                this.view.state = params.data;\n            });\n        }\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/default/controllers/BuyBonusControllerDefault.ts:78:9\",(this.view.noButton),\"pointertap\"]), fromEvent(this.view.noButton, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onCancelClicked.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/default/controllers/BuyBonusControllerDefault.ts:82:9\",(this.view.overlay),\"pointertap\"]), fromEvent(this.view.overlay, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onCancelClicked.bind(this));\n\n        if (\n            this.settings.state === ServerState.FREESPIN &&\n            this.settings.settings.game.state.rounds?.filter((round) => round.type === 'FREESPIN')[0]?.count !==\n                this.settings.settings.game.state.rounds?.filter((round) => round.type === 'FREESPIN')[0]?.remain\n        ) {\n            this.view.state = 'Off';\n            await this.ready();\n            this.view.visible = false;\n        }\n        if (\n            this.settings.state === ServerState.IDLE ||\n            (this.rootStore.domainStore.betResponse &&\n                this.rootStore.domainStore.betResponse.bonus &&\n                this.rootStore.domainStore.betResponse.bonus.type !== BonusTypes.GIFT_SPIN &&\n                this.rootStore.domainStore.betResponse.bonus.type !== BonusTypes.BUY_BONUS)\n        ) {\n            this.view.state = 'On';\n        } else {\n            this.view.state = 'Off';\n        }\n        if (this.settings.settings.game && this.settings.state !== ServerState.IDLE) {\n            this.view.recovery = true;\n        }\n    }\n\n    private onBuyFeatureClicked(): void {\n        if (this.view.state === 'Off' || this.rootStore.subjects.SHOW_JP_STATS.value.type !== -1) {\n            return;\n        }\n        AnalyticsDispatcher.buyBonusClickEvent();\n        this.rootStore.subjects.CLOSE_ALL_POPUPS.next();\n        // this.rootStore.subjects.TAB_OPENED.next(true);\n        Core.sounds.play('buyBonus');\n        this.view.state = 'Off';\n        this.subjects.DISABLED_DOUBLE_CHANCE.next(true);\n        this.view.showPopUp();\n    }\n\n    private onBuyConfirmed(): void {\n        if (this.rootStore.uiStore.STATE.value === UIState.DISABLED) {\n            return;\n        }\n        // const win = this.rootStore.uiStore.WIN.value.amount || 0;\n        this.rootStore.subjects.MODAL_PRESSED.next();\n        Core.sounds.play('buyBonusYes');\n        this.view.state = 'Activated';\n        this.subjects.DISABLED_DOUBLE_CHANCE.next(false);\n        this.view.closePopUp();\n        this.settings.factor = this.settings.getFactorByUniqueGameMode(this.slotConfiguration.buyBonusGameMode);\n        this.settings.gameMode = this.slotConfiguration.buyBonusGameMode;\n        // this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_RESPONSE);\n        this.rootStore.subjects.CLOSE_ALL_POPUPS.next();\n        // this.rootStore.subjects.BEFORE_SPIN.next();\n        // this.rootStore.subjects.SPIN_STARTED.next();\n\n        // this.rootStore.uiStore.BALANCE.next(this.rootStore.uiStore.BALANCE.value - this.getBetAmount() + win);\n\n        // this.rootStore.domainStore.bet();\n        this.rootStore.subjects.START_MANUAL_SPIN.next();\n\n        this.settings.factor = this.settings.getFactorByUniqueGameMode('NORMAL_MODE');\n        this.settings.gameMode = 'NORMAL_MODE';\n    }\n\n    private onBuyCanceled(): void {\n        this.view.state = 'On';\n        this.subjects.DISABLED_DOUBLE_CHANCE.next(false);\n        this.view.closePopUp();\n    }\n\n    private onCancelClicked(): void {\n        this.onBuyCanceled();\n        Core.sounds.play('buyBonusNo');\n    }\n\n    private onStateChanged(): void {\n        if (\n            this.view.state === 'Activated' &&\n            (this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_RESPONSE ||\n                this.rootStore.uiStore.STATE.value === UIState.FREESPIN)\n        ) {\n            return;\n        }\n\n        if (\n            this.rootStore.settings.haveGameMode('DOUBLE_CHANCE') &&\n            this.settings.factor !== this.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE') &&\n            (this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value === 0 ||\n                this.rootStore.subjects.SPECIAL_STOP_CONDITION_REACHED.value) &&\n            this.rootStore.domainStore.SERVER_STATE.value !== ServerState.BONUS_SUMMARY &&\n            (this.rootStore.uiStore.STATE.value === UIState.IDLE ||\n                this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT) &&\n            !this.rootStore.uiStore.fastSpinMode &&\n            (!this.rootStore.domainStore.betResponse?.bonus ||\n                this.rootStore.domainStore.betResponse?.bonus?.remaining === 0) &&\n            this.checkForMaxBet()\n        ) {\n            this.view.state = 'On';\n            this.rootStore.subjects.DISABLED_BUY_BONUS.next({ disabled: false, doNotChangeVisual: false });\n        } else {\n            this.view.state = 'Off';\n        }\n    }\n\n    private checkForMaxBet(): boolean {\n        const buyBonusValue: number =\n            Core.SELECTED_DENOMINATION.value *\n            this.rootStore.uiStore.SELECTED_BET.value *\n            (this.rootStore.settings.factors[this.rootStore.settings.factors.length - 1] /\n                this.rootStore.uiStore.units);\n        const maxBetForBonus: number = Math.min(\n            this.rootStore.settings.clientSettings?.maxBetLimits\n                ? this.rootStore.settings.clientSettings?.maxBetLimits[Core.PLAYER_BALANCE.value.currency]\n                : Infinity,\n            this.rootStore.settings.maxBet ?? Infinity,\n        );\n\n        if (maxBetForBonus && buyBonusValue > maxBetForBonus) {\n            return false;\n        }\n        return true;\n    }\n\n    private onBuyBonusDisable(): void {\n        if (\n            this.rootStore.subjects.DISABLED_BUY_BONUS.value.disabled ||\n            this.subjects.GAMBLE_OPENED.value ||\n            (this.rootStore.settings.haveGameMode('DOUBLE_CHANCE') &&\n                this.settings.factor === this.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE')) ||\n            this.rootStore.domainStore.SERVER_STATE.value === ServerState.BONUS_IDLE ||\n            (this.rootStore.domainStore.betResponse &&\n                this.rootStore.domainStore.betResponse.bonus &&\n                (this.rootStore.domainStore.betResponse.bonus.type === BonusTypes.GIFT_SPIN ||\n                    this.rootStore.domainStore.betResponse.bonus.type === BonusTypes.BUY_BONUS) &&\n                this.rootStore.domainStore.betResponse.state === ServerState.WIN)\n        ) {\n            this.view.state = 'Off';\n        } else {\n            this.view.state = 'On';\n        }\n    }\n\n    private getBetAmount(): number {\n        return (\n            this.rootStore.uiStore.SELECTED_BET.value *\n            this.settings.getFactorByUniqueGameMode(this.slotConfiguration.buyBonusGameMode) *\n            Core.SELECTED_DENOMINATION.value\n        );\n    }\n\n    private onSettingsPopupOpened(opened?: boolean): void {\n        if (\n            opened ||\n            this.subjects.GAMBLE_OPENED.value ||\n            // this.rootStore.domainStore.SERVER_STATE.value === ServerState.BONUS_IDLE ||\n            this.featureController.isInGiftSpins\n        ) {\n            this.view.state = 'Off';\n            this.view.closePopUp();\n        } else if (\n            this.rootStore.settings.haveGameMode('DOUBLE_CHANCE') &&\n            this.settings.factor !== this.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE')\n        ) {\n            this.view.state = 'On';\n            this.subjects.DISABLED_DOUBLE_CHANCE.next(false);\n        }\n    }\n\n    private onKeyPressed(e: KeyboardEvent): void {\n        if (e === null) {\n            return;\n        }\n        // close modal when popup if space/enter/letter/digit is pressed\n        if (\n            this.view.overlay.visible &&\n            ((e.code !== undefined &&\n                (e.code === 'Space' ||\n                    e.code === 'Enter' ||\n                    e.code === 'NumpadEnter' ||\n                    e.code.indexOf('key') !== -1 ||\n                    e.code.indexOf('Digit') !== -1)) ||\n                (e.keyCode !== undefined && (e.keyCode === 32 || e.keyCode === 13)) ||\n                (e.keyCode >= 65 && e.keyCode <= 90) ||\n                (e.keyCode >= 48 && e.keyCode <= 57))\n        ) {\n            this.onCancelClicked();\n        }\n    }\n\n    private onReelsStart(): void {\n        this.view.recovery = false;\n        this.view.closePopUp();\n    }\n\n    private onServerMessage(response): void {\n        switch (response.event) {\n            case 'spin':\n                if (\n                    response.state === ServerState.WIN &&\n                    this.rootStore.settings.haveGameMode('DOUBLE_CHANCE') &&\n                    this.settings.factor !== this.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE') &&\n                    this.rootStore.domainStore.SERVER_STATE.value !== ServerState.BONUS_IDLE\n                ) {\n                    this.view.state = 'On';\n                }\n                break;\n            case 'balance':\n                if (!this.view.popUpContainer.visible && !this.rootStore.subjects.TAB_OPENED.value) {\n                    this.onStateChanged();\n                }\n                break;\n        }\n    }\n\n    private hideWhenRecovery(zOrder: number): void {\n        this.view.visible = Boolean(zOrder);\n\n        this.view.zIndex = zOrder;\n    }\n}\n","import Core, { Money } from '@egt/core';\nimport {\n    BangupActionConsts,\n    BonusTypes,\n    ISlotConfiguration,\n    InitialSettings,\n    RootStore,\n    ServerState,\n    UIState,\n} from '@egt/slot';\nimport { ViewContainer } from '@egt/ui-lib';\nimport { BitmapText, Container, Graphics, ITextStyle, Sprite, Text, TextStyle } from 'pixi.js';\nimport { merge } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { IBuyBonusComponentConfigurationDefault } from '../interfaces/InterfacesDefault';\n\n@injectable()\nexport default class BuyBonusViewDefault extends ViewContainer {\n    public set state(value: 'On' | 'Off' | 'Activated') {\n        if (\n            (value === 'On' &&\n                this.money &&\n                this.money.moneyInUnits > this.rootStore.uiStore.BALANCE.value + this.getWinAmount()) ||\n            (this.settings.state !== ServerState.IDLE && this.settings.state !== ServerState.WIN && this.recovery)\n        ) {\n            value = 'Off';\n        }\n        this.recovery = false;\n\n        // TODO this code is temporary and limitation should come from backend\n        if (this.limitHit) {\n            value = 'Off';\n        }\n\n        if (this.btnHitArea) {\n            if (value === 'On') {\n                this.btnHitArea.cursor = 'pointer';\n                this.btnHitArea.interactive = true;\n            } else {\n                this.btnHitArea.cursor = 'normal';\n                this.btnHitArea.interactive = false;\n            }\n        }\n\n        this._state = value;\n        this.setState();\n    }\n\n    public get state(): 'On' | 'Off' | 'Activated' {\n        return this._state;\n    }\n    public yesButton: Graphics;\n    public noButton: Graphics;\n    public overlay: Graphics;\n    public recovery: boolean = false;\n    public btnHitArea: Graphics;\n    public buyFeatureButton: Sprite;\n    public popUpContainer: Sprite;\n\n    protected money: Money;\n    protected popUpTextMoney: any;\n    protected popUpTextCurrency: any;\n    protected popUpTextsHolder: Container;\n    protected textsHolder: Sprite;\n    protected popUpGraphics: Graphics;\n\n    protected _state: 'On' | 'Off' | 'Activated';\n\n    protected buttonTextMoney: Text;\n    protected buttonTextCurrency: Text;\n    protected buttonTextMaxBet: Text;\n\n    protected limitHit: boolean = false;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('BuyBonusComponentConfiguration')\n        protected componentConfiguration: IBuyBonusComponentConfigurationDefault,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n    ) {\n        super();\n        this.name = 'BuyBonusView';\n    }\n\n    public destroy(): void {\n        this.popUpTextsHolder.destroy();\n        this.popUpContainer.removeChildren();\n        this.removeChild(this.popUpContainer);\n        this.popUpContainer.destroy();\n        this.yesButton.destroy();\n        this.noButton.destroy();\n        super.destroy();\n    }\n\n    public init(): void {\n        const orientation = merge(Core.ORIENTATION, Core.LEFT_HAND_MODE, this.rootStore.subjects.ACTIVE_FEATURE);\n        orientation.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n        // Core.LEFT_HAND_MODE.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n        Core.MONEY_MODE_IN_CREDITS.pipe(takeUntil(Core.ON_GAME_UNLOADED)).subscribe(this.onMoneyModeChanged.bind(this));\n        Core.SELECTED_DENOMINATION.pipe(takeUntil(Core.ON_GAME_UNLOADED)).subscribe(\n            this.onDenominationOrBetChanged.bind(this),\n        );\n        this.rootStore.uiStore.SELECTED_BET.pipe(takeUntil(Core.ON_GAME_UNLOADED)).subscribe(\n            this.onDenominationOrBetChanged.bind(this),\n        );\n\n        this.createButton();\n        this.createPopUp();\n\n        this.createTexts();\n        this.setOrientation();\n    }\n\n    public showPopUp(): void {\n        this.popUpContainer.visible = true;\n        this.overlay.visible = true;\n        this.rootStore.subjects.BUY_BONUS_POPUP_OPENED.next(true);\n        this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(true);\n        this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(true);\n        Core.UI_BLOCKER.next(true);\n    }\n\n    public closePopUp(): void {\n        if (this.popUpContainer && this.popUpContainer.visible) {\n            this.popUpContainer.visible = false;\n            this.overlay.visible = false;\n            this.rootStore.subjects.BUY_BONUS_POPUP_OPENED.next(false);\n            this.rootStore.subjects.TAB_OPENED.next(false);\n            this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(false);\n            this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(false);\n            Core.UI_BLOCKER.next(false);\n        }\n    }\n\n    protected createTexts(_customFont: boolean = false): void {\n        this.textsHolder = new Sprite();\n        this.textsHolder.name = 'Texts holder';\n\n        this.buyFeatureButton.addChild(this.textsHolder);\n\n        this.onDenominationOrBetChanged();\n\n        this.buttonTextMoney = new Text(\n            this.money.stringMoneyWithoutCents,\n            this.componentConfiguration.buttonTextMoneyTextStyle,\n        );\n\n        this.buttonTextMoney.resolution = 2;\n        this.textsHolder.addChild(this.buttonTextMoney);\n\n        this.buttonTextCurrency = new Text(\n            this.rootStore.uiStore.currency,\n            this.componentConfiguration.buttonTextCurrencyTextStyle,\n        );\n\n        this.buttonTextCurrency.resolution = 2;\n        this.textsHolder.addChild(this.buttonTextCurrency);\n\n        this.buttonTextMaxBet = new Text(\n            Core.translator.translate('MAX_BET'),\n            this.componentConfiguration.buttonTextMaxBetTextStyle,\n        );\n        this.buttonTextMaxBet.name = 'Max bet sign';\n        this.buttonTextMaxBet.anchor.set(0.5, 0);\n        this.buyFeatureButton.addChild(this.buttonTextMaxBet);\n\n        if (this.componentConfiguration.moneyFontType.type === 'text') {\n            const popUpTextStyle = new TextStyle(\n                this.componentConfiguration.popUpTextMoneyTextStyle.positionData.defaults as ITextStyle,\n            );\n            this.popUpTextMoney = new Text(this.money.stringMoneyWithoutCents, popUpTextStyle);\n            this.popUpTextMoney.anchor.set(0.5, 1);\n        } else {\n            this.popUpTextMoney = new BitmapText(\n                this.money.stringMoneyWithoutCents,\n                this.componentConfiguration.popUpTextMoneyBitmapStyle.positionData.defaults,\n            );\n            this.popUpTextMoney.anchor.set(0.5, 4);\n        }\n        if (this.componentConfiguration.currencyFontType.type === 'text') {\n            const popUpTextCurrencyStyle = new TextStyle(\n                this.componentConfiguration.popUpTextCurrencyTextStyle.positionData.defaults as ITextStyle,\n            );\n            this.popUpTextCurrency = new Text(this.rootStore.uiStore.currency, popUpTextCurrencyStyle);\n            this.popUpTextCurrency.anchor.set(0.5, 1);\n        } else {\n            this.popUpTextCurrency = new BitmapText(\n                this.rootStore.uiStore.currency,\n                this.componentConfiguration.popUpTextCurrencyBitmapStyle.positionData.defaults,\n            );\n            this.popUpTextCurrency.anchor.set(0.5, 4);\n        }\n\n        this.popUpTextMoney.resolution = 2;\n        this.popUpTextCurrency.resolution = 2;\n\n        this.popUpTextsHolder.addChild(this.popUpTextMoney);\n\n        this.popUpTextsHolder.addChild(this.popUpTextCurrency);\n\n        this.addTranslatableText();\n\n        this.onDenominationOrBetChanged();\n        this.setOrientation();\n    }\n\n    protected setOrientation(): void {\n        if (!this.buttonTextMoney) {\n            return;\n        }\n        this.buyFeatureButton.scale.set(this.componentConfiguration.tilePosition.scale);\n        this.buyFeatureButton.x = this.componentConfiguration.tilePosition.x;\n        this.buyFeatureButton.y = this.componentConfiguration.tilePosition.y;\n        this.buyFeatureButton.visible = this.componentConfiguration.tilePosition.visible !== false;\n\n        this.yesButton.x = this.componentConfiguration.yesButtonPosition.x;\n        this.yesButton.y = this.componentConfiguration.yesButtonPosition.y;\n        this.noButton.x = this.componentConfiguration.noButtonPosition.x;\n        this.noButton.y = this.componentConfiguration.noButtonPosition.y;\n        this.yesButton.width = this.componentConfiguration.yesButtonPosition.width || 0;\n        this.noButton.width = this.componentConfiguration.noButtonPosition.width || 0;\n        this.yesButton.height = this.componentConfiguration.yesButtonPosition.height || 0;\n        this.noButton.height = this.componentConfiguration.noButtonPosition.height || 0;\n\n        this.popUpContainer.x = Core.display.stage.width / 2;\n        this.popUpContainer.y = this.componentConfiguration.popupContainerPosition.y;\n        this.popUpContainer.scale.set(this.componentConfiguration.popupContainerPosition.scale);\n\n        if (this.componentConfiguration.moneyFontType.type === 'text') {\n            this.popUpTextMoney.style.fontSize = this.componentConfiguration.popUpTextMoneyTextStyle.fontSize;\n        } else {\n            this.popUpTextMoney.fontSize = this.componentConfiguration.popUpTextMoneyBitmapStyle.fontSize;\n        }\n        if (this.componentConfiguration.currencyFontType.type === 'text') {\n            this.popUpTextCurrency.style.fontSize = this.componentConfiguration.popUpTextCurrencyTextStyle.fontSize;\n        } else {\n            this.popUpTextCurrency.fontSize = this.componentConfiguration.popUpTextCurrencyBitmapStyle.fontSize;\n        }\n\n        this.buttonTextMaxBet.x = this.componentConfiguration.maxBetTextPossition.x;\n        this.buttonTextMaxBet.y = this.componentConfiguration.maxBetTextPossition.y;\n\n        if (this.componentConfiguration.translatableText.hasTranslatableTextAsset) {\n            this.popUpContainer.texture = Core.assets.getTextureFromSpriteSheet('baseFreeSpins', 'buyFeaturePopUp.png');\n        } else {\n            if (Core.ORIENTATION.value.isLandscape) {\n                this.popUpContainer.texture = Core.assets.getTextureFromSpriteSheet('buyBonus', 'buyFeaturePopUp.png');\n            } else {\n                this.popUpContainer.texture = Core.assets.getTextureFromSpriteSheet(\n                    'buyBonus',\n                    'buyFeaturePopUpPortrait.png',\n                );\n            }\n        }\n\n        if (this.componentConfiguration.buyBonusTileType.type === 'vertical') {\n            this.setTextPositionVertical();\n        } else {\n            this.setTextPositionHorizontal();\n        }\n\n        this.popUpTextMoney.x =\n            -this.popUpTextCurrency.width / 2 + this.componentConfiguration.popUpTextMoneyRelativePosition.x;\n        this.popUpTextMoney.y = this.componentConfiguration.popUpTextMoneyRelativePosition.y;\n        this.popUpTextCurrency.x =\n            this.popUpTextMoney.width / 2 + this.componentConfiguration.popUpTextCurrencyRelativePosition.x;\n\n        this.popUpTextCurrency.y =\n            this.popUpTextMoney.y + this.componentConfiguration.popUpTextCurrencyRelativePosition.y;\n\n        this.fitPopUpTexts();\n\n        if (this.overlay) {\n            this.overlay.width = Core.display.stage.width;\n            this.overlay.height = Core.display.stage.height;\n        }\n\n        if (this.popUpContainer) {\n            this.popUpGraphics.width = this.componentConfiguration.popupHitAreaGraphics.width;\n            this.popUpGraphics.height = this.componentConfiguration.popupHitAreaGraphics.height;\n            this.popUpGraphics.x = this.componentConfiguration.popupHitAreaGraphics.x;\n            this.popUpGraphics.y = this.componentConfiguration.popupHitAreaGraphics.y;\n        }\n        this.setState();\n    }\n\n    protected fitPopUpTexts(): void {\n        this.popUpTextsHolder.scale.set(1);\n        this.popUpTextsHolder.pivot.set(0);\n        this.popUpTextsHolder.position.set(0);\n\n        const maxWidth = this.componentConfiguration.popUpMoneyTextBounds.value;\n        const bounds = this.popUpTextsHolder.getLocalBounds();\n        if (!maxWidth || bounds.width <= maxWidth) {\n            return;\n        }\n\n        // shrink around the center of the texts so they stay where they were placed\n        const centerX = bounds.x + bounds.width / 2;\n        const centerY = bounds.y + bounds.height / 2;\n        this.popUpTextsHolder.pivot.set(centerX, centerY);\n        this.popUpTextsHolder.position.set(centerX, centerY);\n        this.popUpTextsHolder.scale.set(maxWidth / bounds.width);\n    }\n\n    protected addTranslatableText(): void {\n        if (this.componentConfiguration.translatableText.hasTranslatableTextAsset) {\n            const translatableText = new Sprite();\n            translatableText.anchor.set(0.5);\n            translatableText.visible = true;\n            translatableText.texture = Core.assets.getTextureFromSpriteSheet(\n                'baseFreeSpinsTranslations',\n                'buyFeaturePopUpText.png',\n            );\n            translatableText.y = this.componentConfiguration.translatableText.y;\n            translatableText.x = this.componentConfiguration.translatableText.x;\n\n            this.popUpContainer.addChild(translatableText);\n        }\n    }\n\n    protected setTextPositionVertical(): void {\n        if (!this.buttonTextMoney) {\n            return;\n        }\n        this.textsHolder.scale.set(1);\n        let scaleFactor: number = this.componentConfiguration.textHolderPossition.scale || 1;\n        const primaryBounds = this.componentConfiguration.buttonMoneyTextBounds.value / scaleFactor;\n        this.buttonTextMoney.scale.set(1);\n        this.buttonTextCurrency.scale.set(1);\n\n        this.buttonTextCurrency.x = (this.buttonTextMoney.width - this.buttonTextCurrency.width) / 2;\n        this.buttonTextMoney.y = this.buttonTextCurrency.height + this.componentConfiguration.currencyOffset.y;\n        this.buttonTextCurrency.y = 0;\n\n        if (this.textsHolder.getLocalBounds().width > primaryBounds) {\n            scaleFactor = (primaryBounds / this.textsHolder.getLocalBounds().width) * scaleFactor;\n            this.buttonTextCurrency.scale.set(\n                (this.componentConfiguration.textHolderPossition.scale || 1) / scaleFactor,\n            );\n        }\n\n        this.buttonTextMaxBet.style.wordWrap = true;\n        this.buttonTextMaxBet.scale.set(1);\n        if (this.buttonTextMaxBet.width > this.componentConfiguration.buttonMaxBetTextBounds.width) {\n            this.buttonTextMaxBet.scale.set(\n                this.componentConfiguration.buttonMaxBetTextBounds.width / this.buttonTextMaxBet.width,\n            );\n        }\n\n        const maxBetOffset =\n            this.buttonTextMaxBet.visible &&\n            this.buttonTextMaxBet.height > this.componentConfiguration.buttonMaxBetTextBounds.height\n                ? this.componentConfiguration.maxBetTextOffset.wrapedText // bigger offset because max bet text is wrapped\n                : this.componentConfiguration.maxBetTextOffset.normalText;\n\n        this.buttonTextCurrency.x = (this.buttonTextMoney.width - this.buttonTextCurrency.width) / 2;\n        this.buttonTextMoney.y = this.buttonTextCurrency.height + this.componentConfiguration.currencyOffset.y;\n        this.buttonTextCurrency.y = 0;\n\n        this.textsHolder.pivot.set(\n            this.textsHolder.getLocalBounds().width / 2,\n            this.textsHolder.getLocalBounds().height / 2,\n        );\n\n        this.textsHolder.scale.set(scaleFactor);\n\n        this.textsHolder.x = this.componentConfiguration.textHolderPossition.x;\n        this.textsHolder.y = this.componentConfiguration.textHolderPossition.y + maxBetOffset;\n    }\n\n    protected setTextPositionHorizontal(): void {\n        if (!this.buttonTextMoney) {\n            return;\n        }\n        this.textsHolder.scale.set(1);\n        this.buttonTextMaxBet.style.wordWrap = false;\n\n        let scaleFactor: number = this.componentConfiguration.textHolderPossition.scale || 1;\n        let maxBetOffset: number = 0;\n        if (this.buttonTextMaxBet.visible) {\n            scaleFactor *= 0.8;\n            maxBetOffset = 15;\n        }\n        this.buttonTextMoney.scale.set(1);\n        this.buttonTextCurrency.scale.set(1);\n        const spaceBetween = 3;\n\n        this.buttonTextCurrency.x = this.buttonTextMoney.x + this.buttonTextMoney.width + spaceBetween;\n\n        this.buttonTextMoney.y = 0;\n        this.buttonTextCurrency.y = this.buttonTextMoney.height - this.buttonTextCurrency.height;\n        this.textsHolder.pivot.set(\n            this.buttonTextMoney.getLocalBounds().width / 2,\n            this.textsHolder.getLocalBounds().height / 2,\n        );\n\n        const primaryBounds = this.componentConfiguration.buttonMoneyTextBounds.value / scaleFactor;\n        if (this.textsHolder.getLocalBounds().width > primaryBounds) {\n            scaleFactor = (primaryBounds / this.textsHolder.getLocalBounds().width) * scaleFactor;\n        }\n        this.textsHolder.scale.set(scaleFactor);\n        this.textsHolder.x = this.componentConfiguration.textHolderPossition.x;\n        this.textsHolder.y = this.componentConfiguration.textHolderPossition.y + maxBetOffset;\n    }\n\n    protected createHitArea(): void {\n        if (this.btnHitArea) {\n            this.btnHitArea.clear();\n        } else {\n            this.btnHitArea = new Graphics();\n            this.btnHitArea.name = 'Button hit area';\n        }\n        this.btnHitArea\n            .beginFill(0xff0000, 0.5)\n            .drawRoundedRect(\n                this.componentConfiguration.btnHitArea.x,\n                this.componentConfiguration.btnHitArea.y,\n                this.componentConfiguration.btnHitArea.width,\n                this.componentConfiguration.btnHitArea.height,\n                this.componentConfiguration.btnHitArea.radius,\n            )\n            .endFill();\n        this.btnHitArea.cursor = 'pointer';\n        this.btnHitArea.interactive = true;\n        this.btnHitArea.alpha = 0;\n        this.buyFeatureButton.addChild(this.btnHitArea);\n    }\n\n    protected updateButtonTextsOpacity(): void {\n        if (this.buttonTextMoney) {\n            let textOpacity: number = this.componentConfiguration.tileOpacity.textOn;\n            let btnOpacity: number = this.componentConfiguration.tileOpacity.tileOn;\n            this.btnHitArea.cursor = 'pointer';\n            this.btnHitArea.interactive = true;\n            if (this.state === 'Off') {\n                textOpacity = this.componentConfiguration.tileOpacity.textOff;\n                btnOpacity = this.componentConfiguration.tileOpacity.tileOff;\n                this.btnHitArea.cursor = 'normal';\n                this.btnHitArea.interactive = false;\n            } else if (this.state === 'Activated') {\n                textOpacity = this.componentConfiguration.tileOpacity.textActivated;\n                btnOpacity = this.componentConfiguration.tileOpacity.tileActivated;\n                this.btnHitArea.cursor = 'normal';\n                this.btnHitArea.interactive = false;\n            }\n            this.buyFeatureButton.alpha = btnOpacity;\n            this.buttonTextMoney.alpha = textOpacity;\n            this.buttonTextCurrency.alpha = textOpacity;\n        }\n    }\n\n    protected createPopUp(): void {\n        this.overlay = new Graphics();\n        this.overlay\n            .beginFill(this.componentConfiguration.overlay.color, this.componentConfiguration.overlay.opacity)\n            .drawRect(this.x * -1, this.y * -1, Core.display.stage.width, Core.display.stage.height)\n            .endFill();\n        this.addChild(this.overlay);\n        this.overlay.interactive = true;\n        this.overlay.visible = false;\n\n        this.popUpContainer = new Sprite();\n        this.popUpContainer.anchor.set(0.5);\n        this.popUpContainer.x = Core.display.stage.width / 2;\n        this.popUpContainer.y = this.componentConfiguration.popupContainerPosition.y;\n        this.popUpContainer.visible = false;\n        this.popUpContainer.interactive = false;\n        this.popUpContainer.scale.set(this.componentConfiguration.popupContainerPosition.scale);\n        this.addChild(this.popUpContainer);\n\n        this.popUpGraphics = new Graphics();\n        this.popUpGraphics.beginFill(0x000000, 0.4).drawRect(0, 0, 600, 500).endFill();\n        this.popUpGraphics.alpha = 0;\n        this.popUpGraphics.interactive = true;\n        this.popUpContainer.addChild(this.popUpGraphics);\n\n        this.yesButton = new Graphics();\n        this.yesButton\n            .beginFill(0x000000, 1)\n            .drawRect(\n                0,\n                0,\n                this.componentConfiguration.yesButtonPosition.width || 0,\n                this.componentConfiguration.yesButtonPosition.height || 0,\n            )\n            .endFill();\n        this.yesButton.alpha = 0;\n        this.yesButton.cursor = 'pointer';\n        this.yesButton.interactive = true;\n        this.popUpContainer.addChild(this.yesButton);\n\n        this.noButton = new Graphics();\n        this.noButton\n            .beginFill(0x000000, 1)\n            .drawRect(\n                0,\n                0,\n                this.componentConfiguration.noButtonPosition.width || 0,\n                this.componentConfiguration.noButtonPosition.height || 0,\n            )\n            .endFill();\n        this.noButton.alpha = 0;\n        this.noButton.cursor = 'pointer';\n        this.noButton.interactive = true;\n        this.popUpContainer.addChild(this.noButton);\n\n        this.popUpTextsHolder = new Container();\n        this.popUpTextsHolder.name = 'Popup texts holder';\n        this.popUpContainer.addChild(this.popUpTextsHolder);\n    }\n\n    private createButton(): void {\n        this.buyFeatureButton = new Sprite();\n        this.buyFeatureButton.name = 'Buy bonus button';\n        this.addChild(this.buyFeatureButton);\n        this.buyFeatureButton.anchor.set(0.5);\n    }\n\n    private isDoubleChanceFactorActive(): boolean {\n        return (\n            this.rootStore.settings.haveGameMode('DOUBLE_CHANCE') &&\n            this.settings.factor === this.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE')\n        );\n    }\n\n    private isInBonusIdleState(): boolean {\n        return this.rootStore.domainStore.SERVER_STATE.value === ServerState.BONUS_IDLE;\n    }\n\n    private isBonusWinState(): boolean {\n        const betResponse = this.rootStore.domainStore.betResponse;\n        if (!betResponse?.bonus) return false;\n\n        const isGiftSpinOrBuyBonus =\n            betResponse.bonus.type === BonusTypes.GIFT_SPIN || betResponse.bonus.type === BonusTypes.BUY_BONUS;\n\n        return isGiftSpinOrBuyBonus && betResponse.state === ServerState.WIN;\n    }\n\n    private shouldDisableBuyBonus(): boolean {\n        return (\n            this.isDoubleChanceFactorActive() ||\n            this.isInBonusIdleState() ||\n            this.isBonusWinState() ||\n            this.rootStore.uiStore.STATE.value === UIState.SLIDING_BETS\n        );\n    }\n\n    private onDenominationOrBetChanged(): void {\n        let buyBonusValue: number =\n            this.rootStore.settings.factors[this.rootStore.settings.factors.length - 1] *\n            Core.SELECTED_DENOMINATION.value *\n            this.rootStore.uiStore.SELECTED_BET.value;\n\n        this.limitHit = false;\n        if (this.buttonTextMaxBet) {\n            this.buttonTextMaxBet.visible = false;\n        }\n        if (this.settings.clientSettings?.maxBetLimits || this.settings.maxBet) {\n            const maxBetForBonus: number = Math.min(\n                this.settings.clientSettings?.maxBetLimits\n                    ? this.settings.clientSettings?.maxBetLimits[Core.PLAYER_BALANCE.value.currency]\n                    : Infinity,\n                this.settings.maxBet ?? Infinity,\n            );\n            if (maxBetForBonus && buyBonusValue > maxBetForBonus * 100) {\n                this.limitHit = true;\n                buyBonusValue = maxBetForBonus * 100;\n                if (this.buttonTextMaxBet) {\n                    this.buttonTextMaxBet.visible = true;\n                }\n            }\n        }\n\n        this.money = new Money(buyBonusValue);\n\n        this.state = this.shouldDisableBuyBonus() ? 'Off' : 'On';\n\n        this.onMoneyModeChanged();\n    }\n\n    private getWinAmount(): number {\n        const collectBalance = this.rootStore.domainStore.collectResponse?.balance;\n        const isIdleState = this.rootStore.uiStore.STATE.value === UIState.IDLE;\n        const isCollectAction = this.rootStore.uiStore.WIN.value.action === BangupActionConsts.COLLECT;\n        const hasBalanceChanged = collectBalance !== this.rootStore.uiStore.BALANCE.value;\n        // Check for condition where the game enters IDLE state after collect\n        // but balance is not yet updated due to animations.\n        if (collectBalance && isIdleState && isCollectAction && hasBalanceChanged) {\n            // Use prev win amount as after collect the win amount is set to 0\n            const winAmount = Number(this.rootStore.uiStore.WIN.prevValue.amount);\n            return winAmount ? winAmount : 0;\n        }\n        // In all other cases, use the current win amount.\n        const winAmount = Number(this.rootStore.uiStore.WIN.value.amount);\n        return winAmount ? winAmount : 0;\n    }\n\n    private onMoneyModeChanged(): void {\n        if (!this.buttonTextMoney) {\n            return;\n        }\n        this.buttonTextMoney.text = this.money.stringMoneyWithoutCents;\n        this.popUpTextMoney.text = this.money.stringMoneyWithoutCents;\n        this.state = this.state;\n\n        this.setOrientation();\n    }\n\n    private setState(): void {\n        if (!this.buyFeatureButton) {\n            return;\n        }\n\n        if (Core.ORIENTATION.value.isLandscape) {\n            this.buyFeatureButton.texture = Core.assets.getTextureFromSpriteSheet(\n                'buyBonus',\n                'buyFeature' + this._state + 'Landscape.png',\n            );\n        } else {\n            this.buyFeatureButton.texture = Core.assets.getTextureFromSpriteSheet(\n                'buyBonus',\n                'buyFeature' + this._state + 'Portrait.png',\n            );\n        }\n        this.createHitArea();\n        this.updateButtonTextsOpacity();\n    }\n}\n","import Core, {\n    AssetPriority,\n    AssetsCollection,\n    BaseComponentConfiguration,\n    DefaultAssets,\n    DefaultValue,\n    DynamicPositionObject,\n    FeatureFlags,\n    IAsset,\n} from '@egt/core';\nimport {\n    IBalancePositions,\n    IBannerConfig,\n    IBannerInnerPositions,\n    IBBBannerPoint,\n    IBBBtnConfig,\n    IBBPoint,\n    IBBPopUpTitle,\n    IBBXBoundsPoint,\n    IBetOutsidePanelPositions,\n    IBetPanelPositions,\n    IBuyBonusOverlaySettings,\n    ICloseButtonPoint,\n    IDenominationContainer,\n    IInfoTextPositions,\n    IPopUpBackgroundPosition,\n    IToggleTextPositions,\n} from '../interfaces/InterfacesExtendedMultipleBuyBonus';\nimport { IBuyBonusComponentConfigurationExtendedMultipleBuyBonus } from './IBuyBonusComponentConfigurationExtendedMultipleBuyBonus';\nimport { TextStyle } from 'pixi.js';\n\nexport default class BuyBonusComponentConfigurationExtendedMultipleBuyBonus extends BaseComponentConfiguration {}\n\n// the two per-game atlases; the variant is picked centrally from gameWithDoubleChance plus the\n// jurisdiction flags, so a game without double chance only needs gameWithDoubleChance = false\nexport function getExtendedMultipleBuyBonusGameAssets(\n    translatableAssetsType: string = '',\n    mainAssetsType: string = '',\n): IAsset[] {\n    const gameAssetsBase =\n        '../assets/' + Core.configuration.gameKey + '/components/buy-bonus/extended-multiple-buy-bonus';\n    return [\n        {\n            id: 'extendedMultipleBuyBonusTranslatableAssets',\n            url:\n                gameAssetsBase +\n                '/translatableAssets/extendedMultipleBuyBonus' +\n                translatableAssetsType +\n                'TranslatableAssets_' +\n                Core.configuration.language.toLowerCase() +\n                '.json',\n            priority: AssetPriority.HIGHEST,\n            type: 'texture',\n        },\n        {\n            id: 'extendedMultipleBuyBonusMainAssets',\n            url: gameAssetsBase + '/extendedMultipleBuyBonus' + mainAssetsType + 'MainAssets.json',\n            priority: AssetPriority.HIGHEST,\n            type: 'texture',\n        },\n    ];\n}\n\nexport function BuyBonusComponentConfigurationFactoryExtendedMultipleBuyBonus(): any {\n    const gameAssetsBase =\n        '../assets/' + Core.configuration.gameKey + '/components/buy-bonus/extended-multiple-buy-bonus';\n    const svgAsset = (id: string): IAsset => ({\n        id,\n        url: gameAssetsBase + '/svg/' + id + '.svg',\n        priority: AssetPriority.HIGHEST,\n        type: 'svg',\n    });\n\n    // the restriction driven atlas variants are drawn only for games that have double chance\n    const assetsVariant = (gameWithDoubleChance: boolean): { translatable: string; main: string } => {\n        let translatable = '';\n        let main = '';\n        if (gameWithDoubleChance) {\n            if (Core.flags.isActive(FeatureFlags.HIDE_BUY_BONUS)) {\n                translatable = 'OnlyDoubleChance';\n            } else if (Core.flags.isActive(FeatureFlags.HIDE_DOUBLE_CHANCE)) {\n                translatable = 'NoDoubleChance';\n                main = 'NoDoubleChance';\n            }\n        }\n        return { translatable, main };\n    };\n\n    class ExtendedMultipleBuyBonusConfigurationInternalClass\n        extends BuyBonusComponentConfigurationExtendedMultipleBuyBonus\n        implements IBuyBonusComponentConfigurationExtendedMultipleBuyBonus\n    {\n        @DefaultAssets([\n            svgAsset('arrowMinus'),\n            svgAsset('arrowOutsideMinus'),\n            svgAsset('arrowPlus'),\n            svgAsset('arrowOutsidePlus'),\n            svgAsset('betBase'),\n            svgAsset('betOutsideBase'),\n            {\n                id: 'bbBannerFont',\n                url: gameAssetsBase + '/bbBannerFont.fnt',\n                priority: AssetPriority.HIGHEST,\n                type: 'texture',\n            },\n        ])\n        public assets: AssetsCollection;\n\n        public get translatableAssets(): IAsset[] {\n            const variant = assetsVariant(this.gameWithDoubleChance);\n            return [\n                {\n                    id: 'extendedMultipleBuyBonusTranslate',\n                    url:\n                        '../assets/components/slot/buy-bonus/extended-multiple-buy-bonus/translations/' +\n                        Core.configuration.language.toLowerCase() +\n                        '.json',\n                    priority: AssetPriority.HIGHEST,\n                    type: 'translation',\n                },\n                ...getExtendedMultipleBuyBonusGameAssets(variant.translatable, variant.main),\n            ];\n        }\n\n        public haveConfirmationPopUp: boolean = false;\n        public addDoubleChanceToBonusList: boolean = true;\n        public gameWithDoubleChance: boolean = true;\n        public infinityByDefault: boolean = false;\n        public skipSameBets: boolean = true;\n\n        public onlyDoubleChance: boolean = Core.flags.isActive(FeatureFlags.HIDE_BUY_BONUS);\n        public tintColor: number = 0x797979;\n        public bannersHaveSelectedState: boolean = false;\n\n        public mergedBannersData: { shouldBeMerged: string; mergeIn: string }[] = [];\n\n        @DefaultValue<IBBBannerPoint>({\n            defaults: {\n                x: 816,\n                y: 94,\n                scale: 1,\n            },\n            portrait: {\n                x: 47,\n                y: 665,\n            },\n        })\n        public banner0Position: DynamicPositionObject<IBBBannerPoint> & IBBBannerPoint;\n\n        @DefaultValue<IBBBannerPoint>({\n            defaults: {\n                x: 544,\n                y: 94,\n                scale: 1,\n            },\n            portrait: {\n                x: 47,\n                y: 405,\n            },\n        })\n        public banner1Position: DynamicPositionObject<IBBBannerPoint> & IBBBannerPoint;\n\n        @DefaultValue<IBBBannerPoint>({\n            defaults: {\n                x: 272,\n                y: 94,\n                scale: 1,\n            },\n            portrait: {\n                x: 47,\n                y: 145,\n            },\n        })\n        public banner2Position: DynamicPositionObject<IBBBannerPoint> & IBBBannerPoint;\n\n        @DefaultValue<IBBBannerPoint>({\n            defaults: {\n                x: 42,\n                y: 986,\n                scale: 1,\n            },\n            portrait: {\n                x: 47,\n                y: 986,\n            },\n        })\n        public banner3Position: DynamicPositionObject<IBBBannerPoint> & IBBBannerPoint;\n\n        public bannerConfig: IBannerConfig[] = [];\n\n        @DefaultValue<IBuyBonusOverlaySettings>({\n            defaults: {\n                color: 0x000000,\n                opacity: 0.6,\n            },\n        })\n        public overlay: DynamicPositionObject<IBuyBonusOverlaySettings> & IBuyBonusOverlaySettings;\n\n        @DefaultValue<IBBBtnConfig>({\n            defaults: {\n                x: 150,\n                y: 400,\n                useOpacityForDisable: true,\n            },\n            portrait: {\n                x: 73,\n                y: 1168,\n            },\n        })\n        public buyBonusBtn: DynamicPositionObject<IBBBtnConfig> & IBBBtnConfig;\n\n        @DefaultValue<IBBBtnConfig>({\n            defaults: {\n                x: 150,\n                y: 400,\n                useOpacityForDisable: true,\n            },\n            portrait: {\n                x: 73,\n                y: 1168,\n            },\n        })\n        public doubleChanceBtn: DynamicPositionObject<IBBBtnConfig> & IBBBtnConfig;\n\n        @DefaultValue<IPopUpBackgroundPosition>({\n            defaults: {\n                x: 220,\n                y: 56,\n            },\n            portrait: {\n                x: 22,\n                y: 70,\n            },\n        })\n        public popUpBackground: DynamicPositionObject<IPopUpBackgroundPosition> & IPopUpBackgroundPosition;\n\n        @DefaultValue<IBBPopUpTitle>({\n            defaults: {\n                x: 488,\n                y: 18,\n                scale: 0.8,\n            },\n            portrait: {\n                x: 142,\n                y: 27,\n                scale: 1,\n            },\n        })\n        public popUpTitle: DynamicPositionObject<IBBPopUpTitle> & IBBPopUpTitle;\n\n        @DefaultValue<ICloseButtonPoint>({\n            defaults: {\n                scale: 1,\n                x: 525,\n                y: 633,\n            },\n            portrait: {\n                x: 217,\n                y: 1155,\n            },\n        })\n        public popUpBtnClose: DynamicPositionObject<ICloseButtonPoint> & ICloseButtonPoint;\n\n        @DefaultValue<IBBPoint>({\n            defaults: {\n                x: 835,\n                y: 633,\n            },\n            portrait: {\n                x: 547,\n                y: 1155,\n            },\n        })\n        public popUpConfirmBtn: DynamicPositionObject<IBBPoint> & IBBPoint;\n\n        @DefaultValue<IBBPoint>({\n            defaults: {\n                x: 525,\n                y: 633,\n            },\n            portrait: {\n                x: 217,\n                y: 1155,\n            },\n        })\n        public popUpInfinityConfirmBtn: DynamicPositionObject<IBBPoint> & IBBPoint;\n\n        @DefaultValue<IBBXBoundsPoint>({\n            defaults: {\n                x: 680,\n                y: 716,\n                maxWidth: 330,\n            },\n            portrait: {\n                x: 382.5,\n                y: 1023,\n            },\n        })\n        public betOutsideBetContainer: DynamicPositionObject<IBBXBoundsPoint> & IBBXBoundsPoint;\n\n        @DefaultValue<IBBXBoundsPoint>({\n            defaults: {\n                x: 680,\n                y: 737,\n                maxWidth: 330,\n            },\n            portrait: {\n                x: 382.5,\n                y: 1043,\n            },\n        })\n        public betOutsideBetInfo: DynamicPositionObject<IBBXBoundsPoint> & IBBXBoundsPoint;\n\n        @DefaultValue<IBannerInnerPositions>({\n            defaults: {\n                maxBetContainerX: 136,\n                maxBetContainerY: 258,\n                maxBetContainerScale: 0.8,\n                maxBetTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fill: '#ffffff',\n                    align: 'center',\n                    fontSize: 22,\n                }),\n                buyValueCurrencyMaxWidth: 200,\n                buyValueTextFontSize: 12,\n                buyValueTextLetterSpacing: 0,\n                buyValueCurrencyFontSize: 6,\n                buyValueCurrencyLetterSpacing: 0,\n                buyValueCurrencyY: 20,\n                valueTextsScale: 1,\n                valueContainerX: 134,\n                valueContainerY: 273,\n                descriptionTextX: 136,\n                descriptionTextY: 184,\n                descriptionTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPTCond-Bold, Arial, sans-serif',\n                    dropShadow: true,\n                    dropShadowAngle: 1.2,\n                    dropShadowBlur: 3,\n                    dropShadowDistance: 2,\n                    fill: '#ffedbb',\n                    stroke: '#2e2e2e',\n                    strokeThickness: 1,\n                    letterSpacing: 0.78,\n                    align: 'center',\n                    fontSize: 26,\n                    lineHeight: 26,\n                    wordWrap: true,\n                    wordWrapWidth: 234,\n                }),\n                wordSpacing: 10,\n                btnCloseXPosition: 306,\n                btnCloseYPosition: 145,\n                btnCloseScale: 1,\n                btnConfirmXPosition: 482,\n                btnConfirmYPosition: 145,\n                btnConfirmScale: 1,\n                haveDescriptionText: false,\n            },\n            portrait: {\n                maxBetContainerX: 472,\n                maxBetContainerY: 134,\n                maxBetContainerScale: 1,\n                buyValueCurrencyMaxWidth: 250,\n                valueContainerX: 490,\n                valueContainerY: 158,\n                descriptionTextX: 490,\n                descriptionTextY: 63,\n                descriptionTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPTCond-Bold, Arial, sans-serif',\n                    dropShadow: true,\n                    dropShadowAngle: 1.2,\n                    dropShadowBlur: 3,\n                    dropShadowDistance: 2,\n                    fill: '#ffedbb',\n                    stroke: '#2e2e2e',\n                    strokeThickness: 1,\n                    letterSpacing: 0.78,\n                    align: 'center',\n                    fontSize: 26,\n                    lineHeight: 26,\n                    wordWrap: true,\n                    wordWrapWidth: 320,\n                }),\n                wordSpacing: 10,\n            },\n        })\n        public bannerInnerPositions: DynamicPositionObject<IBannerInnerPositions> & IBannerInnerPositions;\n\n        @DefaultValue<IBetPanelPositions>({\n            defaults: {\n                x: 440,\n                y: 454,\n                scale: 0.8,\n                backgroundX: 0,\n                backgroundY: 0,\n                increaseBtnX: 378,\n                increaseBtnY: 62,\n                decreaseBtnX: 20,\n                decreaseBtnY: 62,\n                buyValueCurrencyX: 249,\n                buyValueCurrencyY: 24,\n                buyValueCurrencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fill: '#FFD200',\n                    fontSize: 22,\n                }),\n                buyValueTextX: 249,\n                buyValueTextY: 62,\n                buyValueTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fill: '#FFFFFF',\n                    fontSize: 52,\n                }),\n                buyValueBetX: 249,\n                buyValueBetY: 98,\n                betValueBetStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fill: '#FFD200',\n                    fontSize: 22,\n                }),\n                betValueMaxWidth: 260,\n            },\n            portrait: {\n                buyValueCurrencyY: 26,\n                scale: 1,\n                x: 142,\n                y: 956,\n            },\n        })\n        public betPanel: DynamicPositionObject<IBetPanelPositions> & IBetPanelPositions;\n\n        @DefaultValue<IDenominationContainer>({\n            defaults: {\n                scale: 1,\n                y: 964,\n                buttonsOffset: 15,\n                buttonsYPosition: 0,\n                denominationTextX: 190,\n                denominationTextY: 0,\n                denominationTextStyleInactive: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fill: '#C6C5C5',\n                    fontSize: 20,\n                    trim: true,\n                }),\n                denominationTextStyleActive: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fill: '#FDE126',\n                    fontSize: 20,\n                    trim: true,\n                }),\n                denominationBtnTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fill: '#C6C5C5',\n                    fontSize: 42,\n                    trim: true,\n                }),\n                denominationBtnTextStyleActive: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fill: '#FFFFFF',\n                    fontSize: 42,\n                    trim: true,\n                }),\n                denominationText: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fill: '#FFD200',\n                    fontSize: 16,\n                    trim: true,\n                    align: 'center',\n                }),\n            },\n            portrait: {\n                y: 964,\n            },\n        })\n        public denominationContainer: DynamicPositionObject<IDenominationContainer> & IDenominationContainer;\n\n        @DefaultValue<IBetOutsidePanelPositions>({\n            defaults: {\n                x: 500,\n                y: 662,\n                betOutsideDecreaseBtnX: 406,\n                betOutsideDecreaseBtnY: 710,\n                betOutsideIncreaseBtnX: 868,\n                betOutsideIncreaseBtnY: 710,\n                wordSpacing: 6,\n                betOutsideTotalBetValueStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fill: '#ffffff',\n                    align: 'left',\n                    fontSize: 58,\n                    trim: true,\n                }),\n                betOutsideTotalBetCurrencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fill: '#ffffff',\n                    align: 'left',\n                    fontSize: 24,\n                    trim: true,\n                }),\n                betOutsideBetInfoStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fill: '#FFD200',\n                    align: 'center',\n                    fontSize: 28,\n                    trim: true,\n                }),\n            },\n            portrait: {\n                x: 202.5,\n                y: 969,\n                betOutsideDecreaseBtnX: 108.5,\n                betOutsideDecreaseBtnY: 1017.5,\n                betOutsideIncreaseBtnX: 570.5,\n                betOutsideIncreaseBtnY: 1017.5,\n            },\n            desktop: {\n                betOutsideTotalBetValueStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fill: '#ffffff',\n                    align: 'left',\n                    fontSize: 58,\n                    trim: true,\n                    // padding: 1,\n                    strokeThickness: 1.5,\n                    stroke: 'rgba(255,255,255,0.01)',\n                }),\n            },\n        })\n        public betOutsidePanel: DynamicPositionObject<IBetOutsidePanelPositions> & IBetOutsidePanelPositions;\n\n        @DefaultValue<IInfoTextPositions>({\n            defaults: {\n                x: 680,\n                y: 840,\n                infoTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fontSize: 26,\n                    lineHeight: 34,\n                    fontWeight: 'bold',\n                    fill: '#FFFFFF',\n                    align: 'center',\n                }),\n                infoTextOffset: -2,\n                infoTextOffsetX: 0,\n                onLimitOffsetY: 42,\n            },\n            portrait: {\n                x: 380,\n                y: 835,\n            },\n        })\n        public infoText: DynamicPositionObject<IInfoTextPositions> & IInfoTextPositions;\n\n        @DefaultValue<IBalancePositions>({\n            defaults: {\n                scale: 1,\n                x: 674,\n                y: 721,\n                wordSpacing: 6,\n                balanceTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fill: '#FFD200',\n                    fontSize: 24,\n                    trim: true,\n                }),\n                balanceTextY: -3,\n                balanceValueStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fill: '#FFFFFF',\n                    fontSize: 34,\n                    trim: true,\n                }),\n                balanceCurrencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fill: '#FFFFFF',\n                    fontSize: 16,\n                    trim: true,\n                }),\n            },\n            portrait: {\n                x: 372,\n                y: 1249,\n                balanceTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fill: '#FFD200',\n                    fontSize: 30,\n                    trim: true,\n                }),\n                balanceValueStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fill: '#FFFFFF',\n                    fontSize: 44,\n                    trim: true,\n                }),\n                balanceCurrencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fill: '#FFFFFF',\n                    fontSize: 20,\n                    trim: true,\n                }),\n            },\n        })\n        public balancePositions: DynamicPositionObject<IBalancePositions> & IBalancePositions;\n\n        @DefaultValue<IToggleTextPositions>({\n            defaults: {\n                x: 396,\n                y: 410,\n                scale: 1,\n                toggleTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPTCond-Bold, Arial, sans-serif',\n                    fill: '#FFFFFF',\n                    fontSize: 40,\n                    letterSpacing: 1.2,\n                    stroke: '#000000',\n                    strokeThickness: 1,\n                }),\n            },\n            portrait: {\n                x: 120,\n                y: 912,\n                scale: 1,\n            },\n        })\n        public toggleContainer: DynamicPositionObject<IToggleTextPositions> & IToggleTextPositions;\n\n        @DefaultValue<IToggleTextPositions>({\n            defaults: {\n                x: 396,\n                y: 410,\n                scale: 1,\n                toggleTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPTCond-Bold, Arial, sans-serif',\n                    fill: '#FFFFFF',\n                    fontSize: 40,\n                    letterSpacing: 1.2,\n                    stroke: '#000000',\n                    strokeThickness: 1,\n                }),\n            },\n            portrait: {\n                x: 120,\n                y: 912,\n                scale: 1,\n            },\n        })\n        public guaranteedWinToggleContainer: DynamicPositionObject<IToggleTextPositions> & IToggleTextPositions;\n\n        protected getBannerPositions(bannerId: number): IBBBannerPoint {\n            switch (bannerId) {\n                case 1:\n                    return this.banner1Position;\n                case 2:\n                    return this.banner2Position;\n                case 3:\n                    return this.banner3Position;\n                default:\n                    return this.banner0Position;\n            }\n        }\n        public haveGuaranteedWinToggle: boolean = false;\n    }\n    return ExtendedMultipleBuyBonusConfigurationInternalClass;\n}\n","import Core, { AnalyticsDispatcher, BaseController, FeatureFlags, IErrorData, MoneyFormatter } from '@egt/core';\nimport {\n    BonusTypes,\n    CollectResponse,\n    FeatureController,\n    ISlotConfiguration,\n    InitialSettings,\n    MessBarTypes,\n    RootStore,\n    ServerState,\n    Subjects,\n    UIState,\n} from '@egt/slot';\n//import { inspect } from '@xstate/inspect';\nimport { merge } from 'rxjs';\nimport { skip, takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { Machine, interpret } from 'xstate';\nimport { IBuyBonusComponentConfigurationExtendedMultipleBuyBonus } from '../configuration/IBuyBonusComponentConfigurationExtendedMultipleBuyBonus';\nimport BannerData from '../data/BannerData';\nimport ExtendedMultipleBuyBonusContext from '../data/ExtendedMultipleBuyBonusContext';\nimport { IBannerConfig } from '../interfaces/InterfacesExtendedMultipleBuyBonus';\nimport BuyBonusViewExtendedMultipleBuyBonus from '../views/BuyBonusViewExtendedMultipleBuyBonus';\n\n@injectable()\nexport default class BuyBonusControllerExtendedMultipleBuyBonus extends BaseController {\n    public ready: () => Promise<void>;\n    public stateMachine;\n    private stateMachineService;\n\n    constructor(\n        @inject('BuyBonusView') protected view: BuyBonusViewExtendedMultipleBuyBonus,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('SlotSubjects') public readonly subjects: Subjects,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('FeatureController') protected featureController: FeatureController,\n        @inject('BuyBonusComponentConfiguration')\n        protected componentConfiguration: IBuyBonusComponentConfigurationExtendedMultipleBuyBonus,\n    ) {\n        super(view);\n    }\n\n    public onGameStarted(initialSettings?: any): void {\n        // if (this.componentConfiguration.addDoubleChanceToBonusList) {\n        //     this.settings.buyBonusOptions.unshift(this.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE'));\n        // }\n\n        this.createStateMachine();\n        const context: ExtendedMultipleBuyBonusContext = this.stateMachine.context;\n\n        if (context.bannersData.length === 0) {\n            return;\n        }\n        if (\n            initialSettings &&\n            initialSettings.game?.state?.bet?.gameMode === 'DOUBLE_CHANCE' &&\n            initialSettings.state !== ServerState.BONUS_IDLE &&\n            initialSettings.state !== ServerState.GAMBLE &&\n            !Core.flags.isActive(FeatureFlags.HIDE_DOUBLE_CHANCE)\n        ) {\n            const bannerConfig: BannerData = context.getBannerDataByGameMode('DOUBLE_CHANCE');\n            context.activeBannerId = bannerConfig.bannerId;\n            this.stateMachineService.send('RECOVERY');\n        }\n\n        this.view.init(\n            context.bannersData,\n            context.availableBets[context.currentBetIndex].bet,\n            context.availableBets[context.currentBetIndex].denomination,\n            context.availableDenominations,\n        );\n\n        this.attachListeners();\n\n        if (!this.shouldDisplayBuyBtn(initialSettings)) {\n            this.view.hideBuyBtn();\n        }\n        if (this.componentConfiguration.infinityByDefault) {\n            this.stateMachineService.send('ON_TOGGLE_CLICKED');\n        }\n    }\n\n    private updateDenominations(): void {\n        if (this.settings.maxBet) {\n            this.rootStore.uiStore.denominations = this.settings.denominations;\n            this.rootStore.uiStore.bets = this.settings.bets;\n            this.subjects.DENOMINATIONS_CHANGED.next();\n        }\n    }\n\n    private attachListeners(): void {\n        this.subjects.CLOSE_BUY_BONUS_POPUP.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.stateMachineService.send('CLOSE_POPUP');\n        });\n        this.subjects.EXTENDED_MULTIPLE_BUY_BONUS_BTN_VISIBLE.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.changeBuyBtnVisibility.bind(this),\n        );\n        this.subjects.EXTENDED_MULTIPLE_BUY_BONUS_OUTSIDE_BETS_VISIBLE.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.changeBuyOutsidePanelVisibility.bind(this),\n        );\n        this.subjects.DISABLED_BUY_BONUS.pipe(takeUntil(this.DESTROY)).subscribe(this.disableBuyBonus.bind(this));\n        this.subjects.DOUBLE_CHANCE_ACTIVATED.pipe(skip(1), takeUntil(this.DESTROY)).subscribe((e) => {\n            if (e) {\n                //this.stateMachineService.send('DOUBLE_CHANCE_CLICKED');\n                this.stateMachineService.send('ON_ACTIVATE_DC_FROM_OUTSIDE');\n            } else {\n                this.stateMachineService.send('ON_DEACTIVATE_DC_FROM_OUTSIDE');\n            }\n        });\n        this.rootStore.uiStore.STATE.pipe(takeUntil(this.DESTROY)).subscribe(this.onStateChanged.bind(this));\n        this.rootStore.subjects.BEFORE_SPIN.pipe(takeUntil(this.DESTROY)).subscribe(this.onBeforeSpin.bind(this));\n        this.rootStore.subjects.OPEN_SETTINGS_POPUP.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onSettingsPopUpOpened.bind(this),\n        );\n        this.rootStore.domainStore.COLLECT_RESPONSE.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onCollectClicked.bind(this),\n        );\n        this.rootStore.subjects.KEY_UP.pipe(takeUntil(this.DESTROY)).subscribe(this.onKeyReleased.bind(this));\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.onOrientationChanged.bind(this));\n        this.rootStore.uiStore.BALANCE.pipe(takeUntil(this.DESTROY)).subscribe(this.onBalanceChanged.bind(this));\n\n        const betChangeEvents = merge(\n            this.rootStore.uiStore.SELECTED_BET,\n            this.rootStore.subjects.SETTINGS_BET_CHANGED,\n            this.rootStore.subjects.SETTINGS_DENOMINATION_CHANGED,\n            this.rootStore.uiStore.LINES,\n        );\n        betChangeEvents.pipe(takeUntil(this.DESTROY)).subscribe(this.onBetChanged.bind(this));\n\n        Core.SELECTED_DENOMINATION.pipe(takeUntil(this.DESTROY)).subscribe(this.onDenominationChanged.bind(this));\n\n        this.rootStore.subjects.MAX_WIN_LIMIT_MESSAGE.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onLimitHit.bind(this),\n        );\n        Core.SHOW_ERROR.pipe(takeUntil(this.DESTROY)).subscribe(this.onErrorWithInsifitionsFunds.bind(this));\n    }\n\n    private onCollectClicked(response: CollectResponse): void {\n        if (response.state !== 'bonusIdle' && this.stateMachine.context.collectRequested) {\n            if (response.state === UIState.IDLE && this.rootStore.uiStore.STATE.value === UIState.DISABLED) {\n                this.rootStore.uiStore.STATE.next(UIState.IDLE);\n            }\n            if (this.componentConfiguration.onlyDoubleChance) {\n                this.stateMachineService.send('DOUBLE_CHANCE_CLICKED');\n            } else {\n                this.stateMachineService.send('BUY_BONUS_BTN_CLICKED');\n            }\n        }\n        this.stateMachine.context.collectRequested = false;\n    }\n\n    private onLimitHit(): void {\n        this.view.updateInfoTextOffset(\n            this.rootStore.subjects.MAX_WIN_LIMIT_MESSAGE.value\n                ? this.componentConfiguration.infoText.onLimitOffsetY\n                : 0,\n        );\n    }\n\n    private onBeforeSpin(): void {\n        this.stateMachineService.send('ON_HIDE_INFO_TEXT');\n        this.stateMachineService.send('ON_NEW_SPIN');\n    }\n\n    private onDenominationChanged(): void {\n        this.stateMachine.context.denominationValue = Core.SELECTED_DENOMINATION.value;\n        if (!this.componentConfiguration.skipSameBets) {\n            this.actionSetAvailableBets(this.stateMachine.context);\n        }\n        this.onBetChanged();\n    }\n\n    private onBetChanged(): void {\n        const context: ExtendedMultipleBuyBonusContext = this.stateMachine.context;\n        context.betValue = this.rootStore.uiStore.SELECTED_BET.value;\n        context.denominationValue = Core.SELECTED_DENOMINATION.value;\n        this.stateMachineService.send('UPDATE_OUTSIDE_BETS_EXTERNALLY');\n        if (\n            this.componentConfiguration.onlyDoubleChance &&\n            context.betValue * context.denominationValue * this.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE') >\n                this.settings.maxBet * 100\n        ) {\n            this.view.disabled();\n        }\n    }\n\n    private onSettingsPopUpOpened(): void {\n        this.stateMachineService.send('CLOSE_POPUP');\n    }\n\n    private createStateMachine(): void {\n        const actionSetFactorsById = this.actionSetFactorsById.bind(this);\n        const actionSetAvailableBets = this.actionSetAvailableBets.bind(this);\n        const actionGetLocalStorageData = this.actionGetLocalStorageData.bind(this);\n        const actionOpenPopUp = this.actionOpenPopUp.bind(this);\n        const actionClosePopUp = this.actionClosePopUp.bind(this);\n        const actionOpenConfirmationPopUp = this.actionOpenConfirmationPopUp.bind(this);\n        const actionCloseConfirmationPopUp = this.actionCloseConfirmationPopUp.bind(this);\n        const actionChangeDenomAndBet = this.actionChangeDenomAndBet.bind(this);\n        const actionActivated = this.actionActivated.bind(this);\n        const actionReady = this.actionReady.bind(this);\n        const actionIncreaseBet = this.actionIncreaseBet.bind(this);\n        const actionDecreaseBet = this.actionDecreaseBet.bind(this);\n        const actionShowBuyBtn = this.actionShowBuyBtn.bind(this);\n        const actionHideBuyBtn = this.actionHideBuyBtn.bind(this);\n        const actionShowOutsidePanel = this.actionShowOutsidePanel.bind(this);\n        const actionHideOutsidePanel = this.actionHideOutsidePanel.bind(this);\n        const actionDisabledBuyBonus = this.actionDisabledBuyBonus.bind(this);\n        const actionEnableBuyBonus = this.actionEnableBuyBonus.bind(this);\n        const actionRestoreFactor = this.actionRestoreFactor.bind(this);\n        const actionUpdateBetPanelControls = this.actionUpdateBetPanelControls.bind(this);\n        const actionGetCurrentBetIndex = this.actionGetCurrentBetIndex.bind(this);\n        const actionConfirmationPopUpCheckBoxClicked = this.actionConfirmationPopUpCheckBoxClicked.bind(this);\n        const actionUpdateOutsideBets = this.actionUpdateOutsideBets.bind(this);\n        const actionUpdateOutsideBetPanelControls = this.actionUpdateOutsideBetPanelControls.bind(this);\n        const actionOutsideIncreaseBtn = this.actionOutsideIncreaseBtn.bind(this);\n        const actionOutsideDecreaseBtn = this.actionOutsideDecreaseBtn.bind(this);\n        const actionShowInfoText = this.actionShowInfoText.bind(this);\n        const actionHideInfoText = this.actionHideInfoText.bind(this);\n        const actionBonusSelected = this.actionBonusSelected.bind(this);\n        const actionForceInsufficientFundMessage = this.actionForceInsufficientFundMessage.bind(this);\n        const actionDoubleChanceChangeState = this.actionDoubleChanceChangeState.bind(this);\n        const actionActivateDoubleChanceFromPopUp = this.actionActivateDoubleChanceFromPopUp.bind(this);\n        const actionDeactivateDoubleChance = this.actionDeactivateDoubleChance.bind(this);\n        // const actionSetActivationType = this.actionSetActivationType.bind(this);\n        const actionOnNewSpin = this.actionOnNewSpin.bind(this);\n        const actionDeactivate = this.actionDeactivate.bind(this);\n        const actionOnToggleClicked = this.actionOnToggleClicked.bind(this);\n        const actionOnGuaranteedWinToggleClicked = this.actionOnGuaranteedWinToggleClicked.bind(this);\n        const actionUpdateBetsWhenGuaranteedWin = this.actionUpdateBetsWhenGuaranteedWin.bind(this);\n        const actionOnRecovery = this.actionOnRecovery.bind(this);\n        const actionCollect = this.actionCollect.bind(this);\n        const actionChangeDenomination = this.actionChangeDenomination.bind(this);\n        const actionOnPopUpClosed = this.actionOnPopUpClosed.bind(this);\n        const activateFromOutside = this.activateFromOutside.bind(this);\n        const deactivateFromOutside = this.deactivateFromOutside.bind(this);\n        const actionPlaySliderSounds = this.actionPlaySliderSounds.bind(this);\n        const haveConfirmationPopUp = this.haveConfirmationPopUp.bind(this);\n        const isEnabled = this.isEnabled.bind(this);\n        const canEnableBuyBonus = this.canEnableBuyBonus.bind(this);\n        const shouldDeactivate = this.shouldDeactivate.bind(this);\n        const shouldForceDeactivate = this.shouldForceDeactivate.bind(this);\n\n        this.stateMachine = Machine(\n            {\n                id: 'extendedMultipleBuyBonus',\n                context: new ExtendedMultipleBuyBonusContext(),\n                initial: 'init',\n                on: {\n                    ON_SHOW_BB_BTN: {\n                        actions: ['actionShowBuyBtn'],\n                    },\n                    ON_HIDE_BB_BTN: {\n                        actions: ['actionHideBuyBtn'],\n                    },\n                    ON_SHOW_OUTSIDE_PANEL: {\n                        actions: ['actionShowOutsidePanel'],\n                    },\n                    ON_HIDE_OUTSIDE_PANEL: {\n                        actions: ['actionHideOutsidePanel'],\n                    },\n                    ON_SHOW_INFO_TEXT: {\n                        actions: ['actionShowInfoText'],\n                    },\n                    ON_HIDE_INFO_TEXT: {\n                        actions: ['actionHideInfoText'],\n                    },\n                    ON_TOGGLE_CLICKED: {\n                        actions: ['actionOnToggleClicked'],\n                    },\n                    ON_ACTIVATE_DC_FROM_OUTSIDE: {\n                        actions: ['activateFromOutside'],\n                        target: 'activated',\n                    },\n                    ON_DEACTIVATE_DC_FROM_OUTSIDE: {\n                        actions: ['deactivateFromOutside'],\n                        target: 'ready',\n                    },\n                    ON_GUARANTEED_TOGGLE_CLICKED: {\n                        actions: ['actionOnGuaranteedWinToggleClicked', 'actionUpdateBetsWhenGuaranteedWin'],\n                    },\n                    ON_UPDATE_BALANCE: {\n                        actions: ['actionUpdateBetsWhenGuaranteedWin'],\n                    },\n                    COLLECT_BEFORE_OPEN: {\n                        actions: ['actionCollect'],\n                    },\n                    COLLECT_BEFORE_ACTIVATE_DOUBLE_CHANCE: {\n                        actions: ['actionCollect'],\n                    },\n                    CHANGE_DENOMINATION: {\n                        actions: ['actionChangeDenomination', 'actionUpdateBetPanelControls'],\n                    },\n                    POP_UP_CLOSED: {\n                        actions: ['actionOnPopUpClosed'],\n                    },\n                },\n                states: {\n                    init: {\n                        entry: ['actionSetFactorsById', 'actionSetAvailableBets', 'actionGetLocalStorageData'],\n                        on: {\n                            INIT_COMPLETE: {\n                                target: 'ready',\n                            },\n                            RECOVERY: {\n                                target: 'recovery',\n                            },\n                        },\n                    },\n                    recovery: {\n                        on: {\n                            INIT_COMPLETE: {\n                                actions: ['actionOnRecovery'],\n                                target: 'activated',\n                            },\n                        },\n                    },\n                    ready: {\n                        on: {\n                            BUY_BONUS_BTN_CLICKED: {\n                                actions: [\n                                    'actionGetCurrentBetIndex',\n                                    'actionPlaySliderSounds',\n                                    'actionOpenPopUp',\n                                    'actionUpdateBetPanelControls',\n                                ],\n                                target: 'popUpOpened',\n                                cond: 'isEnabled',\n                            },\n                            DOUBLE_CHANCE_CLICKED: {\n                                actions: ['actionDoubleChanceChangeState'],\n                            },\n                            DISABLE_BUY_BONUS: {\n                                actions: ['actionDisabledBuyBonus'],\n                            },\n                            ENABLE_BUY_BONUS: {\n                                actions: ['actionEnableBuyBonus'],\n                                cond: 'canEnableBuyBonus',\n                            },\n                        },\n                    },\n                    popUpOpened: {\n                        on: {\n                            CLOSE_POPUP: {\n                                actions: ['actionClosePopUp'],\n                                target: 'ready',\n                            },\n                            BONUS_SELECTED: {\n                                actions: ['actionBonusSelected'],\n                            },\n                            // SET_BONUS_ACTIVATION_TYPE: {\n                            //     actions: ['actionSetActivationType'],\n                            // },\n                            BONUS_CHOSEN: [\n                                {\n                                    actions: ['actionClosePopUp', 'actionOpenConfirmationPopUp'],\n                                    target: 'conformationPopupOpened',\n                                    cond: 'haveConfirmationPopUp',\n                                },\n                                {\n                                    actions: [\n                                        'actionDeactivateDoubleChance',\n                                        'actionClosePopUp',\n                                        'actionChangeDenomAndBet',\n                                        'actionForceInsufficientFundMessage',\n                                        'actionActivated',\n                                        'actionShowInfoText',\n                                    ],\n                                    target: 'activated',\n                                },\n                            ],\n                            INCREASE_BET: {\n                                actions: ['actionIncreaseBet', 'actionUpdateBetPanelControls'],\n                            },\n                            DECREASE_BET: {\n                                actions: ['actionDecreaseBet', 'actionUpdateBetPanelControls'],\n                            },\n                            DOUBLE_CHANCE_CLICKED: {\n                                actions: [\n                                    'actionDoubleChanceChangeState',\n                                    'actionClosePopUp',\n                                    'actionChangeDenomAndBet',\n                                    'actionForceInsufficientFundMessage',\n                                    'actionActivateDoubleChanceFromPopUp',\n                                ],\n                                target: 'activated',\n                            },\n                        },\n                    },\n                    conformationPopupOpened: {\n                        on: {\n                            CONFIRMATION_POPUP_CLOSE: {\n                                actions: ['actionCloseConfirmationPopUp'],\n                                target: 'ready',\n                            },\n                            CONFIRMATION_POPUP_BACK: {\n                                actions: ['actionCloseConfirmationPopUp', 'actionOpenPopUp'],\n                                target: 'popUpOpened',\n                            },\n                            CONFIRMATION_POPUP_CONFIRM: {\n                                actions: [\n                                    'actionCloseConfirmationPopUp',\n                                    'actionChangeDenomAndBet',\n                                    'actionForceInsufficientFundMessage',\n                                    'actionActivated',\n                                    'actionShowInfoText',\n                                ],\n                                target: 'activated',\n                            },\n                            CONFIRMATION_CHECK_BOX_CLICKED: {\n                                actions: ['actionConfirmationPopUpCheckBoxClicked'],\n                            },\n                        },\n                    },\n                    activated: {\n                        entry: ['actionUpdateOutsideBets', 'actionUpdateOutsideBetPanelControls'],\n                        on: {\n                            ON_DEACTIVATE_DC_FROM_OUTSIDE: {\n                                actions: ['deactivateFromOutside'],\n                                target: 'ready',\n                            },\n                            BUY_BONUS_BTN_CLICKED: {\n                                actions: [\n                                    'actionPlaySliderSounds',\n                                    'actionReady',\n                                    'actionGetCurrentBetIndex',\n                                    // 'actionOpenPopUp',\n                                    'actionUpdateBetPanelControls',\n                                    'actionHideInfoText',\n                                ],\n                                target: 'ready',\n                                cond: 'isEnabled',\n                            },\n                            DOUBLE_CHANCE_CLICKED: {\n                                actions: ['actionDoubleChanceChangeState'],\n                                target: 'ready',\n                            },\n                            DISABLE_BUY_BONUS: {\n                                actions: ['actionDisabledBuyBonus'],\n                            },\n                            ENABLE_BUY_BONUS: {\n                                actions: ['actionRestoreFactor', 'actionEnableBuyBonus'],\n                                cond: 'canEnableBuyBonus',\n                            },\n                            OUTSIDE_INCREASE_BTN_CLICKED: {\n                                actions: [\n                                    'actionForceInsufficientFundMessage',\n                                    'actionOutsideIncreaseBtn',\n                                    'actionUpdateOutsideBets',\n                                    'actionUpdateOutsideBetPanelControls',\n                                    'actionChangeDenomAndBet',\n                                ],\n                            },\n                            OUTSIDE_DECREASE_BTN_CLICKED: {\n                                actions: [\n                                    'actionForceInsufficientFundMessage',\n                                    'actionOutsideDecreaseBtn',\n                                    'actionUpdateOutsideBets',\n                                    'actionUpdateOutsideBetPanelControls',\n                                    'actionChangeDenomAndBet',\n                                ],\n                            },\n                            ON_HIDE_INFO_TEXT: {\n                                actions: ['actionHideInfoText'],\n                            },\n                            ON_SHOW_OUTSIDE_PANEL: {\n                                actions: ['actionShowOutsidePanel'],\n                            },\n                            ON_HIDE_OUTSIDE_PANEL: {\n                                actions: ['actionHideOutsidePanel'],\n                            },\n                            UPDATE_OUTSIDE_BETS_EXTERNALLY: {\n                                actions: [\n                                    'actionGetCurrentBetIndex',\n                                    'actionUpdateOutsideBets',\n                                    'actionUpdateOutsideBetPanelControls',\n                                ],\n                            },\n                            ON_NEW_SPIN: {\n                                actions: ['actionOnNewSpin'],\n                            },\n                            ON_NEW_SPIN_START: {\n                                actions: ['actionDeactivate'],\n                                target: 'ready',\n                                cond: 'shouldDeactivate',\n                            },\n                            CHECK_FOR_DEACTIVATE_AFTER_REEL_STOP: {\n                                actions: ['actionDeactivate'],\n                                target: 'ready',\n                                cond: 'shouldDeactivate',\n                            },\n                            FORCE_DEACTIVATE: {\n                                actions: ['actionDeactivate'],\n                                target: 'ready',\n                                cond: 'shouldForceDeactivate',\n                            },\n                        },\n                    },\n                },\n            },\n            {\n                actions: {\n                    actionPlaySliderSounds,\n                    actionSetAvailableBets,\n                    actionSetFactorsById,\n                    actionGetLocalStorageData,\n                    actionOpenPopUp,\n                    actionClosePopUp,\n                    actionOnPopUpClosed,\n                    actionOpenConfirmationPopUp,\n                    actionCloseConfirmationPopUp,\n                    actionActivated,\n                    actionChangeDenomAndBet,\n                    actionReady,\n                    actionIncreaseBet,\n                    actionDecreaseBet,\n                    actionShowBuyBtn,\n                    actionHideBuyBtn,\n                    actionShowOutsidePanel,\n                    actionHideOutsidePanel,\n                    actionDisabledBuyBonus,\n                    actionEnableBuyBonus,\n                    actionRestoreFactor,\n                    actionUpdateBetPanelControls,\n                    actionGetCurrentBetIndex,\n                    actionConfirmationPopUpCheckBoxClicked,\n                    actionUpdateOutsideBets,\n                    actionUpdateOutsideBetPanelControls,\n                    actionOutsideIncreaseBtn,\n                    actionOutsideDecreaseBtn,\n                    actionShowInfoText,\n                    actionHideInfoText,\n                    actionBonusSelected,\n                    actionOnRecovery,\n                    actionForceInsufficientFundMessage,\n                    actionDoubleChanceChangeState,\n                    actionActivateDoubleChanceFromPopUp,\n                    actionDeactivateDoubleChance,\n                    activateFromOutside,\n                    deactivateFromOutside,\n                    // actionSetActivationType,\n                    actionOnNewSpin,\n                    actionDeactivate,\n                    actionOnToggleClicked,\n                    actionOnGuaranteedWinToggleClicked,\n                    actionUpdateBetsWhenGuaranteedWin,\n                    actionCollect,\n                    actionChangeDenomination,\n                },\n                guards: {\n                    haveConfirmationPopUp,\n                    isEnabled,\n                    canEnableBuyBonus,\n                    shouldDeactivate,\n                    shouldForceDeactivate,\n                },\n            },\n        );\n        this.stateMachineService = interpret(this.stateMachine, { devTools: Core.configuration.devTools }).start();\n        this.view.stateMachineService = this.stateMachineService;\n    }\n\n    private changeBuyBtnVisibility(visible: boolean): void {\n        if (visible) {\n            this.stateMachineService.send('ON_SHOW_BB_BTN');\n        } else {\n            this.stateMachineService.send('ON_HIDE_BB_BTN');\n        }\n    }\n    private changeBuyOutsidePanelVisibility(visible: boolean): void {\n        if (visible) {\n            this.stateMachineService.send('ON_SHOW_OUTSIDE_PANEL');\n        } else {\n            this.stateMachineService.send('ON_HIDE_OUTSIDE_PANEL');\n        }\n    }\n\n    private activateFromOutside(context): void {\n        const bannerData: BannerData[] = context.bannersData;\n        bannerData.forEach((data) => {\n            if (data.gameMode === 'DOUBLE_CHANCE') {\n                context.activated = false;\n                context.activeBannerId = data.bannerId;\n                context.activationType = 'doubleChance';\n                context.doubleChanceEnabled = true;\n\n                this.view.activateDoubleChance();\n                this.view.showActivated(data, false);\n                context.disabled = true;\n            }\n        });\n    }\n\n    private deactivateFromOutside(context): void {\n        context.activated = false;\n        context.activeBannerId = 0;\n        context.activationType = '';\n        context.doubleChanceEnabled = false;\n        this.actionDeactivateDoubleChance(context);\n        this.view.showReady();\n    }\n\n    private disableBuyBonus(): void {\n        const context: ExtendedMultipleBuyBonusContext = this.stateMachine.context;\n        if (\n            this.subjects.DISABLED_BUY_BONUS.value.disabled ||\n            (this.componentConfiguration.onlyDoubleChance &&\n                context.betValue *\n                    context.denominationValue *\n                    this.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE') >\n                    this.settings.maxBet * 100)\n        ) {\n            this.stateMachineService.send({\n                type: 'DISABLE_BUY_BONUS',\n                doNotChangeVisible: this.subjects.DISABLED_BUY_BONUS.value.doNotChangeVisual,\n            });\n        } else {\n            this.stateMachineService.send('ENABLE_BUY_BONUS');\n            this.infoMessageShouldBeVisible();\n        }\n    }\n\n    private onOrientationChanged(): void {\n        this.infoMessageShouldBeVisible();\n    }\n\n    private onBalanceChanged(): void {\n        this.stateMachineService.send('ON_UPDATE_BALANCE');\n    }\n\n    private infoMessageShouldBeVisible(): void {\n        if (\n            this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value &&\n            (this.rootStore.uiStore.STATE.value === UIState.IDLE ||\n                this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT)\n        ) {\n            this.stateMachineService.send('ON_SHOW_INFO_TEXT');\n        } else {\n            this.stateMachineService.send('ON_HIDE_INFO_TEXT');\n        }\n    }\n\n    private onStateChanged(): void {\n        if (\n            this.rootStore.uiStore.STATE.value === UIState.IDLE ||\n            this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT\n        ) {\n            this.stateMachineService.send('ENABLE_BUY_BONUS');\n            this.stateMachineService.send('CHECK_FOR_DEACTIVATE_AFTER_REEL_STOP');\n            this.infoMessageShouldBeVisible();\n        } else {\n            this.stateMachineService.send({\n                type: 'DISABLE_BUY_BONUS',\n                doNotChangeVisible: this.rootStore.uiStore.STATE.value === UIState.DISABLED ? true : false,\n            });\n            if (\n                this.rootStore.domainStore.betResponse &&\n                this.rootStore.domainStore.betResponse?.state !== ServerState.IDLE &&\n                this.rootStore.uiStore.STATE.value !== UIState.WAITING_FOR_COLLECT_IN_AUTOPLAY &&\n                this.rootStore.uiStore.STATE.value !== UIState.WAITING_FOR_RESPONSE &&\n                this.rootStore.uiStore.STATE.value !== UIState.WAITING_FOR_RESPONSE_IN_AUTOPLAY &&\n                this.rootStore.uiStore.STATE.value !== UIState.WIN &&\n                (this.stateMachine.context as ExtendedMultipleBuyBonusContext).activationType !== 'doubleChance'\n            ) {\n                this.settings.factor = this.settings.getFactorByUniqueGameMode('NORMAL_MODE');\n                this.settings.gameMode = 'NORMAL_MODE';\n            }\n        }\n\n        if (this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value) {\n            const statesToHideBtnText = [UIState.WAITING_FOR_RESPONSE, UIState.FREESPIN, UIState.MYSTERY];\n            const spinButtonTextVisible =\n                //@ts-ignore\n                statesToHideBtnText.indexOf(this.rootStore.uiStore.STATE.value) !== -1 ? false : true;\n            this.subjects.SPIN_BUTTON_SPECIAL_TEXT_VISIBLE.next(spinButtonTextVisible);\n        }\n    }\n\n    private actionSetAvailableBets(context: ExtendedMultipleBuyBonusContext): void {\n        if (this.settings.settings.settings.buyBonus?.denominations) {\n            const bbDenomValues: number[] = [];\n            for (const denom of this.settings.settings.settings.buyBonus.denominations) {\n                if (denom > this.settings.settings.settings.denominations.length) continue;\n                bbDenomValues.push(this.settings.settings.settings.denominations[denom - 1]);\n            }\n            context.availableDenominations = bbDenomValues;\n        } else {\n            context.availableDenominations = this.settings.settings.settings.denominations;\n        }\n\n        const factor = this.settings.settings.settings.factor;\n        const bets: Array<{ betMoney: number; bet: number; denomination: number; baseFactor: number }> = [];\n        let count: number = 0;\n\n        const denominations: number = this.componentConfiguration.skipSameBets\n            ? context.availableDenominations.length\n            : 1;\n\n        for (let i: number = 0; i < denominations; i++) {\n            const denom: number = this.componentConfiguration.skipSameBets\n                ? i\n                : this.rootStore.settings.denominations.indexOf(context.denominationValue);\n            for (const bet of this.settings.settings.settings.bets) {\n                if (\n                    bet === this.settings.settings.settings.bet &&\n                    this.settings.settings.settings.denominations[denom] ===\n                        this.settings.settings.settings.denomination\n                ) {\n                    context.currentBetIndex = count;\n                }\n                bets.push({\n                    betMoney: factor * bet * this.settings.settings.settings.denominations[denom],\n                    bet,\n                    denomination: this.settings.settings.settings.denominations[denom],\n                    baseFactor: factor,\n                });\n                count++;\n            }\n        }\n        // remove duplicated bets and sort them\n        if (this.componentConfiguration.skipSameBets) {\n            const currentBetMoney = bets[context.currentBetIndex].betMoney;\n\n            context.availableBets = bets\n                .filter((bet, index, self) => index === self.findIndex((t) => t.betMoney === bet.betMoney))\n                .sort((a, b) => a.betMoney - b.betMoney);\n\n            const newBetIndex = context.availableBets.findIndex((bet) => bet.betMoney === currentBetMoney);\n            context.currentBetIndex = newBetIndex !== -1 ? newBetIndex : 0;\n        } else {\n            // without sorting\n\n            // sort from smaller to biggest bet\n            context.availableBets = bets.sort((a, b) => a.betMoney - b.betMoney);\n        }\n\n        const maxJurisdictionalBet = this.rootStore.settings.maxBet\n            ? this.rootStore.settings.maxBet * this.settings.units\n            : Infinity;\n        context.availableBets = context.availableBets.filter((bet) => !(bet.betMoney > maxJurisdictionalBet));\n        if (context.currentBetIndex > context.availableBets.length - 1) {\n            context.currentBetIndex = context.availableBets.length - 1;\n        }\n\n        for (const bannerData of context.bannersData) {\n            bannerData.maxBetBannerValue = this.getMaxBannerValue(\n                context.availableBets,\n                bannerData.bonusFactor,\n                bannerData.maxBet,\n            );\n            bannerData.insufficientFundsBannerValue = this.getMaxBannerValue(\n                context.availableBets,\n                bannerData.bonusFactor,\n                this.rootStore.uiStore.BALANCE.value,\n            );\n            if (bannerData.secondBonusFactor) {\n                bannerData.secondFactorMaxBetBannerValue = this.getMaxBannerValue(\n                    context.availableBets,\n                    bannerData.secondBonusFactor,\n                    bannerData.maxBet,\n                );\n                bannerData.secondFactorInsufficientFundsBannerValue = this.getMaxBannerValue(\n                    context.availableBets,\n                    this.rootStore.uiStore.BALANCE.value,\n                    bannerData.secondBonusFactor,\n                );\n            }\n        }\n    }\n\n    // mapping between factors comes from server and banners configuration\n    private actionSetFactorsById(context: ExtendedMultipleBuyBonusContext): void {\n        const mergeBannersData: { shouldBeMerged: string; mergeIn: string; bonusFactor: number }[] = [];\n        const haveBuyBonus: boolean = !Core.flags.isActive(FeatureFlags.HIDE_BUY_BONUS);\n        const haveDoubleChance: boolean = !Core.flags.isActive(FeatureFlags.HIDE_DOUBLE_CHANCE);\n        for (let i: number = 0; i < this.settings.gameModes.length; i++) {\n            if (\n                (this.settings.gameModes[i].gameMode !== 'NORMAL_MODE' &&\n                    this.settings.gameModes[i].gameMode !== 'DOUBLE_CHANCE' &&\n                    haveBuyBonus) ||\n                (this.componentConfiguration.addDoubleChanceToBonusList &&\n                    haveDoubleChance &&\n                    this.settings.gameModes[i].gameMode === 'DOUBLE_CHANCE')\n            ) {\n                const mergedData = this.componentConfiguration.mergedBannersData.filter(\n                    (mergedData) => mergedData.shouldBeMerged === this.settings.gameModes[i].gameMode,\n                );\n                const bannerConfig = this.getBannerConfigByGameMode(this.settings.gameModes[i].gameMode);\n                if (mergedData.length === 0) {\n                    const bannerData = new BannerData();\n                    bannerData.bannerId = bannerConfig.bannerId;\n                    bannerData.bannerDescriptionText = bannerConfig.bannerDescriptionText;\n                    bannerData.activeText = bannerConfig.activatedText;\n                    bannerData.betText = bannerConfig.betText;\n                    bannerData.spinBtnText = bannerConfig.spinBtnText;\n                    bannerData.shouldBuy = bannerConfig.shouldBuy;\n                    bannerData.bonusFactor = this.settings.gameModes[i].factor;\n                    bannerData.gameMode = this.settings.gameModes[i].gameMode;\n                    bannerData.denomPopUpTitleText = bannerConfig.denomPopUpTitleText;\n                    bannerData.betSettingsTitleText = bannerConfig.betSettingsTitleText;\n                    bannerData.maxBet = this.getMaxBet(bannerData.bonusFactor, bannerData.gameMode);\n                    bannerData.deactivateOnReelStoppedWhenBuyOnce = bannerConfig.deactivateOnReelStoppedWhenBuyOnce;\n                    // bannerData.maxBetBannerBetValue = this.getMaxBetBannerBetValue(context.availableBets, bannerData.bonusFactor, bannerData.maxBet);\n                    context.bannersData.push(bannerData);\n                } else {\n                    mergeBannersData.push({\n                        shouldBeMerged: mergedData[0].shouldBeMerged,\n                        mergeIn: mergedData[0].mergeIn,\n                        bonusFactor: this.settings.gameModes[i].factor,\n                    });\n                }\n            }\n        }\n\n        for (const mergedBannerData of mergeBannersData) {\n            const mergeInBannerData = context.getBannerDataByGameMode(mergedBannerData.mergeIn);\n            mergeInBannerData.secondGameMode = mergedBannerData.shouldBeMerged;\n            mergeInBannerData.secondBonusFactor = mergedBannerData.bonusFactor;\n        }\n        context.bannersData.sort((a, b) => a.bannerId - b.bannerId);\n    }\n\n    private getBannerConfigByGameMode(gameMode: string): IBannerConfig {\n        return this.componentConfiguration.bannerConfig.find((config) => config.gameMode === gameMode) as IBannerConfig;\n    }\n\n    private getMaxBet(_factor: number, gameMode: string): number {\n        const maxBetLimits = this.settings.settings.settings.clientSettings?.maxBetLimits?.hasOwnProperty(\n            this.settings.currency,\n        )\n            ? this.settings.settings.settings.clientSettings.maxBetLimits[this.settings.currency]\n            : undefined;\n        const maxBet = maxBetLimits && gameMode !== 'DOUBLE_CHANCE' ? maxBetLimits * this.settings.units : Infinity;\n        const maxJurisdictionalBet = this.rootStore.settings.maxBet\n            ? this.rootStore.settings.maxBet * this.settings.units\n            : Infinity;\n\n        return Math.min(maxBet, maxJurisdictionalBet);\n    }\n\n    private getMaxBannerValue(\n        availableBets: Array<{ betMoney: number; bet: number; denomination: number; baseFactor: number }>,\n        factor: number,\n        maxBetOrPlayerBalance: number,\n    ): number {\n        let betValue: number = Number.MAX_VALUE;\n        for (const betData of availableBets) {\n            const money = new MoneyFormatter(betData.bet * betData.denomination * factor);\n            if (money.moneyInUnits > maxBetOrPlayerBalance && money.moneyInUnits < betValue) {\n                betValue = money.moneyInUnits;\n            }\n        }\n        return betValue;\n    }\n\n    private actionGetLocalStorageData(context: ExtendedMultipleBuyBonusContext): void {\n        context.confirmationCheckBoxChecked =\n            localStorage.getItem('buyBonusConfirmationCheckboxChecked') === 'true' ? true : false;\n    }\n\n    private actionOnPopUpClosed(context: ExtendedMultipleBuyBonusContext): void {\n        context.closingPopUp = false;\n        if (context.activated) {\n            this.actionUpdateBetsWhenGuaranteedWin(context);\n        }\n    }\n\n    private actionCollect(context: ExtendedMultipleBuyBonusContext): void {\n        if (!this.isEnabled(context)) {\n            return;\n        }\n        if (\n            !context.activated &&\n            context.activationType !== 'doubleChance' &&\n            !this.componentConfiguration.onlyDoubleChance &&\n            (this.rootStore.uiStore.STATE.value === UIState.COLLECT_BEFORE_IDLE ||\n                this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT)\n        ) {\n            this.rootStore.uiStore.STATE.next(UIState.DISABLED);\n            context.collectRequested = true;\n            this.rootStore.domainStore.collect();\n            this.rootStore.uiStore.COLLECT_CHANGED.next();\n        } else {\n            if (this.componentConfiguration.onlyDoubleChance) {\n                this.stateMachineService.send('DOUBLE_CHANCE_CLICKED');\n            } else {\n                this.stateMachineService.send('BUY_BONUS_BTN_CLICKED');\n            }\n        }\n    }\n\n    private setAvailableDenom(\n        availableDenominations: number[],\n        currentDenomIndex: number,\n        offset: number,\n        biggerOffset: boolean,\n    ): number {\n        const denomOffset = biggerOffset ? offset : offset * -1;\n\n        if (\n            this.rootStore.settings.denominations[currentDenomIndex + denomOffset] &&\n            availableDenominations.includes(this.rootStore.settings.denominations[currentDenomIndex + denomOffset])\n        ) {\n            return this.rootStore.settings.denominations[currentDenomIndex + denomOffset];\n        } else {\n            const nextDenomOffset = !biggerOffset ? offset + 1 : offset;\n            return this.setAvailableDenom(availableDenominations, currentDenomIndex, nextDenomOffset, !biggerOffset);\n        }\n    }\n\n    private actionOpenPopUp(context: ExtendedMultipleBuyBonusContext): void {\n        if (this.rootStore.subjects.SHOW_JP_STATS.value.type != -1) {\n            return;\n        }\n\n        if (!context.availableDenominations.includes(Core.SELECTED_DENOMINATION.value)) {\n            const currentDenomIndex = this.rootStore.settings.denominations.indexOf(Core.SELECTED_DENOMINATION.value);\n            context.denominationValue = this.setAvailableDenom(\n                context.availableDenominations,\n                currentDenomIndex,\n                1,\n                true,\n            );\n            context.currentBetIndex = 0;\n            this.actionSetAvailableBets(context);\n        }\n\n        AnalyticsDispatcher.buyBonusClickEvent();\n        this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_BTN_CLICKED.next();\n        this.rootStore.subjects.CLOSE_ALL_POPUPS.next();\n        this.rootStore.subjects.BUY_BONUS_POPUP_OPENED.next(true);\n        this.rootStore.subjects.TAB_OPENED.next(true);\n        let roundWin = 0;\n        if (\n            this.rootStore.uiStore.STATE.value === UIState.COLLECT_BEFORE_IDLE ||\n            this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT\n        ) {\n            // this.rootStore.domainStore.collect();\n            // this.rootStore.uiStore.COLLECT_CHANGED.next();\n            roundWin = this.rootStore.domainStore.betResponse.stateWinAmount;\n        }\n\n        const betData = context.availableBets[context.currentBetIndex];\n        this.view.openPopUp();\n        Core.UI_BLOCKER.next(true);\n        const guaranteedWinMode: boolean =\n            this.componentConfiguration.haveGuaranteedWinToggle && context.guaranteedWinToggleState === 'on'\n                ? true\n                : false;\n        this.view.updateBets(\n            betData.betMoney,\n            betData.bet,\n            betData.denomination,\n            context.activeBannerId,\n            guaranteedWinMode,\n        );\n        this.view.updatePopUpBalance(new MoneyFormatter(Core.PLAYER_BALANCE.value.balance + roundWin).stringMoney);\n        this.rootStore.subjects.HIDE_BET_BUTTONS.next();\n        this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(true);\n        this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(true);\n        this.rootStore.subjects.SHOW_HIDE_VIEW.next({ name: 'UIView', display: false });\n        this.rootStore.subjects.SHOW_HIDE_VIEW.next({ name: 'UIViewTurtle', display: false });\n    }\n\n    private actionPlaySliderSounds(context: ExtendedMultipleBuyBonusContext): void {\n        if (context.activated) {\n            Core.sounds.play('buyBonusNo');\n        } else {\n            if (context.activationType === 'doubleChance') {\n                Core.sounds.play('buyBonusClosed');\n            } else {\n                Core.sounds.play('buyBonus');\n            }\n            context.activationType = context.activationTypeToggleState;\n        }\n    }\n\n    private actionClosePopUp(_context: ExtendedMultipleBuyBonusContext): void {\n        _context.closingPopUp = true;\n        // context.activeBannerId = event.bonusId;\n        this.rootStore.subjects.BUY_BONUS_POPUP_OPENED.next(false);\n        this.rootStore.subjects.TAB_OPENED.next(false);\n        this.view.closePopUp();\n        Core.UI_BLOCKER.next(false);\n        this.rootStore.subjects.SHOW_BET_BUTTONS.next();\n        this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(false);\n        this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(false);\n        this.rootStore.subjects.SHOW_HIDE_VIEW.next({ name: 'UIView', display: true });\n        this.rootStore.subjects.SHOW_HIDE_VIEW.next({ name: 'UIViewTurtle', display: true });\n    }\n\n    private actionOpenConfirmationPopUp(context: ExtendedMultipleBuyBonusContext): void {\n        const bannerData: BannerData = context.getBannerDataById(context.activeBannerId);\n        const betUnits: number =\n            context.availableBets[context.currentBetIndex].bet *\n            context.availableBets[context.currentBetIndex].denomination *\n            bannerData.bonusFactor;\n        const money: MoneyFormatter = new MoneyFormatter(betUnits);\n        this.rootStore.subjects.BUY_BONUS_POPUP_OPENED.next(true);\n        this.view.openConfirmationPopUp(bannerData, money.stringMoneyWithCurrency);\n    }\n\n    private actionCloseConfirmationPopUp(context: ExtendedMultipleBuyBonusContext, event): void {\n        this.rootStore.subjects.BUY_BONUS_POPUP_OPENED.next(false);\n        this.view.closeConfirmationPopUp();\n        if (event.type === 'CONFIRMATION_POPUP_BACK' || event.type === 'CONFIRMATION_POPUP_CLOSE') {\n            context.confirmationCheckBoxChecked = false;\n            this.view.confirmationCheckBoxClicked(context.confirmationCheckBoxChecked);\n        }\n    }\n\n    private actionUpdateOutsideBets(context: ExtendedMultipleBuyBonusContext): void {\n        const betData = context.availableBets[context.currentBetIndex];\n        const guaranteedWinMode: boolean =\n            this.componentConfiguration.haveGuaranteedWinToggle && context.guaranteedWinToggleState === 'on'\n                ? true\n                : false;\n        const selectedBonusFactor =\n            guaranteedWinMode && context.getBannerDataById(context.activeBannerId).secondBonusFactor\n                ? context.getBannerDataById(context.activeBannerId).secondBonusFactor\n                : context.getBannerDataById(context.activeBannerId).bonusFactor;\n        let totalBetMoney = new MoneyFormatter(betData.bet * betData.denomination * selectedBonusFactor).stringMoney;\n        if (betData.bet * betData.denomination * selectedBonusFactor > 9900) {\n            totalBetMoney = totalBetMoney.replace('.00', '');\n        }\n        this.view.updateOutsideBet(totalBetMoney);\n    }\n\n    private actionChangeDenomAndBet(context: ExtendedMultipleBuyBonusContext): void {\n        const betData = context.availableBets[context.currentBetIndex];\n        const denom = this.componentConfiguration.skipSameBets\n            ? this.searchForDenomination(new MoneyFormatter(betData.betMoney).stringMoney, 0, true)\n            : context.availableBets[context.currentBetIndex];\n\n        this.rootStore.uiStore.SELECTED_BET.next(denom.bet);\n        this.rootStore.subjects.SETTINGS_BET_CHANGED.next();\n        this.rootStore.subjects.CHANGE_SELECTED_BET_BTN_EXTERNALLY.next({\n            betVal: this.rootStore.uiStore.SELECTED_BET.value,\n            changedFromPopUp: false,\n        });\n        Core.SELECTED_DENOMINATION.next(denom.denomination);\n        const settingsDenomination = this.settings.denominations.indexOf(denom.denomination) + 1;\n        this.rootStore.subjects.SETTINGS_DENOMINATION_CHANGED.next({\n            denomination: settingsDenomination,\n            playDenomChangeSound: false,\n        });\n\n        if (this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value) {\n            this.rootStore.uiStore.CURRENT_BET_LEVEL.next({\n                betLevel: this.rootStore.uiStore.SELECTED_BET.value,\n                denomLevel: Core.SELECTED_DENOMINATION.value,\n            });\n        }\n    }\n\n    private actionActivated(context: ExtendedMultipleBuyBonusContext): void {\n        if (this.componentConfiguration.haveConfirmationPopUp) {\n            localStorage.setItem('buyBonusConfirmationCheckboxChecked', context.confirmationCheckBoxChecked.toString());\n            this.view.closeConfirmationPopUp();\n        }\n        const bannerData: BannerData = context.getBannerDataById(context.activeBannerId);\n        if (\n            context.guaranteedWinToggleState === 'off' ||\n            (context.guaranteedWinToggleState === 'on' && !bannerData.secondGameMode)\n        ) {\n            this.settings.gameMode = bannerData.gameMode;\n            this.settings.factor = bannerData.bonusFactor;\n        } else {\n            this.settings.gameMode = bannerData.secondGameMode;\n            this.settings.factor = bannerData.secondBonusFactor;\n        }\n        this.rootStore.uiStore.CURRENT_BET_LEVEL.next({\n            betLevel: this.rootStore.uiStore.SELECTED_BET.value,\n            denomLevel: Core.SELECTED_DENOMINATION.value,\n        });\n        if (bannerData.shouldBuy) {\n            Core.sounds.play('buyBonusYes');\n\n            this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_RESPONSE);\n            this.rootStore.subjects.SETTINGS_BET_CHANGED.next();\n            this.rootStore.subjects.CHANGE_SELECTED_BET_BTN_EXTERNALLY.next({\n                betVal: this.rootStore.uiStore.SELECTED_BET.value,\n                changedFromPopUp: false,\n            });\n\n            this.rootStore.subjects.BEFORE_SPIN.next();\n            this.rootStore.subjects.SPIN_STARTED.next();\n            this.rootStore.domainStore.bet();\n        }\n\n        context.activated = true;\n        if (context.activationTypeToggleState === 'infinity') {\n            context.activationType = 'infinity';\n            this.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.next(true);\n            this.stateMachineService.send('ON_SHOW_INFO_TEXT');\n            this.rootStore.subjects.FACTOR_CHANGED.next();\n            this.updateDenominations();\n            this.view.showActivated(bannerData, true);\n            this.rootStore.subjects.HIDE_BET_BUTTONS.next();\n            this.subjects.SPIN_BUTTON_SPECIAL_TEXT_VISIBLE.next(true);\n            this.subjects.EXTENDED_DENOMINATION_POP_UP_TITLE.next(bannerData.denomPopUpTitleText);\n            this.subjects.BET_SETTINGS_TITLE.next(bannerData.betSettingsTitleText);\n        } else {\n            context.activationType = 'once';\n            this.view.showActivated(bannerData, false);\n            this.subjects.START_MANUAL_SPIN.next();\n        }\n        context.spinsAfterActivation = 0;\n    }\n\n    private actionReady(context: ExtendedMultipleBuyBonusContext): void {\n        context.activated = false;\n        context.doubleChanceState = 'inactive';\n        this.subjects.EXTENDED_DENOMINATION_POP_UP_TITLE.next('BET LEVELS');\n        this.subjects.BET_SETTINGS_TITLE.next('BET');\n        this.view.showReady();\n        this.settings.factor = this.settings.getFactorByUniqueGameMode('NORMAL_MODE');\n        this.settings.gameMode = 'NORMAL_MODE';\n        this.rootStore.subjects.FACTOR_CHANGED.next();\n        this.updateDenominations();\n        this.rootStore.subjects.CLOSE_ALL_POPUPS.next();\n        this.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.next(false);\n        this.rootStore.subjects.SHOW_BET_BUTTONS.next();\n    }\n\n    private actionUpdateBetsWhenGuaranteedWin(context: ExtendedMultipleBuyBonusContext) {\n        if (context.closingPopUp) {\n            return;\n        }\n        this.view.enableAllBanners();\n        for (const bannerData of context.bannersData) {\n            bannerData.maxBetBannerValue = this.getMaxBannerValue(\n                context.availableBets,\n                bannerData.bonusFactor,\n                bannerData.maxBet,\n            );\n            bannerData.insufficientFundsBannerValue = this.getMaxBannerValue(\n                context.availableBets,\n                bannerData.bonusFactor,\n                this.rootStore.uiStore.BALANCE.value,\n            );\n            if (bannerData.secondBonusFactor) {\n                bannerData.secondFactorMaxBetBannerValue = this.getMaxBannerValue(\n                    context.availableBets,\n                    bannerData.secondBonusFactor,\n                    bannerData.maxBet,\n                );\n                bannerData.secondFactorInsufficientFundsBannerValue = this.getMaxBannerValue(\n                    context.availableBets,\n                    bannerData.secondBonusFactor,\n                    this.rootStore.uiStore.BALANCE.value,\n                );\n            }\n        }\n        const betData = context.availableBets[context.currentBetIndex];\n        const guaranteedWinMode: boolean =\n            this.componentConfiguration.haveGuaranteedWinToggle && context.guaranteedWinToggleState === 'on'\n                ? true\n                : false;\n        this.view.updateBets(\n            betData.betMoney,\n            betData.bet,\n            betData.denomination,\n            context.activeBannerId,\n            guaranteedWinMode,\n        );\n        this.view.updatePopUpBalance(new MoneyFormatter(Core.PLAYER_BALANCE.value.balance).stringMoney);\n    }\n\n    private actionIncreaseBet(context: ExtendedMultipleBuyBonusContext): void {\n        if (context.currentBetIndex < context.availableBets.length - 1) {\n            context.currentBetIndex++;\n            const betData = context.availableBets[context.currentBetIndex];\n            const guaranteedWinMode: boolean =\n                this.componentConfiguration.haveGuaranteedWinToggle && context.guaranteedWinToggleState === 'on'\n                    ? true\n                    : false;\n            this.view.updateBets(\n                betData.betMoney,\n                betData.bet,\n                betData.denomination,\n                context.activeBannerId,\n                guaranteedWinMode,\n            );\n        }\n    }\n\n    private actionDecreaseBet(context: ExtendedMultipleBuyBonusContext): void {\n        if (context.currentBetIndex > 0) {\n            context.currentBetIndex--;\n            const betData = context.availableBets[context.currentBetIndex];\n            const guaranteedWinMode: boolean =\n                this.componentConfiguration.haveGuaranteedWinToggle && context.guaranteedWinToggleState === 'on'\n                    ? true\n                    : false;\n            this.view.updateBets(\n                betData.betMoney,\n                betData.bet,\n                betData.denomination,\n                context.activeBannerId,\n                guaranteedWinMode,\n            );\n        }\n    }\n\n    private actionUpdateBetPanelControls(context: ExtendedMultipleBuyBonusContext): void {\n        this.view.disableDecreaseBtn(context.currentBetIndex === 0);\n        this.view.disableIncreaseBtn(context.currentBetIndex === context.availableBets.length - 1);\n    }\n\n    private actionUpdateOutsideBetPanelControls(context: ExtendedMultipleBuyBonusContext): void {\n        const outOfBets: boolean = context.currentBetIndex + 1 < context.availableBets.length ? false : true;\n        if (outOfBets) {\n            this.view.lastBet = context.currentBetIndex === context.availableBets.length - 1;\n            this.view.disableOutsideIncreaseBtn(context.currentBetIndex === context.availableBets.length - 1);\n        } else {\n            const betData = context.availableBets[context.currentBetIndex + 1];\n            const activeBonusConfig = context.getBannerDataById(context.activeBannerId);\n            const guaranteedWinMode: boolean =\n                this.componentConfiguration.haveGuaranteedWinToggle && context.guaranteedWinToggleState === 'on'\n                    ? true\n                    : false;\n            const selectedBonusFactor =\n                guaranteedWinMode && context.getBannerDataById(context.activeBannerId).secondBonusFactor\n                    ? context.getBannerDataById(context.activeBannerId).secondBonusFactor\n                    : context.getBannerDataById(context.activeBannerId).bonusFactor;\n            const currentBet = betData.bet * betData.denomination * selectedBonusFactor;\n            this.view.disableOutsideIncreaseBtn(\n                context.currentBetIndex === context.availableBets.length - 1 || currentBet > activeBonusConfig.maxBet,\n            );\n            this.view.lastBet =\n                context.currentBetIndex === context.availableBets.length - 1 || currentBet > activeBonusConfig.maxBet;\n        }\n        this.view.firstBet = context.currentBetIndex === 0;\n        this.view.disableOutsideDecreaseBtn(context.currentBetIndex === 0);\n    }\n\n    private actionOutsideIncreaseBtn(context: ExtendedMultipleBuyBonusContext): void {\n        if (context.currentBetIndex < context.availableBets.length - 1) {\n            const betData = context.availableBets[context.currentBetIndex + 1];\n            const activeBonusConfig = context.getBannerDataById(context.activeBannerId);\n            const currentBet = betData.bet * betData.denomination * activeBonusConfig.bonusFactor;\n            if (currentBet <= activeBonusConfig.maxBet) {\n                context.currentBetIndex++;\n            }\n        }\n    }\n\n    private actionOutsideDecreaseBtn(context: ExtendedMultipleBuyBonusContext): void {\n        if (context.currentBetIndex > 0) {\n            context.currentBetIndex--;\n        }\n    }\n\n    private actionForceInsufficientFundMessage(): void {\n        if (\n            this.rootStore.getBetAmount() > this.rootStore.uiStore.BALANCE.value &&\n            !this.featureController.isControlInFeature\n        ) {\n            this.rootStore.subjects.SHOW_DIRECT_MESSAGEBAR_TEXT.next([\n                MessBarTypes.INSUFFICIENT,\n                Core.translator.translate('4813').toUpperCase().replace('. (##ERROR_CODE##)', ''),\n            ]);\n\n            // PostMessageDispatcher.balanceTooLow();\n        }\n    }\n\n    private actionDoubleChanceChangeState(_context: ExtendedMultipleBuyBonusContext): void {\n        if (!_context.doubleChanceEnabled) {\n            return;\n        }\n        if (!this.componentConfiguration.onlyDoubleChance) {\n            _context.activationType = 'doubleChance';\n        }\n        if (_context.doubleChanceState === 'active') {\n            this.actionDeactivateDoubleChance(_context);\n            Core.sounds.play('doubleChanceDeactivate');\n        } else {\n            // const bannerData: BannerData = _context.getBannerDataById(_context.activeBannerId);\n            // this.settings.factor = this.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE');\n            // this.settings.gameMode = 'DOUBLE_CHANCE';\n            // this.rootStore.subjects.FACTOR_CHANGED.next();\n            // this.updateDenominations();\n\n            Core.sounds.play('doubleChanceActivate');\n            _context.doubleChanceState = 'active';\n            // this.actionReady(_context);\n            this.actionHideInfoText(_context);\n            this.view.activateDoubleChance();\n            // this.settings.factor = this.settings.factors[this.slotConfiguration.doubleChanceFactorIndex];\n            this.settings.factor = this.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE');\n            this.settings.gameMode = 'DOUBLE_CHANCE';\n            this.rootStore.subjects.FACTOR_CHANGED.next();\n\n            if (this.componentConfiguration.onlyDoubleChance) {\n                this.updateDenominations();\n            }\n        }\n    }\n\n    private actionDeactivateDoubleChance(_context: ExtendedMultipleBuyBonusContext): void {\n        _context.doubleChanceState = 'inactive';\n        this.view.deactivateDoubleChance();\n        // this.settings.factor = this.settings.factors[this.slotConfiguration.normalFactorIndex];\n        this.settings.factor = this.settings.getFactorByUniqueGameMode('NORMAL_MODE');\n        this.settings.gameMode = 'NORMAL_MODE';\n        this.rootStore.subjects.FACTOR_CHANGED.next();\n        this.updateDenominations();\n    }\n\n    private actionActivateDoubleChanceFromPopUp(context: ExtendedMultipleBuyBonusContext): void {\n        const bannerData: BannerData = context.getBannerDataById(context.activeBannerId);\n        // this.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.next(true);\n        this.view.showActivated(bannerData, false);\n        this.updateDenominations();\n    }\n\n    private actionOnNewSpin(context: ExtendedMultipleBuyBonusContext): void {\n        context.spinsAfterActivation++;\n        this.stateMachineService.send('ON_NEW_SPIN_START');\n    }\n\n    private actionDeactivate(context: ExtendedMultipleBuyBonusContext): void {\n        context.activated = false;\n        context.doubleChanceState = 'inactive';\n        this.settings.factor = this.settings.getFactorByUniqueGameMode('NORMAL_MODE');\n        this.settings.gameMode = 'NORMAL_MODE';\n        this.view.showReady();\n    }\n\n    private actionOnToggleClicked(context: ExtendedMultipleBuyBonusContext): void {\n        if (context.activationTypeToggleState === 'infinity') {\n            this.view.updateToggleState('Inactive');\n            context.activationType = 'once';\n            context.activationTypeToggleState = 'once';\n        } else {\n            this.view.updateToggleState('Active');\n            context.activationType = 'infinity';\n            context.activationTypeToggleState = 'infinity';\n        }\n    }\n\n    private actionOnGuaranteedWinToggleClicked(context: ExtendedMultipleBuyBonusContext): void {\n        if (context.guaranteedWinToggleState === 'on') {\n            this.view.guaranteedWinUpdateToggleState('Inactive');\n            context.guaranteedWinToggleState = 'off';\n        } else {\n            this.view.guaranteedWinUpdateToggleState('Active');\n            context.guaranteedWinToggleState = 'on';\n        }\n    }\n\n    private actionShowInfoText(_context: ExtendedMultipleBuyBonusContext): void {\n        if (_context.activationTypeToggleState === 'infinity') {\n            this.view.showInfoText(_context.getBannerDataById(_context.activeBannerId).activeText);\n        }\n    }\n\n    private actionHideInfoText(_context: ExtendedMultipleBuyBonusContext): void {\n        this.view.hideInfoText();\n    }\n\n    private actionBonusSelected(_context: ExtendedMultipleBuyBonusContext, event): void {\n        if (event.bonusId !== _context.activeBannerId) {\n            if (this.componentConfiguration.bannersHaveSelectedState) {\n                Core.sounds.play('buyBonusSelect');\n            }\n            _context.activeBannerId = event.bonusId;\n        }\n    }\n\n    private actionOnRecovery(_context: ExtendedMultipleBuyBonusContext): void {\n        const bannerConfig: BannerData = _context.getBannerDataById(_context.activeBannerId);\n        this.stateMachine.context.doubleChanceState = 'active';\n        _context.activationType = 'doubleChance';\n        this.view.activateDoubleChance();\n\n        this.settings.factor = bannerConfig.bonusFactor;\n        this.settings.gameMode = bannerConfig.gameMode;\n        this.rootStore.subjects.FACTOR_CHANGED.next();\n        this.updateDenominations();\n        this.view.showActivated(bannerConfig, false);\n    }\n\n    private actionGetCurrentBetIndex(context: ExtendedMultipleBuyBonusContext): void {\n        context.betValue = this.rootStore.uiStore.SELECTED_BET.value;\n        context.denominationValue = Core.SELECTED_DENOMINATION.value;\n        if (!this.componentConfiguration.skipSameBets) {\n            this.actionChangeDenomination(context, {\n                denomID: this.rootStore.settings.denominations.indexOf(context.denominationValue),\n                type: 'CHANGE_DENOMINATION',\n            });\n        }\n        const betMoney: number = context.denominationValue * context.betValue * this.settings.settings.settings.factor;\n        for (let i: number = 0; i < context.availableBets.length; i++) {\n            if (betMoney === context.availableBets[i].betMoney) {\n                context.currentBetIndex = i;\n            }\n        }\n    }\n\n    private actionConfirmationPopUpCheckBoxClicked(context: ExtendedMultipleBuyBonusContext): void {\n        context.confirmationCheckBoxChecked = !context.confirmationCheckBoxChecked;\n        this.view.confirmationCheckBoxClicked(context.confirmationCheckBoxChecked);\n    }\n\n    private actionShowBuyBtn(): void {\n        this.view.showBuyBtn();\n    }\n\n    private actionHideBuyBtn(): void {\n        this.view.hideBuyBtn();\n    }\n\n    private actionShowOutsidePanel(context: ExtendedMultipleBuyBonusContext): void {\n        if (context.activated) {\n            this.view.showOutsidePanel();\n        }\n    }\n\n    private actionHideOutsidePanel(context: ExtendedMultipleBuyBonusContext): void {\n        if (context.activated) {\n            this.view.hideOutsidePanel();\n        }\n    }\n\n    private actionDisabledBuyBonus(\n        context: ExtendedMultipleBuyBonusContext,\n        e: { doNotChangeVisible: boolean; type: string },\n    ): void {\n        context.disabled = true;\n        context.doubleChanceEnabled = false;\n        this.view.disabled(e.doNotChangeVisible);\n    }\n\n    private actionEnableBuyBonus(context: ExtendedMultipleBuyBonusContext): void {\n        if (\n            !(\n                this.componentConfiguration.onlyDoubleChance &&\n                context.betValue *\n                    context.denominationValue *\n                    this.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE') >\n                    this.settings.maxBet * 100\n            )\n        ) {\n            context.disabled = false;\n            context.doubleChanceEnabled = true;\n            this.view.enabled();\n        }\n    }\n    private actionRestoreFactor(context: ExtendedMultipleBuyBonusContext): void {\n        if (context.activationType !== 'infinity') {\n            return;\n        }\n        const bannerData: BannerData = context.getBannerDataById(context.activeBannerId);\n        if (\n            this.componentConfiguration.haveGuaranteedWinToggle &&\n            context.guaranteedWinToggleState === 'on' &&\n            bannerData.secondBonusFactor\n        ) {\n            this.settings.factor = bannerData.secondBonusFactor;\n            this.settings.gameMode = bannerData.secondGameMode;\n        } else {\n            this.settings.factor = bannerData.bonusFactor;\n            this.settings.gameMode = bannerData.gameMode;\n        }\n        this.rootStore.subjects.FACTOR_CHANGED.next();\n    }\n\n    // use this action only for games where can change denomination inside pop up like bell link\n    private actionChangeDenomination(context: ExtendedMultipleBuyBonusContext, e): void {\n        if (this.componentConfiguration.skipSameBets) {\n            return;\n        }\n\n        context.denominationValue = this.rootStore.settings.denominations[e.denomID];\n        context.availableBets = [];\n        this.actionSetAvailableBets(context);\n\n        if (context.closingPopUp) {\n            const selectedBetValue = context.betValue || this.rootStore.uiStore.SELECTED_BET.value;\n            context.currentBetIndex = this.getMatchedBetIndex(\n                context,\n                selectedBetValue,\n                context.denominationValue,\n                context.currentBetIndex,\n            );\n        } else {\n            context.currentBetIndex = 0;\n        }\n\n        const denom = context.availableBets[context.currentBetIndex];\n        context.denominationValue = denom.denomination;\n\n        const betData = context.availableBets[context.currentBetIndex];\n        const guaranteedWinMode: boolean =\n            this.componentConfiguration.haveGuaranteedWinToggle && context.guaranteedWinToggleState === 'on'\n                ? true\n                : false;\n        this.view.updateBets(\n            betData.betMoney,\n            betData.bet,\n            betData.denomination,\n            context.activeBannerId,\n            guaranteedWinMode,\n        );\n    }\n\n    private getMatchedBetIndex(\n        context: ExtendedMultipleBuyBonusContext,\n        betValue: number,\n        denominationValue: number,\n        fallbackIndex = 0,\n    ): number {\n        if (!context.availableBets.length) {\n            return 0;\n        }\n\n        const matchedIndex = context.availableBets.findIndex(\n            (availableBet) => availableBet.bet === betValue && availableBet.denomination === denominationValue,\n        );\n\n        return matchedIndex !== -1 ? matchedIndex : fallbackIndex;\n    }\n\n    private haveConfirmationPopUp(context: ExtendedMultipleBuyBonusContext): boolean {\n        return !context.confirmationCheckBoxChecked && this.componentConfiguration.haveConfirmationPopUp;\n    }\n\n    private canEnableBuyBonus() {\n        return !this.featureController.isInGiftSpins;\n    }\n\n    private shouldDeactivate(context: ExtendedMultipleBuyBonusContext, e): boolean {\n        const bannerData: BannerData = context.getBannerDataById(context.activeBannerId);\n        if (e.type === 'ON_NEW_SPIN_START') {\n            return context.activationType === 'once' && context.spinsAfterActivation === 2;\n        } else {\n            return context.activationType === 'once' && bannerData.deactivateOnReelStoppedWhenBuyOnce;\n        }\n    }\n\n    private shouldForceDeactivate(context: ExtendedMultipleBuyBonusContext): boolean {\n        return context.activationTypeToggleState !== 'infinity';\n    }\n\n    private isEnabled(context: ExtendedMultipleBuyBonusContext): boolean {\n        return !context.disabled;\n    }\n\n    private shouldDisplayBuyBtn(settings): boolean {\n        const { state, bonus } = settings;\n\n        return (\n            state === ServerState.IDLE ||\n            state === ServerState.BONUS_IDLE ||\n            state === ServerState.BONUS_SUMMARY ||\n            state === ServerState.RESPIN ||\n            // In case of interruption in gsc the bb btn should be visible but disabled\n            ((state === ServerState.FREESPIN || state === ServerState.CHOICE) &&\n                bonus &&\n                (bonus.type === BonusTypes.BUY_BONUS || bonus.type === BonusTypes.GIFT_SPIN))\n        );\n    }\n\n    // search for bet in closest denomination\n    private searchForDenomination(\n        bet: string,\n        denominationOffset: number,\n        checkInBiggerDenomination: boolean,\n    ): { denomination: number; bet: number } {\n        let denomination: number = -1;\n        const currentDenominationIndex: number = this.settings.denominations.indexOf(Core.SELECTED_DENOMINATION.value);\n        if (checkInBiggerDenomination) {\n            if (currentDenominationIndex + denominationOffset < this.settings.denominations.length) {\n                denomination = this.settings.denominations[currentDenominationIndex + denominationOffset];\n            } else {\n                return this.searchForDenomination(bet, denominationOffset, false);\n            }\n        } else {\n            if (currentDenominationIndex - denominationOffset >= 0) {\n                denomination = this.settings.denominations[currentDenominationIndex - denominationOffset];\n                denominationOffset++;\n            } else {\n                denominationOffset++;\n                return this.searchForDenomination(bet, denominationOffset, true);\n            }\n        }\n        const denominationMap: Map<string, { denomination: number; bet: number }> = new Map();\n        for (const bet of this.settings.bets) {\n            const betValue = new MoneyFormatter(denomination * bet * this.settings.factors[0]);\n            denominationMap.set(betValue.stringMoney, {\n                denomination: denomination,\n                bet: bet,\n            });\n        }\n        if (denominationMap.has(bet)) {\n            return denominationMap.get(bet) as { denomination: number; bet: number };\n        } else {\n            return this.searchForDenomination(bet, denominationOffset, !checkInBiggerDenomination);\n        }\n    }\n    protected onKeyReleased(e: KeyboardEvent): void {\n        if (e === null) {\n            return;\n        }\n        // close modal when popup if space/enter/letter/digit is pressed\n        if (\n            (e.code !== undefined &&\n                (e.code === 'Space' ||\n                    e.code === 'Enter' ||\n                    e.code === 'NumpadEnter' ||\n                    e.code === 'ArrowDown' ||\n                    e.code.indexOf('key') !== -1 ||\n                    e.code.indexOf('Digit') !== -1)) ||\n            (e.keyCode !== undefined && (e.keyCode === 32 || e.keyCode === 13)) ||\n            (e.keyCode >= 65 && e.keyCode <= 90) ||\n            (e.keyCode >= 48 && e.keyCode <= 57)\n        ) {\n            this.stateMachineService.send('CLOSE_POPUP');\n        }\n    }\n\n    private onErrorWithInsifitionsFunds(error: IErrorData): void {\n        const errorCode = error.code.toString();\n        if (errorCode === '4813' || errorCode === '4818') {\n            this.stateMachineService.send('FORCE_DEACTIVATE');\n        }\n    }\n}\n","export default class BannerData {\n    public bannerId: number;\n    public bonusFactor: number;\n    public gameMode: string;\n    public secondBonusFactor: number;\n    public secondGameMode: string;\n    public shouldBuy: boolean;\n    public maxBet: number;\n    public maxBetBannerValue: number;\n    public secondFactorMaxBetBannerValue: number;\n    public insufficientFundsBannerValue: number;\n    public secondFactorInsufficientFundsBannerValue: number;\n    public bannerDescriptionText: string;\n    public activeText: string;\n    public betText: string;\n    public spinBtnText: string;\n    public denomPopUpTitleText: string;\n    public betSettingsTitleText: string;\n    public deactivateOnReelStoppedWhenBuyOnce: boolean;\n}\n","import BannerData from './BannerData';\n\nexport default class ExtendedMultipleBuyBonusContext {\n    public doubleChanceState: 'active' | 'inactive' = 'inactive';\n    public doubleChanceEnabled: boolean = true;\n    public activated: boolean = false;\n    public activationType: 'infinity' | 'once' | 'doubleChance' = 'once';\n    public guaranteedWinToggleState: 'on' | 'off' = 'off';\n    public activationTypeToggleState: 'infinity' | 'once';\n    public bannersData: BannerData[] = [];\n    public activeBannerId: number = -1;\n    public disabled: boolean = false;\n    public currentBetIndex: number = 0;\n    public availableDenominations: number[] = [];\n    public availableBets: Array<{ betMoney: number; bet: number; denomination: number; baseFactor: number }> = [];\n    public confirmationCheckBoxChecked: boolean = false;\n    public spinsAfterActivation: number = 0;\n    public collectRequested: boolean = false;\n    public closingPopUp: boolean = false;\n    public denominationValue: number = 0;\n    public betValue: number;\n\n    public getBannerDataById(bannerId: number): BannerData {\n        return this.bannersData.filter((config) => config.bannerId === bannerId)[0];\n    }\n\n    public getBannerDataByFactor(factor: number): BannerData {\n        return this.bannersData.filter((config) => config.bonusFactor === factor)[0];\n    }\n    public getBannerDataByGameMode(gameMode: string): BannerData {\n        return this.bannersData.filter((config) => config.gameMode === gameMode)[0];\n    }\n}\n","import Core from '@egt/core';\nimport { ISlotConfiguration, InitialSettings, RootStore } from '@egt/slot';\nimport { ViewContainer } from '@egt/ui-lib';\nimport { gsap } from 'gsap';\nimport { Container, Graphics, NineSlicePlane, Sprite, Text } from 'pixi.js';\nimport { fromEvent, merge } from 'rxjs';\nimport { filter, takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { IBuyBonusComponentConfigurationExtendedMultipleBuyBonus } from '../configuration/IBuyBonusComponentConfigurationExtendedMultipleBuyBonus';\nimport BannerData from '../data/BannerData';\nimport { IBannerConfig } from '../interfaces/InterfacesExtendedMultipleBuyBonus';\nimport ExtendedMultipleBuyBonusBanner from './ExtendedMultipleBuyBonusBanner';\nimport ExtendedMultipleBuyBonusBetControl from './ExtendedMultipleBuyBonusBetControl';\nimport ExtendedMultipleBuyBonusInfoText from './ExtendedMultipleBuyBonusInfoText';\n\n@injectable()\nexport default class BuyBonusViewExtendedMultipleBuyBonus extends ViewContainer {\n    public stateMachineService;\n    public firstBet: boolean;\n    public lastBet: boolean;\n\n    private buyBonusBtn: Sprite;\n    private buyBonusTextureType: string = 'buyBonusBtn';\n\n    private doubleChanceButton: Sprite;\n    private doubleChanceState: 'Active' | 'Inactive' = 'Inactive';\n\n    private popUpContainer: Sprite;\n    private popUpOverlay: Graphics;\n\n    private showTimeLine: any;\n    private hideTimeLine: any;\n\n    private popUpBackground: Sprite;\n    private popUpTitle: Sprite;\n    private popUpBtnClose: Sprite;\n    private popUpConfirmBtn: Sprite;\n    // private popUpInfinityConfirmBtn: Sprite;\n\n    private popUpToggleTextMaxWidth: number;\n    private popUpToggleTimeLine: any;\n    private popUpToggleContainer: Sprite;\n    private popUpToggleActive: Sprite;\n    private popUpToggleText: Text;\n    private popUpToggleInactive: Sprite;\n    private popUpToggleSliderActive: Sprite;\n    private popUpToggleSliderInactive: Sprite;\n    private popUpToggleBackgroundActive: NineSlicePlane;\n    private popUpToggleBackgroundInactive: NineSlicePlane;\n    private popUpToggleState: 'Active' | 'Inactive' = 'Inactive';\n\n    private guaranteedWinPopUpToggleTextMaxWidth: number;\n    private guaranteedWinPopUpToggleTimeLine: any;\n    private guaranteedWinPopUpToggleContainer: Sprite;\n    private guaranteedWinPopUpToggleText: Text;\n    private guaranteedWinPopUpToggleActive: Sprite;\n    private guaranteedWinPopUpToggleInactive: Sprite;\n    private guaranteedWinPopUpToggleSliderActive: Sprite;\n    private guaranteedWinPopUpToggleSliderInactive: Sprite;\n    private guaranteedWinPopUpToggleBackgroundActive: NineSlicePlane;\n    private guaranteedWinPopUpToggleBackgroundInactive: NineSlicePlane;\n\n    private popUpBanners: ExtendedMultipleBuyBonusBanner[] = [];\n\n    private betPanel: ExtendedMultipleBuyBonusBetControl;\n\n    private infoText: ExtendedMultipleBuyBonusInfoText;\n\n    private balanceContainer: Sprite;\n    private balanceText: Text;\n    private balanceValue: Text;\n    private balanceCurrency: Text;\n\n    private confirmationPopUpContainer: Sprite;\n    private confirmationPopUpOverlay: Graphics;\n    private confirmationPopUpBackground: Sprite;\n    private confirmationPopUpTitle: Sprite;\n    private confirmationPopUpDescriptionText: Text;\n    private confirmationPopUpValueText: Text;\n    private confirmationPopUpValueDescriptionText: Text;\n    private confirmationPopUpConfirmBtn: Sprite;\n    private confirmationPopUpConfirmBtnText: Sprite;\n    private confirmationPopUpBackBtn: Sprite;\n    private confirmationPopUpBackBtnText: Sprite;\n    private confirmationPopUpCheckBox: Sprite;\n    private confirmationPopUpDontShowText: Text;\n\n    private betOutsideContainer: Sprite;\n    private betOutsideBase: Sprite;\n    private betOutsideIncreaseBtn: Sprite;\n    private betOutsideIncreaseBtnGraphics: Graphics;\n    private betOutsideDecreaseBtn: Sprite;\n    private betOutsideDecreaseBtnGraphics: Graphics;\n    private betOutsideBetContainer: Sprite;\n    private betOutsideTotalBetValue: Text;\n    private betOutsideTotalBetCurrency: Text;\n    private betOutsideBetInfo: Text;\n\n    // private denominationText: Text;\n    private denomContainer: Container;\n    private denominationBtns: { inactive: Sprite; active: Sprite; id: number }[] = [];\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('BuyBonusComponentConfiguration')\n        protected componentConfiguration: IBuyBonusComponentConfigurationExtendedMultipleBuyBonus,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n    ) {\n        super();\n        this.name = 'BuyBonusView';\n    }\n\n    public destroy(): void {\n        super.destroy();\n    }\n\n    public init(\n        bannersConfig: BannerData[],\n        bet: number,\n        denomination: number,\n        availableDenominations: number[],\n    ): void {\n        if (this.componentConfiguration.onlyDoubleChance) {\n            this.createDoubleChanceButton();\n        }\n        this.createButton();\n        this.createOutsideBet();\n        this.createInfoText();\n        this.createPopUp();\n        this.createPopUpBanners(bannersConfig, bet, denomination);\n        this.createBetPanel();\n        this.createBalanceContainer();\n        if (this.componentConfiguration.haveConfirmationPopUp) {\n            this.createConfirmationPopUp();\n        }\n\n        if (!this.componentConfiguration.skipSameBets) {\n            this.createDenominationButtons(availableDenominations);\n        }\n\n        this.closePopUp();\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus.ts:144:9\",(this.betPanel.decreaseBtnGraphics),\"pointertap\"]), fromEvent(this.betPanel.decreaseBtnGraphics, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onDecreaseBetAmount.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus.ts:148:9\",(this.betPanel.increaseBtnGraphics),\"pointertap\"]), fromEvent(this.betPanel.increaseBtnGraphics, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onIncreaseBetAmount.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus.ts:152:9\",(this.buyBonusBtn),\"pointertap\"]), fromEvent(this.buyBonusBtn, 'pointertap'))\n            .pipe(\n                filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.onBuyBonusBtnClicked.bind(this));\n\n        if (this.doubleChanceButton) {\n            (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus.ts:160:13\",(this.doubleChanceButton),\"pointertap\"]), fromEvent(this.doubleChanceButton, 'pointertap'))\n                .pipe(\n                    filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n                    takeUntil(this.DESTROY),\n                )\n                .subscribe(this.onDoubleBtnChanceClicked.bind(this));\n        }\n\n        if (this.componentConfiguration.bannersHaveSelectedState) {\n            for (const popUpBanner of this.popUpBanners) {\n                (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus.ts:170:17\",(popUpBanner),\"pointertap\"]), fromEvent(popUpBanner, 'pointertap'))\n                    .pipe(takeUntil(this.DESTROY))\n                    .subscribe(\n                        this.onBonusSelected.bind(\n                            this,\n                            popUpBanner.bannerId,\n                            popUpBanner.gameMode,\n                            popUpBanner.bonusFactor,\n                        ),\n                    );\n            }\n\n            (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus.ts:182:13\",(this.popUpConfirmBtn),\"pointertap\"]), fromEvent(this.popUpConfirmBtn, 'pointertap'))\n                .pipe(takeUntil(this.DESTROY))\n                .subscribe(this.onBonusChosen.bind(this));\n        } else {\n            for (const popUpBanner of this.popUpBanners) {\n                (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus.ts:187:17\",(popUpBanner.bannerConfirmBnt),\"pointertap\"]), fromEvent(popUpBanner.bannerConfirmBnt, 'pointertap'))\n                    .pipe(takeUntil(this.DESTROY))\n                    .subscribe(\n                        this.onBonusSelected.bind(\n                            this,\n                            popUpBanner.bannerId,\n                            popUpBanner.gameMode,\n                            popUpBanner.bonusFactor,\n                        ),\n                    );\n                (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus.ts:197:17\",(popUpBanner.bannerCancelBtn),\"pointertap\"]), fromEvent(popUpBanner.bannerCancelBtn, 'pointertap'))\n                    .pipe(takeUntil(this.DESTROY))\n                    .subscribe(this.onPopUpCancelClicked.bind(this));\n            }\n        }\n\n        if (!this.componentConfiguration.skipSameBets) {\n            for (const denomination of this.denominationBtns) {\n                (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus.ts:205:17\",(denomination.inactive),\"pointertap\"]), fromEvent(denomination.inactive, 'pointertap'))\n                    .pipe(takeUntil(this.DESTROY))\n                    .subscribe(this.onDenominationChanged.bind(this, denomination.id));\n                fromEvent(denomination.inactive, 'pointerover')\n                    .pipe(takeUntil(this.DESTROY))\n                    .subscribe(this.onDenominationHover.bind(this, denomination.id));\n                fromEvent(denomination.inactive, 'pointerout')\n                    .pipe(takeUntil(this.DESTROY))\n                    .subscribe(this.onDenominationOut.bind(this, denomination.id));\n                (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus.ts:214:17\",(denomination.inactive),\"pointerupoutside\"]), fromEvent(denomination.inactive, 'pointerupoutside'))\n                    .pipe(takeUntil(this.DESTROY))\n                    .subscribe(this.onDenominationOut.bind(this, denomination.id));\n                (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus.ts:217:17\",(denomination.inactive),\"pointerdown\"]), fromEvent(denomination.inactive, 'pointerdown'))\n                    .pipe(takeUntil(this.DESTROY))\n                    .subscribe(this.onDenominationDown.bind(this, denomination.id));\n            }\n        }\n\n        // fromEvent(this.popUpInfinityConfirmBtn, 'pointertap')\n        //     .pipe(takeUntil(this.DESTROY))\n        //     .subscribe(this.onInfinityBonusChosen.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus.ts:227:9\",(this.popUpToggleBackgroundActive),\"pointertap\"]), fromEvent(this.popUpToggleBackgroundActive, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onToggleClicked.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus.ts:231:9\",(this.popUpToggleBackgroundInactive),\"pointertap\"]), fromEvent(this.popUpToggleBackgroundInactive, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onToggleClicked.bind(this));\n\n        if (this.componentConfiguration.haveGuaranteedWinToggle) {\n            (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus.ts:236:13\",(this.guaranteedWinPopUpToggleBackgroundActive),\"pointertap\"]), fromEvent(this.guaranteedWinPopUpToggleBackgroundActive, 'pointertap'))\n                .pipe(takeUntil(this.DESTROY))\n                .subscribe(this.onGuaranteedWinToggleClicked.bind(this));\n\n            (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus.ts:240:13\",(this.guaranteedWinPopUpToggleBackgroundInactive),\"pointertap\"]), fromEvent(this.guaranteedWinPopUpToggleBackgroundInactive, 'pointertap'))\n                .pipe(takeUntil(this.DESTROY))\n                .subscribe(this.onGuaranteedWinToggleClicked.bind(this));\n        }\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus.ts:245:9\",(this.popUpBtnClose),\"pointertap\"]), fromEvent(this.popUpBtnClose, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPopUpCancelClicked.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus.ts:249:9\",(this.popUpOverlay),\"pointertap\"]), fromEvent(this.popUpOverlay, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPopUpCancelClicked.bind(this));\n        if (this.componentConfiguration.haveConfirmationPopUp) {\n            (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus.ts:253:13\",(this.confirmationPopUpConfirmBtn),\"pointertap\"]), fromEvent(this.confirmationPopUpConfirmBtn, 'pointertap'))\n                .pipe(takeUntil(this.DESTROY))\n                .subscribe(this.onConfirmClicked.bind(this));\n\n            (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus.ts:257:13\",(this.confirmationPopUpBackBtn),\"pointertap\"]), fromEvent(this.confirmationPopUpBackBtn, 'pointertap'))\n                .pipe(takeUntil(this.DESTROY))\n                .subscribe(this.onBackClicked.bind(this));\n\n            (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus.ts:261:13\",(this.confirmationPopUpOverlay),\"pointertap\"]), fromEvent(this.confirmationPopUpOverlay, 'pointertap'))\n                .pipe(takeUntil(this.DESTROY))\n                .subscribe(this.onCloseConfirmationPopUp.bind(this));\n\n            (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus.ts:265:13\",(this.confirmationPopUpCheckBox),\"pointertap\"]), fromEvent(this.confirmationPopUpCheckBox, 'pointertap'))\n                .pipe(takeUntil(this.DESTROY))\n                .subscribe(this.onConfirmationCheckBoxClicked.bind(this));\n        }\n\n        this.stateMachineService.send('INIT_COMPLETE');\n        const orientationEvent = merge(Core.ORIENTATION, Core.LEFT_HAND_MODE);\n        orientationEvent.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n    }\n\n    private onDenominationChanged(denomID: number) {\n        this.onDenominationOut(denomID);\n\n        Core.sounds.play('buyBonusDenominationChanged');\n        this.stateMachineService.send({ type: 'CHANGE_DENOMINATION', denomID: denomID });\n        this.updateDenomination(this.rootStore.uiStore.denominations[denomID]);\n    }\n\n    private onDenominationHover(denomID: number) {\n        const btnObject = this.denominationBtns.find((item) => item.id === denomID) as {\n            inactive: Sprite;\n            active: Sprite;\n            id: number;\n        };\n        btnObject.inactive.texture = Core.assets.getAsset('denominationBntBBHover').texture;\n    }\n\n    private onDenominationOut(denomID: number) {\n        const btnObject = this.denominationBtns.find((item) => item.id === denomID) as {\n            inactive: Sprite;\n            active: Sprite;\n            id: number;\n        };\n        btnObject.inactive.texture = Core.assets.getAsset('denominationBntBBNormal').texture;\n    }\n\n    private onDenominationDown(denomID: number) {\n        const btnObject = this.denominationBtns.find((item) => item.id === denomID) as {\n            inactive: Sprite;\n            active: Sprite;\n            id: number;\n        };\n        btnObject.inactive.texture = Core.assets.getAsset('denominationBntBBPressed').texture;\n    }\n\n    private createButton(): void {\n        this.buyBonusBtn = new Sprite(\n            Core.assets.getTextureFromSpriteSheet(\n                'extendedMultipleBuyBonusTranslatableAssets',\n                'buyBonusBtn' + Core.ORIENTATION.value.orientation + '.png',\n            ),\n        );\n        this.buyBonusBtn.interactive = true;\n        this.buyBonusBtn.cursor = 'pointer';\n        this.buyBonusBtn.anchor.set(0.5);\n        this.buyBonusBtn.name = 'buyBonusBtn';\n        this.addChild(this.buyBonusBtn);\n    }\n\n    private createPopUp(): void {\n        this.popUpContainer = new Sprite();\n        this.popUpContainer.name = 'popUpContainer';\n        this.popUpContainer.visible = false;\n\n        this.popUpOverlay = new Graphics();\n        this.popUpOverlay\n            .beginFill(this.componentConfiguration.overlay.color, this.componentConfiguration.overlay.opacity)\n            .drawRect(0, 0, Core.display.stage.width, Core.display.stage.height)\n            .endFill();\n        this.popUpOverlay.name = 'popUpOverlay';\n        this.addChild(this.popUpOverlay);\n        this.popUpOverlay.interactive = true;\n\n        this.addChild(this.popUpContainer);\n\n        // this.popUpBackground = new Sprite(\n        //     Core.assets.getAsset('popUpBase' + Core.ORIENTATION.value.orientation).texture,\n        // );\n        this.popUpBackground = new Sprite(\n            Core.assets.getTextureFromSpriteSheet(\n                'extendedMultipleBuyBonusMainAssets',\n                'popUpBase' + Core.ORIENTATION.value.orientation + '.png',\n            ),\n        );\n        this.popUpBackground.interactive = true;\n        this.popUpBackground.name = 'popUpBackground';\n        this.popUpContainer.addChild(this.popUpBackground);\n\n        this.popUpTitle = new Sprite(\n            Core.assets.getTextureFromSpriteSheet('extendedMultipleBuyBonusTranslatableAssets', 'popUpTitle.png'),\n        );\n        this.popUpTitle.interactive = true;\n        this.popUpTitle.name = 'popUpTitle';\n        this.popUpContainer.addChild(this.popUpTitle);\n\n        if (this.componentConfiguration.bannersHaveSelectedState) {\n            this.popUpBtnClose = new Sprite(\n                Core.assets.getTextureFromSpriteSheet('extendedMultipleBuyBonusTranslatableAssets', 'cancelBtn.png'),\n            );\n            this.popUpBtnClose.name = 'popUpBtnClose';\n            this.popUpBtnClose.interactive = true;\n            this.popUpBtnClose.cursor = 'pointer';\n            this.popUpBtnClose.anchor.set(0.5);\n            this.popUpContainer.addChild(this.popUpBtnClose);\n\n            this.popUpConfirmBtn = new Sprite(\n                Core.assets.getTextureFromSpriteSheet('extendedMultipleBuyBonusTranslatableAssets', 'buyBonusBnt.png'),\n            );\n            this.popUpConfirmBtn.name = 'popUpConfirmBtn';\n            this.popUpConfirmBtn.anchor.set(0.5);\n            this.popUpContainer.addChild(this.popUpConfirmBtn);\n        } else {\n            this.popUpBtnClose = new Sprite(\n                Core.assets.getTextureFromSpriteSheet('extendedMultipleBuyBonusMainAssets', 'btnClose.png'),\n            );\n            this.popUpBtnClose.name = 'popUpBtnClose';\n            this.popUpBtnClose.interactive = true;\n            this.popUpBtnClose.cursor = 'pointer';\n            this.popUpBtnClose.anchor.set(0.5);\n            this.popUpContainer.addChild(this.popUpBtnClose);\n        }\n\n        // this.popUpInfinityConfirmBtn = new Sprite(\n        //     Core.assets.getTextureFromSpriteSheet(\n        //         'extendedMultipleBuyBonusTranslatableAssets',\n        //         'activateInfinityBtn.png',\n        //     ),\n        // );\n        // this.popUpInfinityConfirmBtn.name = 'popUpInfinityConfirmBtn';\n        // this.popUpInfinityConfirmBtn.anchor.set(0.5);\n        // this.popUpContainer.addChild(this.popUpInfinityConfirmBtn);\n\n        this.createPopUpToggle();\n        if (this.componentConfiguration.haveGuaranteedWinToggle) {\n            this.createGuaranteedWinPopUpToggle();\n            this.scaleTogglesTextScaleAndPosition(\n                this.guaranteedWinPopUpToggleBackgroundActive,\n                this.guaranteedWinPopUpToggleBackgroundInactive,\n                this.guaranteedWinPopUpToggleText,\n                this.guaranteedWinPopUpToggleActive,\n                this.guaranteedWinPopUpToggleInactive,\n                this.guaranteedWinPopUpToggleSliderActive,\n                this.guaranteedWinPopUpToggleSliderInactive,\n                true,\n            );\n            this.scaleTogglesTextScaleAndPosition(\n                this.popUpToggleBackgroundActive,\n                this.popUpToggleBackgroundInactive,\n                this.popUpToggleText,\n                this.popUpToggleActive,\n                this.popUpToggleInactive,\n                this.popUpToggleSliderActive,\n                this.popUpToggleSliderInactive,\n                false,\n            );\n            this.scaleTogglesTextToSameSize();\n        }\n    }\n\n    private createPopUpToggle(): void {\n        this.popUpToggleContainer = new Sprite();\n        this.popUpToggleContainer.name = 'popUpToggleContainer';\n        this.popUpContainer.addChild(this.popUpToggleContainer);\n\n        this.popUpToggleBackgroundActive = new NineSlicePlane(\n            Core.assets.getTextureFromSpriteSheet('extendedMultipleBuyBonusMainAssets', 'toggleBackgroundActive.png'),\n            39,\n            39,\n            39,\n            39,\n        );\n        this.popUpToggleBackgroundActive.interactive = true;\n        this.popUpToggleBackgroundActive.cursor = 'pointer';\n        this.popUpToggleBackgroundActive.alpha = 0;\n        this.popUpToggleContainer.addChild(this.popUpToggleBackgroundActive);\n\n        this.popUpToggleBackgroundInactive = new NineSlicePlane(\n            Core.assets.getTextureFromSpriteSheet('extendedMultipleBuyBonusMainAssets', 'toggleBackgroundInactive.png'),\n            39,\n            39,\n            39,\n            39,\n        );\n        this.popUpToggleBackgroundInactive.interactive = true;\n        this.popUpToggleBackgroundInactive.cursor = 'pointer';\n        this.popUpToggleBackgroundInactive.alpha = 1;\n        this.popUpToggleContainer.addChild(this.popUpToggleBackgroundInactive);\n\n        this.popUpToggleText = new Text(\n            Core.translator.translate('EXTENDED_MULTIPLE.TOGGLE_TEXT'),\n            this.componentConfiguration.toggleContainer.toggleTextStyle,\n        );\n\n        this.popUpToggleText.alpha = 0.7;\n        this.popUpToggleText.anchor.set(0, 0.5);\n        this.popUpToggleContainer.addChild(this.popUpToggleText);\n\n        this.popUpToggleActive = new Sprite(\n            Core.assets.getTextureFromSpriteSheet('extendedMultipleBuyBonusMainAssets', 'toggleActive.png'),\n        );\n        this.popUpToggleActive.anchor.set(0, 0.5);\n        this.popUpToggleActive.alpha = 0;\n        this.popUpToggleContainer.addChild(this.popUpToggleActive);\n\n        this.popUpToggleInactive = new Sprite(\n            Core.assets.getTextureFromSpriteSheet('extendedMultipleBuyBonusMainAssets', 'toggleInactive.png'),\n        );\n        this.popUpToggleInactive.anchor.set(0, 0.5);\n        this.popUpToggleInactive.alpha = 1;\n        this.popUpToggleContainer.addChild(this.popUpToggleInactive);\n\n        this.popUpToggleSliderActive = new Sprite(\n            Core.assets.getTextureFromSpriteSheet('extendedMultipleBuyBonusMainAssets', 'toggleSliderActive.png'),\n        );\n        this.popUpToggleSliderActive.anchor.set(0, 0.5);\n        this.popUpToggleSliderActive.alpha = 1;\n        this.popUpToggleContainer.addChild(this.popUpToggleSliderActive);\n\n        this.popUpToggleSliderInactive = new Sprite(\n            Core.assets.getTextureFromSpriteSheet('extendedMultipleBuyBonusMainAssets', 'toggleSliderInactive.png'),\n        );\n        this.popUpToggleSliderInactive.anchor.set(0, 0.5);\n        this.popUpToggleSliderInactive.alpha = 1;\n        this.popUpToggleContainer.addChild(this.popUpToggleSliderInactive);\n    }\n\n    private createGuaranteedWinPopUpToggle(): void {\n        this.guaranteedWinPopUpToggleContainer = new Sprite();\n        this.guaranteedWinPopUpToggleContainer.name = 'guaranteedWinPopUpToggleContainer';\n        this.popUpContainer.addChild(this.guaranteedWinPopUpToggleContainer);\n\n        this.guaranteedWinPopUpToggleBackgroundActive = new NineSlicePlane(\n            Core.assets.getTextureFromSpriteSheet('extendedMultipleBuyBonusMainAssets', 'toggleBackgroundActive.png'),\n            39,\n            39,\n            39,\n            39,\n        );\n        this.guaranteedWinPopUpToggleBackgroundActive.interactive = true;\n        this.guaranteedWinPopUpToggleBackgroundActive.cursor = 'pointer';\n        this.guaranteedWinPopUpToggleBackgroundActive.alpha = 0;\n        this.guaranteedWinPopUpToggleContainer.addChild(this.guaranteedWinPopUpToggleBackgroundActive);\n\n        this.guaranteedWinPopUpToggleBackgroundInactive = new NineSlicePlane(\n            Core.assets.getTextureFromSpriteSheet('extendedMultipleBuyBonusMainAssets', 'toggleBackgroundInactive.png'),\n            39,\n            39,\n            39,\n            39,\n        );\n        this.guaranteedWinPopUpToggleBackgroundInactive.interactive = true;\n        this.guaranteedWinPopUpToggleBackgroundInactive.cursor = 'pointer';\n        this.guaranteedWinPopUpToggleBackgroundInactive.alpha = 1;\n        this.guaranteedWinPopUpToggleContainer.addChild(this.guaranteedWinPopUpToggleBackgroundInactive);\n\n        this.guaranteedWinPopUpToggleText = new Text(\n            Core.translator.translate('EXTENDED_MULTIPLE.GUARANTEED_WIN_TOGGLE_TEXT'),\n            this.componentConfiguration.guaranteedWinToggleContainer.toggleTextStyle,\n        );\n        this.guaranteedWinPopUpToggleText.anchor.set(0, 0.5);\n        this.guaranteedWinPopUpToggleText.alpha = 0.7;\n        this.guaranteedWinPopUpToggleContainer.addChild(this.guaranteedWinPopUpToggleText);\n\n        this.guaranteedWinPopUpToggleActive = new Sprite(\n            Core.assets.getTextureFromSpriteSheet('extendedMultipleBuyBonusMainAssets', 'toggleActive.png'),\n        );\n        this.guaranteedWinPopUpToggleActive.anchor.set(0, 0.5);\n        this.guaranteedWinPopUpToggleActive.alpha = 0;\n        this.guaranteedWinPopUpToggleContainer.addChild(this.guaranteedWinPopUpToggleActive);\n\n        this.guaranteedWinPopUpToggleInactive = new Sprite(\n            Core.assets.getTextureFromSpriteSheet('extendedMultipleBuyBonusMainAssets', 'toggleInactive.png'),\n        );\n        this.guaranteedWinPopUpToggleInactive.anchor.set(0, 0.5);\n        this.guaranteedWinPopUpToggleInactive.alpha = 1;\n        this.guaranteedWinPopUpToggleContainer.addChild(this.guaranteedWinPopUpToggleInactive);\n\n        this.guaranteedWinPopUpToggleSliderActive = new Sprite(\n            Core.assets.getTextureFromSpriteSheet('extendedMultipleBuyBonusMainAssets', 'toggleSliderActive.png'),\n        );\n        this.guaranteedWinPopUpToggleSliderActive.anchor.set(0, 0.5);\n        this.guaranteedWinPopUpToggleSliderActive.alpha = 1;\n        this.guaranteedWinPopUpToggleContainer.addChild(this.guaranteedWinPopUpToggleSliderActive);\n\n        this.guaranteedWinPopUpToggleSliderInactive = new Sprite(\n            Core.assets.getTextureFromSpriteSheet('extendedMultipleBuyBonusMainAssets', 'toggleSliderInactive.png'),\n        );\n        this.guaranteedWinPopUpToggleSliderInactive.anchor.set(0, 0.5);\n        this.guaranteedWinPopUpToggleSliderInactive.alpha = 1;\n        this.guaranteedWinPopUpToggleContainer.addChild(this.guaranteedWinPopUpToggleSliderInactive);\n    }\n\n    private createPopUpBanners(banners: BannerData[], bet: number, denomination: number): void {\n        for (const bannerData of banners) {\n            const banner: ExtendedMultipleBuyBonusBanner = new ExtendedMultipleBuyBonusBanner(\n                bannerData,\n                this.rootStore.settings.currency,\n                bet,\n                denomination,\n                this.componentConfiguration,\n            );\n            this.popUpBanners.push(banner);\n            this.popUpContainer.addChild(banner);\n        }\n    }\n\n    private setConfirmBtnState(active: boolean): void {\n        if (!this.componentConfiguration.bannersHaveSelectedState) {\n            return;\n        }\n        if (active) {\n            this.popUpConfirmBtn.interactive = true;\n            this.popUpConfirmBtn.cursor = 'pointer';\n            this.popUpConfirmBtn.tint = 0xffffff;\n            // this.popUpInfinityConfirmBtn.interactive = true;\n            // this.popUpInfinityConfirmBtn.cursor = 'pointer';\n            // this.popUpInfinityConfirmBtn.tint = 0xffffff;\n        } else {\n            this.popUpConfirmBtn.interactive = false;\n            this.popUpConfirmBtn.cursor = 'normal';\n            this.popUpConfirmBtn.tint = this.componentConfiguration.tintColor;\n            // this.popUpInfinityConfirmBtn.interactive = false;\n            // this.popUpInfinityConfirmBtn.cursor = 'normal';\n            // this.popUpInfinityConfirmBtn.tint = this.componentConfiguration.tintColor;\n        }\n    }\n\n    private createBetPanel(): void {\n        this.betPanel = new ExtendedMultipleBuyBonusBetControl(\n            this.rootStore.settings.currency,\n            this.componentConfiguration,\n        );\n        this.popUpContainer.addChild(this.betPanel);\n    }\n\n    private createBalanceContainer(): void {\n        this.balanceContainer = new Sprite();\n        this.balanceContainer.name = 'balanceContainer';\n        this.popUpContainer.addChild(this.balanceContainer);\n        this.balanceText = new Text(\n            Core.translator.translate('EXTENDED_MULTIPLE.BUY_BONUS.BALANCE'),\n            this.componentConfiguration.balancePositions.balanceTextStyle,\n        );\n        this.balanceText.name = 'balanceText';\n        this.balanceText.anchor.set(0, 1);\n        this.balanceContainer.addChild(this.balanceText);\n\n        this.balanceValue = new Text('', this.componentConfiguration.balancePositions.balanceValueStyle);\n        this.balanceValue.name = 'balanceValue';\n        this.balanceValue.x = this.balanceText.width + this.componentConfiguration.balancePositions.wordSpacing;\n        this.balanceValue.anchor.set(0, 1);\n        this.balanceContainer.addChild(this.balanceValue);\n\n        this.balanceCurrency = new Text(\n            this.settings.currency,\n            this.componentConfiguration.balancePositions.balanceCurrencyStyle,\n        );\n        this.balanceCurrency.name = 'balanceCurrency';\n        this.balanceCurrency.anchor.set(0, 1);\n        this.balanceContainer.addChild(this.balanceCurrency);\n    }\n\n    private createConfirmationPopUp(): void {\n        this.confirmationPopUpContainer = new Sprite();\n        this.confirmationPopUpContainer.name = 'confirmationPopUpContainer';\n        this.addChild(this.confirmationPopUpContainer);\n\n        this.confirmationPopUpOverlay = new Graphics();\n        this.confirmationPopUpOverlay\n            .beginFill(this.componentConfiguration.overlay.color, this.componentConfiguration.overlay.opacity)\n            .drawRect(0, 0, Core.display.stage.width, Core.display.stage.height)\n            .endFill();\n        this.confirmationPopUpOverlay.name = 'confirmationPopUpOverlay';\n        this.confirmationPopUpContainer.addChild(this.confirmationPopUpOverlay);\n        this.confirmationPopUpOverlay.interactive = true;\n\n        this.confirmationPopUpBackground = new Sprite(Core.assets.getAsset('confirmationPopUpBase').texture);\n        this.confirmationPopUpBackground.name = 'confirmationPopUpBackground';\n        this.confirmationPopUpBackground.interactive = true;\n        this.confirmationPopUpContainer.addChild(this.confirmationPopUpBackground);\n\n        // this.confirmationPopUpTitle = new Sprite(Core.assets.getTextureFromSpriteSheet('extendedMultipleBuyBonusTranslatableAssets','confirmationPopUpTitle0.png'));\n        this.confirmationPopUpTitle = new Sprite();\n        this.confirmationPopUpTitle.name = 'confirmationPopUpTitle';\n        this.confirmationPopUpContainer.addChild(this.confirmationPopUpTitle);\n\n        this.confirmationPopUpDescriptionText = new Text('15 FREE SPINS with multiplier symbols\\nfrom x2 to x500');\n        this.confirmationPopUpDescriptionText.name = 'confirmationPopUpDescriptionText';\n        this.confirmationPopUpDescriptionText.anchor.set(0.5);\n        this.confirmationPopUpContainer.addChild(this.confirmationPopUpDescriptionText);\n\n        this.confirmationPopUpValueText = new Text('5 000EGT');\n        this.confirmationPopUpValueText.name = 'confirmationPopUpValueText';\n        this.confirmationPopUpValueText.anchor.set(0.5);\n        this.confirmationPopUpContainer.addChild(this.confirmationPopUpValueText);\n\n        this.confirmationPopUpValueDescriptionText = new Text('Will be substracted from your balance.');\n        this.confirmationPopUpValueDescriptionText.name = 'confirmationPopUpValueDescriptionText';\n        this.confirmationPopUpValueDescriptionText.anchor.set(0.5);\n        this.confirmationPopUpContainer.addChild(this.confirmationPopUpValueDescriptionText);\n\n        this.confirmationPopUpConfirmBtn = new Sprite(Core.assets.getAsset('btnConfirmActive').texture);\n        this.confirmationPopUpConfirmBtn.interactive = true;\n        this.confirmationPopUpConfirmBtn.cursor = 'pointer';\n        this.confirmationPopUpConfirmBtn.name = 'confirmationPopUpConfirmBtn';\n        this.confirmationPopUpContainer.addChild(this.confirmationPopUpConfirmBtn);\n\n        this.confirmationPopUpConfirmBtnText = new Sprite(\n            Core.assets.getTextureFromSpriteSheet('extendedMultipleBuyBonusTranslatableAssets', 'activateBtnText.png'),\n        );\n        this.confirmationPopUpConfirmBtnText.anchor.set(0.5);\n        this.confirmationPopUpConfirmBtnText.name = 'confirmationPopUpConfirmBtnText';\n        this.confirmationPopUpContainer.addChild(this.confirmationPopUpConfirmBtnText);\n\n        this.confirmationPopUpBackBtn = new Sprite(Core.assets.getAsset('bntBack').texture);\n        this.confirmationPopUpBackBtn.interactive = true;\n        this.confirmationPopUpBackBtn.cursor = 'pointer';\n        this.confirmationPopUpBackBtn.name = 'confirmationPopUpBackBtn';\n        this.confirmationPopUpContainer.addChild(this.confirmationPopUpBackBtn);\n\n        this.confirmationPopUpBackBtnText = new Sprite(\n            Core.assets.getTextureFromSpriteSheet('extendedMultipleBuyBonusTranslatableAssets', 'backBtnText.png'),\n        );\n        this.confirmationPopUpBackBtnText.anchor.set(0.5);\n        this.confirmationPopUpBackBtnText.name = 'confirmationPopUpBackBtnText';\n        this.confirmationPopUpContainer.addChild(this.confirmationPopUpBackBtnText);\n\n        this.confirmationPopUpCheckBox = new Sprite(Core.assets.getAsset('checkBoxUnchecked').texture);\n        this.confirmationPopUpCheckBox.interactive = true;\n        this.confirmationPopUpCheckBox.cursor = 'pointer';\n        this.confirmationPopUpCheckBox.name = 'confirmationPopUpCheckbox';\n        this.confirmationPopUpContainer.addChild(this.confirmationPopUpCheckBox);\n\n        this.confirmationPopUpDontShowText = new Text('Do nоt show again');\n        this.confirmationPopUpDontShowText.name = 'confirmationPopUpDontShowText';\n        this.confirmationPopUpDontShowText.anchor.set(0.5);\n        this.confirmationPopUpContainer.addChild(this.confirmationPopUpDontShowText);\n\n        this.confirmationPopUpContainer.visible = false;\n    }\n\n    private createOutsideBet(): void {\n        this.betOutsideContainer = new Sprite();\n        this.betOutsideContainer.name = 'betOutsideContainer';\n        this.addChild(this.betOutsideContainer);\n\n        this.betOutsideBase = new Sprite(Core.assets.getAsset('betOutsideBase').texture);\n        this.betOutsideBase.name = 'betOutsideBase';\n        this.betOutsideContainer.addChild(this.betOutsideBase);\n\n        this.betOutsideBetContainer = new Sprite();\n        this.betOutsideBetContainer.anchor.set(0.5);\n        this.betOutsideBetContainer.name = 'betOutsideBetContainer';\n        this.betOutsideContainer.addChild(this.betOutsideBetContainer);\n\n        this.betOutsideDecreaseBtn = new Sprite(Core.assets.getAsset('arrowOutsideMinus').texture);\n        this.betOutsideDecreaseBtn.interactive = true;\n        // this.betOutsideDecreaseBtn.cursor = 'pointer';\n        this.betOutsideDecreaseBtn.name = 'betOutsideDecreaseBtn';\n        this.betOutsideDecreaseBtn.anchor.set(0, 0.5);\n        this.betOutsideContainer.addChild(this.betOutsideDecreaseBtn);\n\n        this.betOutsideIncreaseBtn = new Sprite(Core.assets.getAsset('arrowOutsidePlus').texture);\n        this.betOutsideIncreaseBtn.interactive = true;\n        // this.betOutsideIncreaseBtn.cursor = 'pointer';\n        this.betOutsideIncreaseBtn.name = 'betOutsideIncreaseBtn';\n        this.betOutsideIncreaseBtn.anchor.set(0, 0.5);\n        this.betOutsideContainer.addChild(this.betOutsideIncreaseBtn);\n\n        this.betOutsideTotalBetValue = new Text(\n            '',\n            this.componentConfiguration.betOutsidePanel.betOutsideTotalBetValueStyle,\n        );\n        this.betOutsideTotalBetValue.anchor.set(0, 1);\n        this.betOutsideTotalBetValue.name = 'betOutsideTotalBetValue';\n        this.betOutsideBetContainer.addChild(this.betOutsideTotalBetValue);\n\n        this.betOutsideTotalBetCurrency = new Text(\n            this.rootStore.settings.currency,\n            this.componentConfiguration.betOutsidePanel.betOutsideTotalBetCurrencyStyle,\n        );\n        this.betOutsideTotalBetCurrency.anchor.set(0, 1);\n        this.betOutsideTotalBetCurrency.name = 'betOutsideBetText';\n        this.betOutsideBetContainer.addChild(this.betOutsideTotalBetCurrency);\n\n        this.betOutsideBetInfo = new Text('', this.componentConfiguration.betOutsidePanel.betOutsideBetInfoStyle);\n        this.betOutsideBetInfo.anchor.set(0.5);\n        this.betOutsideBetInfo.name = 'betOutsideBetInfo';\n        this.betOutsideContainer.addChild(this.betOutsideBetInfo);\n\n        this.betOutsideContainer.visible = false;\n    }\n\n    private createInfoText(): void {\n        this.infoText = new ExtendedMultipleBuyBonusInfoText(this.componentConfiguration);\n        this.addChild(this.infoText);\n    }\n\n    private onToggleClicked(): void {\n        this.stateMachineService.send('ON_TOGGLE_CLICKED');\n        // Core.sounds.play('buyBonusClosed');\n    }\n\n    private onGuaranteedWinToggleClicked(): void {\n        this.stateMachineService.send('ON_GUARANTEED_TOGGLE_CLICKED');\n        // Core.sounds.play('buyBonusClosed');\n    }\n\n    private onPopUpCancelClicked(): void {\n        this.stateMachineService.send('CLOSE_POPUP');\n        Core.sounds.play('buyBonusClosed');\n    }\n\n    private onBuyBonusBtnClicked(): void {\n        // this.stateMachineService.send('BUY_BONUS_BTN_CLICKED');\n        this.stateMachineService.send('COLLECT_BEFORE_OPEN');\n    }\n\n    private onDoubleBtnChanceClicked(): void {\n        // this.stateMachineService.send('DOUBLE_CHANCE_CLICKED');\n        this.stateMachineService.send('COLLECT_BEFORE_ACTIVATE_DOUBLE_CHANCE');\n    }\n\n    private onDoubleChanceBannerClicked(): void {\n        this.stateMachineService.send('DOUBLE_CHANCE_CLICKED');\n    }\n\n    protected onBonusSelected(id: number, gameMode: string, bonusFactor: number): void {\n        this.setSelectedBanner(id);\n        this.stateMachineService.send({ type: 'BONUS_SELECTED', bonusId: id });\n        if (!this.componentConfiguration.bannersHaveSelectedState) {\n            if (\n                gameMode === 'DOUBLE_CHANCE' ||\n                (this.settings.haveGameMode('DOUBLE_CHANCE') &&\n                    bonusFactor === this.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE'))\n            ) {\n                this.onDoubleChanceBannerClicked();\n            } else {\n                this.onBonusChosen();\n            }\n        }\n    }\n\n    public setSelectedBanner(id: number): void {\n        if (!this.componentConfiguration.bannersHaveSelectedState) {\n            return;\n        }\n        for (const popUpBanner of this.popUpBanners) {\n            popUpBanner.setSelected(popUpBanner.bannerId === id);\n        }\n    }\n\n    public updateInfoTextOffset(offset): void {\n        this.infoText.infoMessageYOffsetLandscape(offset);\n    }\n\n    public updateToggleState(toggleStat: 'Active' | 'Inactive'): void {\n        this.popUpToggleState = toggleStat;\n        this.popUpToggleTimeLine = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus.ts:823:36\",null]), gsap.timeline({\n            onComplete: () => {\n                this.popUpToggleTimeLine = null;\n            },\n        }));\n\n        if (toggleStat === 'Active') {\n            Core.sounds.play('toggleOn');\n            this.popUpToggleTimeLine.to(\n                [this.popUpToggleBackgroundActive, this.popUpToggleActive],\n                {\n                    alpha: 1,\n                    duration: 0.3,\n                },\n                0,\n            );\n            this.popUpToggleTimeLine.to(\n                [this.popUpToggleBackgroundInactive, this.popUpToggleInactive],\n                {\n                    alpha: 0,\n                    duration: 0.3,\n                },\n                0,\n            );\n            this.popUpToggleTimeLine.to(\n                [this.popUpToggleSliderActive, this.popUpToggleSliderInactive],\n                {\n                    x: this.popUpToggleActive.x + 51,\n                    duration: 0.3,\n                },\n                0,\n            );\n            this.popUpToggleTimeLine.to(\n                this.popUpToggleText,\n                {\n                    alpha: 1,\n                    duration: 0.3,\n                },\n                0,\n            );\n            this.popUpToggleTimeLine.to(\n                this.popUpToggleSliderActive,\n                {\n                    alpha: 1,\n                    duration: 0.1,\n                },\n                0.3,\n            );\n            this.popUpToggleTimeLine.to(\n                this.popUpToggleSliderInactive,\n                {\n                    alpha: 0,\n                    duration: 0.1,\n                },\n                0.4,\n            );\n        } else {\n            Core.sounds.play('toggleOff');\n            this.popUpToggleTimeLine.to(\n                [this.popUpToggleBackgroundActive, this.popUpToggleActive],\n                {\n                    alpha: 0,\n                    duration: 0.3,\n                },\n                0,\n            );\n            this.popUpToggleTimeLine.to(\n                [this.popUpToggleBackgroundInactive, this.popUpToggleInactive],\n                {\n                    alpha: 1,\n                    duration: 0.3,\n                },\n                0,\n            );\n            this.popUpToggleTimeLine.to(\n                [this.popUpToggleSliderActive, this.popUpToggleSliderInactive],\n                {\n                    x: this.popUpToggleActive.x + 7,\n                    duration: 0.3,\n                },\n                0,\n            );\n            this.popUpToggleTimeLine.to(\n                this.popUpToggleText,\n                {\n                    alpha: 0.7,\n                    duration: 0.3,\n                },\n                0,\n            );\n            this.popUpToggleTimeLine.to(\n                this.popUpToggleSliderActive,\n                {\n                    alpha: 0,\n                    duration: 0.1,\n                },\n                0.4,\n            );\n            this.popUpToggleTimeLine.to(\n                this.popUpToggleSliderInactive,\n                {\n                    alpha: 1,\n                    duration: 0.1,\n                },\n                0.3,\n            );\n        }\n    }\n\n    public guaranteedWinUpdateToggleState(toggleStat: 'Active' | 'Inactive'): void {\n        this.guaranteedWinPopUpToggleTimeLine = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus.ts:933:49\",null]), gsap.timeline({\n            onComplete: () => {\n                this.guaranteedWinPopUpToggleTimeLine = null;\n            },\n        }));\n\n        if (toggleStat === 'Active') {\n            Core.sounds.play('toggleOn');\n            this.guaranteedWinPopUpToggleTimeLine.to(\n                [this.guaranteedWinPopUpToggleBackgroundActive, this.guaranteedWinPopUpToggleActive],\n                {\n                    alpha: 1,\n                    duration: 0.3,\n                },\n                0,\n            );\n            this.guaranteedWinPopUpToggleTimeLine.to(\n                [this.guaranteedWinPopUpToggleBackgroundInactive, this.guaranteedWinPopUpToggleInactive],\n                {\n                    alpha: 0,\n                    duration: 0.3,\n                },\n                0,\n            );\n            this.guaranteedWinPopUpToggleTimeLine.to(\n                [this.guaranteedWinPopUpToggleSliderActive, this.guaranteedWinPopUpToggleSliderInactive],\n                {\n                    x: this.guaranteedWinPopUpToggleActive.x + 51,\n                    duration: 0.3,\n                },\n                0,\n            );\n            this.guaranteedWinPopUpToggleTimeLine.to(\n                this.guaranteedWinPopUpToggleText,\n                {\n                    alpha: 1,\n                    duration: 0.3,\n                },\n                0,\n            );\n            this.guaranteedWinPopUpToggleTimeLine.to(\n                this.guaranteedWinPopUpToggleSliderActive,\n                {\n                    alpha: 1,\n                    duration: 0.1,\n                },\n                0.3,\n            );\n            this.guaranteedWinPopUpToggleTimeLine.to(\n                this.guaranteedWinPopUpToggleSliderInactive,\n                {\n                    alpha: 0,\n                    duration: 0.1,\n                },\n                0.4,\n            );\n        } else {\n            Core.sounds.play('toggleOff');\n            this.guaranteedWinPopUpToggleTimeLine.to(\n                [this.guaranteedWinPopUpToggleBackgroundActive, this.guaranteedWinPopUpToggleActive],\n                {\n                    alpha: 0,\n                    duration: 0.3,\n                },\n                0,\n            );\n            this.guaranteedWinPopUpToggleTimeLine.to(\n                [this.guaranteedWinPopUpToggleBackgroundInactive, this.guaranteedWinPopUpToggleInactive],\n                {\n                    alpha: 1,\n                    duration: 0.3,\n                },\n                0,\n            );\n            this.guaranteedWinPopUpToggleTimeLine.to(\n                [this.guaranteedWinPopUpToggleSliderActive, this.guaranteedWinPopUpToggleSliderInactive],\n                {\n                    x: this.guaranteedWinPopUpToggleActive.x + 7,\n                    duration: 0.3,\n                },\n                0,\n            );\n            this.guaranteedWinPopUpToggleTimeLine.to(\n                this.guaranteedWinPopUpToggleText,\n                {\n                    alpha: 0.7,\n                    duration: 0.3,\n                },\n                0,\n            );\n            this.guaranteedWinPopUpToggleTimeLine.to(\n                this.guaranteedWinPopUpToggleSliderActive,\n                {\n                    alpha: 0,\n                    duration: 0.1,\n                },\n                0.4,\n            );\n            this.guaranteedWinPopUpToggleTimeLine.to(\n                this.guaranteedWinPopUpToggleSliderInactive,\n                {\n                    alpha: 1,\n                    duration: 0.1,\n                },\n                0.3,\n            );\n        }\n    }\n\n    protected onBonusChosen(): void {\n        // this.stateMachineService.send({ type: 'SET_BONUS_ACTIVATION_TYPE', value: 'once' });\n        this.stateMachineService.send({ type: 'BONUS_CHOSEN' });\n        Core.sounds.play('buyBonusActivate');\n    }\n    // private onInfinityBonusChosen(): void {\n    //     this.stateMachineService.send({ type: 'SET_BONUS_ACTIVATION_TYPE', value: 'infinity' });\n    //     this.stateMachineService.send({ type: 'BONUS_CHOSEN' });\n    //     Core.sounds.play('buyBonusActivate');\n    // }\n\n    private onDecreaseBetAmount(): void {\n        Core.sounds.play('buyBonusDecreaseBtn');\n        this.stateMachineService.send('DECREASE_BET');\n    }\n\n    private onIncreaseBetAmount(): void {\n        Core.sounds.play('buyBonusIncreaseBtn');\n        this.stateMachineService.send('INCREASE_BET');\n    }\n\n    private onConfirmClicked(): void {\n        this.stateMachineService.send('CONFIRMATION_POPUP_CONFIRM');\n    }\n\n    private onBackClicked(): void {\n        this.stateMachineService.send('CONFIRMATION_POPUP_BACK');\n    }\n\n    private onCloseConfirmationPopUp(): void {\n        this.stateMachineService.send('CONFIRMATION_POPUP_CLOSE');\n    }\n\n    private onConfirmationCheckBoxClicked(): void {\n        this.stateMachineService.send('CONFIRMATION_CHECK_BOX_CLICKED');\n    }\n\n    private onOutsideIncreaseBtn(): void {\n        Core.sounds.play('buyBonusIncreaseBtn');\n        this.stateMachineService.send('OUTSIDE_INCREASE_BTN_CLICKED');\n    }\n\n    private onOutsideDecreaseBtn(): void {\n        Core.sounds.play('buyBonusDecreaseBtn');\n        this.stateMachineService.send('OUTSIDE_DECREASE_BTN_CLICKED');\n    }\n\n    public enableAllBanners(): void {\n        for (const banner of this.popUpBanners) {\n            banner.enable = true;\n        }\n    }\n\n    public openPopUp(): void {\n        if (this.showTimeLine) {\n            this.showTimeLine.totalProgress(1);\n        }\n        if (this.hideTimeLine) {\n            this.hideTimeLine.totalProgress(1);\n        }\n        const originalYPosition = this.popUpContainer.y;\n        this.popUpContainer.visible = true;\n        this.popUpOverlay.visible = true;\n        this.popUpContainer.y = this.popUpContainer.y + 250;\n        this.popUpContainer.alpha = 0;\n        this.popUpOverlay.alpha = 0;\n\n        this.showTimeLine = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus.ts:1109:29\",null]), gsap.timeline({\n            onComplete: () => {\n                if (this.showTimeLine) {\n                    this.showTimeLine.kill();\n                }\n                this.showTimeLine = null;\n            },\n        }));\n\n        this.showTimeLine.to(\n            [this.popUpContainer, this.popUpOverlay],\n            {\n                alpha: 1,\n                duration: 0.3,\n            },\n            0,\n        );\n        this.showTimeLine.to(\n            this.popUpContainer,\n            {\n                y: this.popUpContainer.y - 265,\n                duration: 0.25,\n                ease: 'power1.out',\n            },\n            0,\n        );\n        this.showTimeLine.to(\n            this.popUpContainer,\n            {\n                y: originalYPosition,\n                duration: 0.2,\n                ease: 'power1.in',\n            },\n            0.25,\n        );\n    }\n\n    public closePopUp(): void {\n        if (this.showTimeLine) {\n            this.showTimeLine.totalProgress(1);\n        }\n        if (this.hideTimeLine) {\n            this.hideTimeLine.totalProgress(1);\n        }\n        const originalYPosition: number = this.popUpContainer.y;\n\n        this.hideTimeLine = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus.ts:1155:29\",null]), gsap.timeline({\n            onComplete: () => {\n                this.popUpContainer.visible = false;\n                this.popUpOverlay.visible = false;\n\n                this.popUpContainer.alpha = 1;\n                this.popUpOverlay.alpha = 1;\n                this.stateMachineService.send('POP_UP_CLOSED');\n\n                this.popUpContainer.y = originalYPosition;\n                if (this.hideTimeLine) {\n                    this.hideTimeLine.kill();\n                }\n                this.hideTimeLine = null;\n            },\n        }));\n\n        this.hideTimeLine.to(\n            this.popUpContainer,\n            {\n                alpha: 0,\n                y: 250,\n                duration: 0.3,\n            },\n            0,\n        );\n\n        this.hideTimeLine.to(\n            this.popUpOverlay,\n            {\n                alpha: 0,\n                duration: 0.3,\n            },\n            0,\n        );\n    }\n\n    public deactivateDoubleChance(): void {\n        this.doubleChanceState = 'Inactive';\n        this.updateDoubleChanceBtnTexture();\n    }\n\n    public activateDoubleChance(): void {\n        this.doubleChanceState = 'Active';\n        this.updateDoubleChanceBtnTexture();\n    }\n\n    private updateDoubleChanceBtnTexture(): void {\n        if (!this.doubleChanceButton) {\n            return;\n        }\n        this.doubleChanceButton.texture = Core.assets.getTextureFromSpriteSheet(\n            'extendedMultipleBuyBonusTranslatableAssets',\n            'x2Btn' + this.doubleChanceState + Core.ORIENTATION.value.orientation + '.png',\n        );\n    }\n\n    public openConfirmationPopUp(bannerData: BannerData, betValueText: string): void {\n        this.confirmationPopUpTitle.texture = Core.assets.getTextureFromSpriteSheet(\n            'extendedMultipleBuyBonusTranslatableAssets',\n            'confirmationPopUpTitle' + bannerData.bannerId + '.png',\n        );\n        const btnText: string = bannerData.shouldBuy ? 'buyBtnText.png' : 'activateBtnText.png';\n        this.confirmationPopUpConfirmBtnText.texture = Core.assets.getTextureFromSpriteSheet(\n            'extendedMultipleBuyBonusTranslatableAssets',\n            btnText,\n        );\n        this.confirmationPopUpContainer.visible = true;\n        this.confirmationPopUpValueText.text = betValueText;\n        this.confirmationPopUpDescriptionText.text = Core.translator.translate(\n            'BUY_BONUS_CONFIRMATION_DESCRIPTION_' + bannerData.bannerId,\n        );\n    }\n\n    public closeConfirmationPopUp(): void {\n        this.confirmationPopUpContainer.visible = false;\n    }\n\n    public showActivated(bonusType: BannerData, showOutsideBetInfo: boolean): void {\n        this.buyBonusTextureType = 'buyBonusBtnActive' + bonusType.bannerId;\n        this.buyBonusBtn.texture = Core.assets.getTextureFromSpriteSheet(\n            'extendedMultipleBuyBonusTranslatableAssets',\n            'buyBonusBtnActive' + bonusType.bannerId + Core.ORIENTATION.value.orientation + '.png',\n        );\n\n        if (showOutsideBetInfo) {\n            this.betOutsideBetInfo.text = Core.translator.translate(bonusType.betText);\n            this.resizeOutsideBetInfoText();\n            this.betOutsideContainer.visible = true;\n        }\n    }\n\n    public showReady(): void {\n        this.buyBonusTextureType = 'buyBonusBtn';\n        this.buyBonusBtn.texture = Core.assets.getTextureFromSpriteSheet(\n            'extendedMultipleBuyBonusTranslatableAssets',\n            'buyBonusBtn' + Core.ORIENTATION.value.orientation + '.png',\n        );\n        this.betOutsideContainer.visible = false;\n    }\n\n    public showBuyBtn(): void {\n        this.buyBonusBtn.visible = true;\n        if (this.doubleChanceButton) {\n            this.doubleChanceButton.visible = true;\n        }\n    }\n\n    public hideBuyBtn(): void {\n        this.buyBonusBtn.visible = false;\n        if (this.doubleChanceButton) {\n            this.doubleChanceButton.visible = false;\n        }\n    }\n\n    public enabled(): void {\n        if (this.componentConfiguration.buyBonusBtn.useOpacityForDisable) {\n            this.buyBonusBtn.alpha = 1;\n            if (this.doubleChanceButton) {\n                this.doubleChanceButton.alpha = 1;\n            }\n        } else {\n            this.buyBonusBtn.tint = 0xffffff;\n            if (this.doubleChanceButton) {\n                this.doubleChanceButton.tint = 0xffffff;\n            }\n        }\n        if (!this.lastBet) {\n            this.disableOutsideIncreaseBtn(false);\n        }\n        if (!this.firstBet) {\n            this.disableOutsideDecreaseBtn(false);\n        }\n        this.buyBonusBtn.interactive = true;\n        this.buyBonusBtn.cursor = 'pointer';\n        if (this.doubleChanceButton) {\n            this.doubleChanceButton.interactive = true;\n            this.doubleChanceButton.cursor = 'pointer';\n        }\n    }\n    public disabled(doNotChangeVisible: boolean = false): void {\n        if (!doNotChangeVisible) {\n            if (this.componentConfiguration.buyBonusBtn.useOpacityForDisable) {\n                this.buyBonusBtn.alpha = 0.7;\n                if (this.doubleChanceButton) {\n                    this.doubleChanceButton.alpha = 0.7;\n                }\n            } else {\n                this.buyBonusBtn.tint = this.componentConfiguration.tintColor;\n                if (this.doubleChanceButton) {\n                    this.doubleChanceButton.tint = this.componentConfiguration.tintColor;\n                }\n            }\n        }\n        this.disableOutsideDecreaseBtn(true);\n        this.disableOutsideIncreaseBtn(true);\n        this.setBetOutsideDecreaseBtnGraphics(false);\n        this.setBetOutsideIncreaseBtnGraphics(false);\n        this.buyBonusBtn.interactive = false;\n        this.buyBonusBtn.cursor = 'normal';\n        if (this.doubleChanceButton) {\n            this.doubleChanceButton.interactive = false;\n            this.doubleChanceButton.cursor = 'normal';\n        }\n    }\n\n    public updateBets(\n        betMoney: number,\n        bet: number,\n        denomination: number,\n        activeBannerId: number,\n        guaranteedWinActivated: boolean,\n    ): void {\n        this.betPanel.updateBet(betMoney);\n        if (!this.componentConfiguration.skipSameBets) {\n            this.updateDenomination(denomination);\n        }\n        let haveActiveBanner: boolean = false;\n        let haveSelectBanner: boolean = false;\n        // let selectNextAvailableBanner: boolean = false;\n        let bannerValueMinScale: number = 1;\n        for (const banner of this.popUpBanners) {\n            banner.updateBet(bet, denomination, this.rootStore.uiStore.BALANCE.value, guaranteedWinActivated);\n            if (banner.buyValueScale < bannerValueMinScale) {\n                bannerValueMinScale = banner.buyValueScale;\n            }\n            if (banner.enable) {\n                haveActiveBanner = true;\n            }\n            if (!banner.enable && banner.bannerId === activeBannerId) {\n                haveSelectBanner = false;\n                banner.setSelected(false);\n                this.stateMachineService.send({ type: 'BONUS_SELECTED', bonusId: -1 });\n                this.updateBets(betMoney, bet, denomination, -1, guaranteedWinActivated);\n                return;\n                // selectNextAvailableBanner = true;\n            }\n            if (activeBannerId < 0 && !haveSelectBanner && banner.enable) {\n                haveSelectBanner = true;\n                banner.setSelected(true);\n                this.stateMachineService.send({ type: 'BONUS_SELECTED', bonusId: banner.bannerId });\n            }\n        }\n        // update all banners to have same scales for buy value\n        for (const banner of this.popUpBanners) {\n            banner.updateScaleValueToBeSameForAll(bannerValueMinScale);\n        }\n        if (!haveActiveBanner) {\n            this.stateMachineService.send({ type: 'BONUS_SELECTED', bonusId: -1 });\n        }\n\n        this.setConfirmBtnState(haveActiveBanner);\n        // this.stateMachineService.send({ type: 'BONUS_SELECTED', bonusId: this.choseAvailableBonusForSelection() });\n    }\n\n    public updatePopUpBalance(balance: string): void {\n        this.balanceValue.text = balance;\n        this.setBalancePosition();\n    }\n\n    public updateOutsideBet(totalBetMoney: string): void {\n        this.betOutsideTotalBetValue.text = totalBetMoney;\n        // this.betOutsideBetValue.text = betMoney;\n        this.setBetOutsidePosition();\n    }\n\n    public disableDecreaseBtn(disabled: boolean): void {\n        this.betPanel.disableDecreaseBtn(disabled);\n    }\n\n    public disableIncreaseBtn(disabled: boolean): void {\n        this.betPanel.disableIncreaseBtn(disabled);\n    }\n\n    public disableOutsideDecreaseBtn(disabled: boolean): void {\n        if (disabled) {\n            this.betOutsideDecreaseBtn.tint = this.componentConfiguration.tintColor;\n            this.setBetOutsideDecreaseBtnGraphics(false);\n        } else {\n            this.betOutsideDecreaseBtn.tint = 0xffffff;\n            this.setBetOutsideDecreaseBtnGraphics(true);\n        }\n        // this.betOutsideDecreaseBtn.texture = disabled\n        //     ? Core.assets.getAsset('arrowMinusInactive').texture\n        //     : Core.assets.getAsset('arrowMinusActive').texture;\n        // this.betOutsideDecreaseBtn.interactive = !disabled;\n    }\n\n    public disableOutsideIncreaseBtn(disabled: boolean): void {\n        if (disabled) {\n            this.betOutsideIncreaseBtn.tint = this.componentConfiguration.tintColor;\n            this.setBetOutsideIncreaseBtnGraphics(false);\n        } else {\n            this.betOutsideIncreaseBtn.tint = 0xffffff;\n            this.setBetOutsideIncreaseBtnGraphics(true);\n        }\n        // this.betOutsideIncreaseBtn.texture = disabled\n        //     ? Core.assets.getAsset('arrowPlusInactive').texture\n        //     : Core.assets.getAsset('arrowPlusActive').texture;\n        // this.betOutsideIncreaseBtn.interactive = !disabled;\n    }\n\n    public confirmationCheckBoxClicked(checked: boolean): void {\n        this.confirmationPopUpCheckBox.texture = checked\n            ? Core.assets.getAsset('checkBoxChecked').texture\n            : Core.assets.getAsset('checkBoxUnchecked').texture;\n    }\n\n    public showInfoText(activeText: string): void {\n        this.infoText.showInfoText(activeText);\n    }\n\n    public hideInfoText(): void {\n        this.infoText.hideInfoText();\n    }\n\n    public showOutsidePanel(): void {\n        this.betOutsideContainer.visible = true;\n    }\n\n    public hideOutsidePanel(): void {\n        this.betOutsideContainer.visible = false;\n    }\n\n    // public setSelectedFirstEnabledBanner(): void {\n    //     for (const popUpBanner of this.popUpBanners) {\n    //         if (popUpBanner.enable) {\n    //             popUpBanner.setSelected(true);\n    //             this.stateMachineService.send({ type: 'BONUS_SELECTED', bonusId: popUpBanner.bannerId });\n    //             break;\n    //         }\n    //     }\n    // }\n\n    // private choseAvailableBonusForSelection(): number {\n    //     for (const popUpBanner of this.popUpBanners) {\n    //         if (popUpBanner.enable) {\n    //             return popUpBanner.bannerId;\n    //         }\n    //     }\n    //     return -1;\n    // }\n\n    private createDoubleChanceButton(): void {\n        this.doubleChanceButton = new Sprite();\n        this.doubleChanceButton.interactive = true;\n        this.doubleChanceButton.cursor = 'pointer';\n        this.doubleChanceButton.anchor.set(0.5);\n        this.doubleChanceButton.name = 'doubleChanceButton';\n        this.addChild(this.doubleChanceButton);\n    }\n\n    private setBetOutsidePosition(): void {\n        this.betOutsideTotalBetValue.x =\n            -(\n                this.betOutsideTotalBetValue.width +\n                this.componentConfiguration.betOutsidePanel.wordSpacing +\n                this.betOutsideTotalBetCurrency.width\n            ) / 2;\n        this.betOutsideTotalBetCurrency.x =\n            this.betOutsideTotalBetValue.x +\n            this.betOutsideTotalBetValue.width +\n            this.componentConfiguration.betOutsidePanel.wordSpacing;\n        if (\n            this.betOutsideBetContainer.getLocalBounds().width >\n            this.componentConfiguration.betOutsideBetContainer.maxWidth\n        ) {\n            this.betOutsideBetContainer.scale.set(\n                this.componentConfiguration.betOutsideBetContainer.maxWidth /\n                    this.betOutsideBetContainer.getLocalBounds().width,\n            );\n        }\n        this.betOutsideBetContainer.x = this.componentConfiguration.betOutsideBetContainer.x;\n        this.betOutsideBetContainer.y = this.componentConfiguration.betOutsideBetContainer.y;\n    }\n\n    private setOrientation(): void {\n        this.buyBonusBtn.x =\n            Core.LEFT_HAND_MODE.value && Core.ORIENTATION.value.isLandscape\n                ? Core.display.stage.width - this.componentConfiguration.buyBonusBtn.x\n                : this.componentConfiguration.buyBonusBtn.x;\n        this.buyBonusBtn.y = this.componentConfiguration.buyBonusBtn.y;\n\n        this.buyBonusBtn.texture = Core.assets.getTextureFromSpriteSheet(\n            'extendedMultipleBuyBonusTranslatableAssets',\n            this.buyBonusTextureType + Core.ORIENTATION.value.orientation + '.png',\n        );\n\n        if (this.doubleChanceButton) {\n            this.doubleChanceButton.x = this.componentConfiguration.doubleChanceBtn.x;\n            this.doubleChanceButton.y = this.componentConfiguration.doubleChanceBtn.y;\n        }\n\n        this.updateDoubleChanceBtnTexture();\n\n        if (this.popUpToggleTimeLine) {\n            this.popUpToggleTimeLine.totalProgress(1);\n        }\n\n        if (this.guaranteedWinPopUpToggleTimeLine) {\n            this.guaranteedWinPopUpToggleTimeLine.totalProgress(1);\n        }\n\n        this.popUpBackground.x = this.componentConfiguration.popUpBackground.x;\n        this.popUpBackground.y = this.componentConfiguration.popUpBackground.y;\n\n        this.popUpTitle.x = this.componentConfiguration.popUpTitle.x;\n        this.popUpTitle.y = this.componentConfiguration.popUpTitle.y;\n        this.popUpTitle.scale.set(this.componentConfiguration.popUpTitle.scale);\n\n        this.popUpBtnClose.x = this.componentConfiguration.popUpBtnClose.x;\n        this.popUpBtnClose.y = this.componentConfiguration.popUpBtnClose.y;\n        this.popUpBtnClose.scale.set(this.componentConfiguration.popUpBtnClose.scale);\n\n        this.setBetOutsidePosition();\n\n        if (this.betOutsideBetInfo.width > this.componentConfiguration.betOutsideBetInfo.maxWidth) {\n            this.betOutsideBetInfo.scale.set(\n                this.componentConfiguration.betOutsideBetInfo.maxWidth / this.betOutsideBetInfo.width,\n            );\n        }\n        this.betOutsideBetInfo.x = this.componentConfiguration.betOutsideBetInfo.x;\n        this.betOutsideBetInfo.y = this.componentConfiguration.betOutsideBetInfo.y;\n\n        let bannerValueMinScale: number = 1;\n        for (let i: number = 0; i < this.popUpBanners.length; i++) {\n            const bannerConfig: IBannerConfig = this.getBannerConfigByGameMode(this.popUpBanners[i].gameMode);\n            this.popUpBanners[i].scale.set(bannerConfig.bannerPosition.scale);\n            this.popUpBanners[i].x = bannerConfig.bannerPosition.x;\n            this.popUpBanners[i].y = bannerConfig.bannerPosition.y;\n            this.popUpBanners[i].setOrientation();\n            if (this.popUpBanners[i].buyValueScale < bannerValueMinScale) {\n                bannerValueMinScale = this.popUpBanners[i].buyValueScale;\n            }\n        }\n        // update all banners to have same scales for buy value\n        for (const banner of this.popUpBanners) {\n            banner.updateScaleValueToBeSameForAll(bannerValueMinScale);\n        }\n\n        this.betPanel.scale.set(this.componentConfiguration.betPanel.scale);\n        this.betPanel.x = this.componentConfiguration.betPanel.x;\n        this.betPanel.y = this.componentConfiguration.betPanel.y;\n        this.betPanel.setOrientation();\n\n        this.setBalancePosition();\n\n        // confirmation popup was removed and is not supported\n        if (this.componentConfiguration.haveConfirmationPopUp) {\n            this.confirmationPopUpBackground.x = 53;\n            this.confirmationPopUpBackground.y = 252;\n\n            this.confirmationPopUpTitle.x = 200;\n            this.confirmationPopUpTitle.y = 200;\n\n            this.confirmationPopUpDescriptionText.x = 380;\n            this.confirmationPopUpDescriptionText.y = 500;\n\n            this.confirmationPopUpValueText.x = 380;\n            this.confirmationPopUpValueText.y = 590;\n\n            this.confirmationPopUpValueDescriptionText.x = 380;\n            this.confirmationPopUpValueDescriptionText.y = 660;\n\n            this.confirmationPopUpConfirmBtn.x = 400;\n            this.confirmationPopUpConfirmBtn.y = 720;\n\n            this.confirmationPopUpConfirmBtnText.x = 534;\n            this.confirmationPopUpConfirmBtnText.y = 756;\n\n            this.confirmationPopUpBackBtn.x = 100;\n            this.confirmationPopUpBackBtn.y = 720;\n\n            this.confirmationPopUpBackBtnText.x = 234;\n            this.confirmationPopUpBackBtnText.y = 756;\n\n            this.confirmationPopUpCheckBox.x = 234;\n            this.confirmationPopUpCheckBox.y = 872;\n\n            this.confirmationPopUpDontShowText.x = 410;\n            this.confirmationPopUpDontShowText.y = 892;\n        }\n\n        if (this.denomContainer) {\n            this.denomContainer.scale.set(this.componentConfiguration.denominationContainer.scale);\n            this.denomContainer.x = Core.display.stage.width / 2 - this.denomContainer.width / 2;\n            this.denomContainer.y = this.componentConfiguration.denominationContainer.y;\n            // this.denominationText.style = this.componentConfiguration.denominationContainer.denominationTextStyle;\n            // this.denominationText.x = this.componentConfiguration.denominationContainer.denominationTextX;\n            // this.denominationText.y = this.componentConfiguration.denominationContainer.denominationTextY;\n        }\n\n        this.betOutsideBase.x = this.componentConfiguration.betOutsidePanel.x;\n        this.betOutsideBase.y = this.componentConfiguration.betOutsidePanel.y;\n\n        this.betOutsideDecreaseBtn.x = this.componentConfiguration.betOutsidePanel.betOutsideDecreaseBtnX;\n        this.betOutsideDecreaseBtn.y = this.componentConfiguration.betOutsidePanel.betOutsideDecreaseBtnY;\n\n        this.betOutsideIncreaseBtn.x = this.componentConfiguration.betOutsidePanel.betOutsideIncreaseBtnX;\n        this.betOutsideIncreaseBtn.y = this.componentConfiguration.betOutsidePanel.betOutsideIncreaseBtnY;\n\n        if (this.componentConfiguration.bannersHaveSelectedState) {\n            this.popUpConfirmBtn.x = this.componentConfiguration.popUpConfirmBtn.x;\n            this.popUpConfirmBtn.y = this.componentConfiguration.popUpConfirmBtn.y;\n        }\n\n        this.popUpOverlay.width = Core.display.stage.width;\n        this.popUpOverlay.height = Core.display.stage.height;\n\n        this.popUpBackground.texture = Core.assets.getTextureFromSpriteSheet(\n            'extendedMultipleBuyBonusMainAssets',\n            'popUpBase' + Core.ORIENTATION.value.orientation + '.png',\n        );\n\n        if (this.componentConfiguration.haveGuaranteedWinToggle) {\n            this.updateGuaranteedWinTogglesPosition();\n        } else {\n            this.updateTogglesPosition();\n        }\n        this.infoText.setOrientation();\n        this.resizeOutsideBetInfoText();\n    }\n\n    private resizeOutsideBetInfoText(): void {\n        this.betOutsideBetInfo.scale.set(1);\n        if (this.betOutsideBetInfo.width > this.betOutsideBase.width - 40) {\n            this.betOutsideBetInfo.scale.set((this.betOutsideBase.width - 40) / this.betOutsideBetInfo.width);\n        }\n    }\n\n    private updateTogglesPosition(): void {\n        this.popUpToggleText.scale.set(1);\n\n        const scaleOffset: number = Core.ORIENTATION.value.isLandscape ? 80 : 250;\n        if (this.popUpToggleText.width > this.popUpBackground.width - scaleOffset) {\n            this.popUpToggleText.scale.set((this.popUpBackground.width - scaleOffset) / this.popUpToggleText.width);\n        }\n\n        const leftOffset: number = this.componentConfiguration.skipSameBets ? 36 : 24;\n        const wordSpacing: number = 10;\n        const rightOffset: number = this.componentConfiguration.skipSameBets ? 22 : 12;\n\n        this.popUpToggleBackgroundActive.height = 78;\n        this.popUpToggleBackgroundActive.width =\n            this.popUpToggleText.width + this.popUpToggleActive.width + wordSpacing + leftOffset + rightOffset;\n        this.popUpToggleBackgroundActive.pivot.set(\n            this.popUpToggleBackgroundActive.width / 2,\n            this.popUpToggleBackgroundActive.height / 2,\n        );\n\n        this.popUpToggleBackgroundInactive.height = 78;\n        this.popUpToggleBackgroundInactive.width =\n            this.popUpToggleText.width + this.popUpToggleActive.width + wordSpacing + leftOffset + rightOffset;\n        this.popUpToggleBackgroundInactive.pivot.set(\n            this.popUpToggleBackgroundInactive.width / 2,\n            this.popUpToggleBackgroundInactive.height / 2,\n        );\n\n        this.popUpToggleText.x = leftOffset - this.popUpToggleBackgroundActive.width / 2;\n\n        this.popUpToggleActive.x = this.popUpToggleText.x + this.popUpToggleText.width + wordSpacing;\n        this.popUpToggleInactive.x = this.popUpToggleText.x + this.popUpToggleText.width + wordSpacing;\n\n        this.popUpToggleSliderActive.x = this.popUpToggleActive.x + (this.popUpToggleState === 'Active' ? 51 : 7);\n        this.popUpToggleSliderInactive.x = this.popUpToggleInactive.x + (this.popUpToggleState === 'Active' ? 51 : 7);\n\n        this.popUpToggleContainer.x = this.componentConfiguration.toggleContainer.x;\n        this.popUpToggleContainer.y = this.componentConfiguration.toggleContainer.y;\n        this.popUpToggleContainer.scale.set(this.componentConfiguration.toggleContainer.scale);\n    }\n\n    private updateGuaranteedWinTogglesPosition(): void {\n        this.guaranteedWinPopUpToggleContainer.x = this.componentConfiguration.guaranteedWinToggleContainer.x;\n        this.guaranteedWinPopUpToggleContainer.y = this.componentConfiguration.guaranteedWinToggleContainer.y;\n        this.guaranteedWinPopUpToggleContainer.scale.set(\n            this.componentConfiguration.guaranteedWinToggleContainer.scale,\n        );\n\n        this.popUpToggleContainer.x = this.componentConfiguration.toggleContainer.x;\n        this.popUpToggleContainer.y = this.componentConfiguration.toggleContainer.y;\n        this.popUpToggleContainer.scale.set(this.componentConfiguration.toggleContainer.scale);\n    }\n\n    private scaleTogglesTextScaleAndPosition(\n        backgroundActive: NineSlicePlane,\n        backgroundInactive: NineSlicePlane,\n        toggleText: Text,\n        toggleActive: Sprite,\n        toggleInactive: Sprite,\n        toggleSliderActive: Sprite,\n        toggleSliderInactive: Sprite,\n        isGuaranteedWinToggle: boolean,\n    ): void {\n        backgroundActive.width = 340;\n        backgroundActive.height = 82;\n        backgroundActive.pivot.set(backgroundActive.width / 2, backgroundActive.height / 2);\n\n        backgroundInactive.width = 340;\n        backgroundInactive.height = 82;\n        backgroundInactive.pivot.set(backgroundInactive.width / 2, backgroundInactive.height / 2);\n\n        toggleText.x = 26 - backgroundActive.width / 2;\n\n        if (isGuaranteedWinToggle) {\n            this.guaranteedWinPopUpToggleTextMaxWidth = toggleText.style.wordWrapWidth as number;\n        } else {\n            this.popUpToggleTextMaxWidth = toggleText.style.wordWrapWidth as number;\n        }\n        this.updateTextToBeOnTwoLines(toggleText);\n\n        toggleActive.x = 40;\n        toggleInactive.x = 40;\n\n        toggleSliderActive.x = toggleActive.x + 7;\n        toggleSliderInactive.x = toggleInactive.x + 7;\n    }\n\n    private scaleTogglesTextToSameSize(): void {\n        const toggleTextMaxWidth: number = this.popUpToggleTextMaxWidth;\n        const toggleScaleFactor = toggleTextMaxWidth / this.popUpToggleText.width;\n        const guaranteedTextMaxWidth: number = this.guaranteedWinPopUpToggleTextMaxWidth;\n        const guaranteedToggleScaleFactor = guaranteedTextMaxWidth / this.guaranteedWinPopUpToggleText.width;\n\n        const scaleFactor: number =\n            toggleScaleFactor < guaranteedToggleScaleFactor ? toggleScaleFactor : guaranteedToggleScaleFactor;\n        if (scaleFactor < 1) {\n            this.popUpToggleText.scale.set(scaleFactor);\n            this.guaranteedWinPopUpToggleText.scale.set(scaleFactor);\n        }\n    }\n\n    private updateTextToBeOnTwoLines(toggleText: Text): void {\n        const lineHeight: number = toggleText.style.lineHeight || (toggleText.style.fontSize as number);\n        const estimatedLineCount = Math.round(toggleText.height / lineHeight);\n        if (estimatedLineCount > 2) {\n            (toggleText.style.wordWrapWidth as number) += 10;\n            this.updateTextToBeOnTwoLines(toggleText);\n        }\n    }\n\n    private getBannerConfigByGameMode(gameMode: string): IBannerConfig {\n        return this.componentConfiguration.bannerConfig.find((config) => config.gameMode === gameMode) as IBannerConfig;\n    }\n\n    private setBalancePosition(): void {\n        this.balanceContainer.scale.set(this.componentConfiguration.balancePositions.scale);\n\n        this.balanceCurrency.style = this.componentConfiguration.balancePositions.balanceCurrencyStyle;\n        this.balanceText.style = this.componentConfiguration.balancePositions.balanceTextStyle;\n        this.balanceValue.style = this.componentConfiguration.balancePositions.balanceValueStyle;\n\n        this.balanceValue.x = this.balanceText.width + this.componentConfiguration.balancePositions.wordSpacing * 2;\n        this.balanceCurrency.x =\n            this.balanceValue.x + this.balanceValue.width + this.componentConfiguration.balancePositions.wordSpacing;\n        this.balanceContainer.x =\n            this.componentConfiguration.balancePositions.x -\n            ((this.balanceText.width + this.balanceValue.width + this.balanceCurrency.width) / 2) *\n                this.componentConfiguration.balancePositions.scale;\n        this.balanceContainer.y = this.componentConfiguration.balancePositions.y;\n    }\n\n    private setBetOutsideIncreaseBtnGraphics(interactive: boolean): void {\n        if (!this.betOutsideIncreaseBtnGraphics) {\n            this.betOutsideIncreaseBtnGraphics = new Graphics();\n            this.betOutsideIncreaseBtnGraphics\n                .beginFill(0x000000, 0.1)\n                .drawPolygon(\n                    0,\n                    0, // Point 1 (x1, y1)\n                    this.betOutsideIncreaseBtn.width,\n                    this.betOutsideIncreaseBtn.width / 2, // Point 2 (x2, y2)\n                    0,\n                    this.betOutsideIncreaseBtn.width,\n                )\n                .endFill();\n            this.betOutsideIncreaseBtnGraphics.alpha = 0;\n            this.betOutsideIncreaseBtn.addChild(this.betOutsideIncreaseBtnGraphics);\n            this.betOutsideIncreaseBtnGraphics.pivot.set(0, this.betOutsideIncreaseBtnGraphics.height / 2);\n\n            (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus.ts:1794:13\",(this.betOutsideIncreaseBtnGraphics),\"pointertap\"]), fromEvent(this.betOutsideIncreaseBtnGraphics, 'pointertap'))\n                .pipe(takeUntil(this.DESTROY))\n                .subscribe(this.onOutsideIncreaseBtn.bind(this));\n        }\n\n        this.betOutsideIncreaseBtnGraphics.interactive = interactive;\n        this.betOutsideIncreaseBtnGraphics.cursor = 'pointer';\n    }\n\n    private setBetOutsideDecreaseBtnGraphics(interactive: boolean): void {\n        if (!this.betOutsideDecreaseBtnGraphics) {\n            this.betOutsideDecreaseBtnGraphics = new Graphics();\n            this.betOutsideDecreaseBtnGraphics\n                .beginFill(0x000000, 0.1)\n                .drawPolygon(\n                    0,\n                    this.betOutsideDecreaseBtn.width / 2, // Point 1 (x1, y1)\n                    this.betOutsideDecreaseBtn.width,\n                    0, // Point 2 (x2, y2)\n                    this.betOutsideDecreaseBtn.width,\n                    this.betOutsideDecreaseBtn.width,\n                )\n                .endFill();\n            this.betOutsideDecreaseBtnGraphics.alpha = 0;\n            this.betOutsideDecreaseBtn.addChild(this.betOutsideDecreaseBtnGraphics);\n            this.betOutsideDecreaseBtnGraphics.pivot.set(0, this.betOutsideDecreaseBtnGraphics.height / 2);\n\n            (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/extended-multiple-buy-bonus/views/BuyBonusViewExtendedMultipleBuyBonus.ts:1821:13\",(this.betOutsideDecreaseBtnGraphics),\"pointertap\"]), fromEvent(this.betOutsideDecreaseBtnGraphics, 'pointertap'))\n                .pipe(takeUntil(this.DESTROY))\n                .subscribe(this.onOutsideDecreaseBtn.bind(this));\n        }\n        this.betOutsideDecreaseBtnGraphics.interactive = interactive;\n        this.betOutsideDecreaseBtnGraphics.cursor = 'pointer';\n    }\n\n    private updateDenomination(denomination: number): void {\n        for (let i: number = 0; i < this.denominationBtns.length; i++) {\n            if (this.rootStore.settings.denominations.indexOf(denomination) === i) {\n                this.denominationBtns[i].active.visible = true;\n                this.denominationBtns[i].inactive.visible = false;\n            } else {\n                this.denominationBtns[i].active.visible = false;\n                this.denominationBtns[i].inactive.visible = true;\n            }\n        }\n    }\n\n    private createDenominationButtons(availableDenominations: number[]): void {\n        this.denomContainer = new Container();\n        this.denomContainer.name = 'denomContainer';\n        this.popUpContainer.addChild(this.denomContainer);\n\n        const denomText = new Text(\n            Core.translator.translate('BET LEVEL'),\n            this.componentConfiguration.denominationContainer.denominationText,\n        );\n        denomText.y = 32;\n        this.denomContainer.addChild(denomText);\n\n        const denomIcon = new Sprite(\n            Core.assets.getTextureFromSpriteSheet('extendedMultipleBuyBonusMainAssets', 'coinIcon.png'),\n        );\n        denomIcon.x = denomText.width / 2 - denomIcon.width / 2;\n        denomIcon.y = 6;\n        this.denomContainer.addChild(denomIcon);\n\n        for (let i: number = 0; i < availableDenominations.length; i++) {\n            const denomBtnInactive: Sprite = new Sprite(Core.assets.getAsset('denominationBntBBNormal').texture);\n            denomBtnInactive.name = 'denomBtn' + i;\n            denomBtnInactive.x =\n                (denomBtnInactive.width + this.componentConfiguration.denominationContainer.buttonsOffset) * i +\n                denomText.width +\n                this.componentConfiguration.denominationContainer.buttonsOffset * 2;\n            denomBtnInactive.y = this.componentConfiguration.denominationContainer.buttonsYPosition;\n            denomBtnInactive.interactive = true;\n            denomBtnInactive.cursor = 'pointer';\n            const denomTextInactive = new Text(\n                i + 1,\n                this.componentConfiguration.denominationContainer.denominationBtnTextStyle,\n            );\n            denomTextInactive.x = denomBtnInactive.width / 2 - denomTextInactive.width / 2;\n            denomTextInactive.y = 10;\n            denomBtnInactive.addChild(denomTextInactive);\n            this.denomContainer.addChild(denomBtnInactive);\n\n            const denominationTextInactive = new Text(\n                Core.translator.translate('EXTENDED_MULTIPLE.BUY_BONUS.DENOMINATION'),\n                this.componentConfiguration.denominationContainer.denominationTextStyleInactive,\n            );\n            denominationTextInactive.name = 'denominationText';\n            denominationTextInactive.anchor.set(0.5, 0);\n            denomBtnInactive.addChild(denominationTextInactive);\n            denominationTextInactive.x = denomBtnInactive.width / 2;\n            denominationTextInactive.y = 49;\n\n            const denomBtnActive: Sprite = new Sprite(Core.assets.getAsset('denominationBntBBSelected').texture);\n            denomBtnActive.name = 'denomBtn' + i;\n            denomBtnActive.x =\n                (denomBtnActive.width + this.componentConfiguration.denominationContainer.buttonsOffset) * i +\n                denomText.width +\n                this.componentConfiguration.denominationContainer.buttonsOffset * 2;\n            denomBtnActive.y = this.componentConfiguration.denominationContainer.buttonsYPosition;\n            const denomTextActive = new Text(\n                i + 1,\n                this.componentConfiguration.denominationContainer.denominationBtnTextStyleActive,\n            );\n            denomTextActive.x = denomBtnActive.width / 2 - denomTextActive.width / 2;\n            denomTextActive.y = 10;\n            denomBtnActive.addChild(denomTextActive);\n            this.denomContainer.addChild(denomBtnActive);\n\n            const denominationTextActive = new Text(\n                Core.translator.translate('EXTENDED_MULTIPLE.BUY_BONUS.DENOMINATION'),\n                this.componentConfiguration.denominationContainer.denominationTextStyleActive,\n            );\n            denominationTextActive.name = 'denominationText';\n            denominationTextActive.anchor.set(0.5, 0);\n            denomBtnActive.addChild(denominationTextActive);\n            denominationTextActive.x = denomBtnActive.width / 2;\n            denominationTextActive.y = 49;\n\n            this.denominationBtns.push({ active: denomBtnActive, inactive: denomBtnInactive, id: i });\n        }\n    }\n}\n","import Core, { MoneyFormatter } from '@egt/core';\nimport { ViewContainer } from '@egt/ui-lib';\nimport { BitmapText, NineSlicePlane, Sprite, Text } from 'pixi.js';\nimport { IBuyBonusComponentConfigurationExtendedMultipleBuyBonus } from '../configuration/IBuyBonusComponentConfigurationExtendedMultipleBuyBonus';\nimport BannerData from '../data/BannerData';\n\nexport default class ExtendedMultipleBuyBonusBanner extends ViewContainer {\n    // public btn: Sprite;\n    public bannerId: number;\n    public gameMode: string;\n    public enable: boolean = true;\n    public buyValueScale: number = 1;\n    public bonusFactor: number;\n\n    public bannerConfirmBnt: Sprite;\n    public bannerCancelBtn: Sprite;\n\n    private selected: boolean = false;\n    private background: Sprite;\n    // private btnText: Sprite;\n    private valueContainer: Sprite;\n    private buyValueText: BitmapText;\n    private buyValueCurrencyText: BitmapText;\n\n    private maxBetContainer: Sprite;\n    private maxBetBackground: NineSlicePlane;\n    private maxBetText: Text;\n    private maxBetOffset: number = 20;\n\n    private descriptionText: Text;\n    // private money: Money;\n\n    constructor(\n        private bannerData: BannerData,\n        private currency: string,\n        bet: number,\n        denomination: number,\n        private componentConfiguration: IBuyBonusComponentConfigurationExtendedMultipleBuyBonus,\n    ) {\n        super();\n        this.gameMode = this.bannerData.gameMode;\n        this.bonusFactor = bannerData.bonusFactor;\n        this.bannerId = bannerData.bannerId;\n        this.createBanner(bet, denomination);\n        if (!this.componentConfiguration.bannersHaveSelectedState) {\n            this.createBannerBtns();\n        }\n        this.name = 'ExtendedMultipleBuyBonusBanner' + this.bannerId;\n    }\n\n    private createBanner(bet: number, denomination: number): void {\n        // this.money = ;\n        this.background = new Sprite();\n        this.setSelected(false);\n        this.background.name = 'background';\n        this.addChild(this.background);\n        if (this.componentConfiguration.bannersHaveSelectedState) {\n            this.interactive = true;\n            this.cursor = 'pointer';\n        }\n\n        if (this.componentConfiguration.bannerInnerPositions.haveDescriptionText) {\n            this.descriptionText = new Text(\n                Core.translator.translate(this.bannerData.bannerDescriptionText),\n                this.componentConfiguration.bannerInnerPositions.descriptionTextStyle,\n            );\n            this.descriptionText.anchor.set(0.5, 0.5);\n            this.addChild(this.descriptionText);\n        }\n\n        this.valueContainer = new Sprite();\n        this.addChild(this.valueContainer);\n\n        this.buyValueText = new BitmapText(\n            new MoneyFormatter(bet * denomination * this.bannerData.bonusFactor).stringMoney,\n            {\n                fontName: 'bbBannerFont',\n                fontSize: this.componentConfiguration.bannerInnerPositions.buyValueTextFontSize,\n                align: 'center',\n                letterSpacing: this.componentConfiguration.bannerInnerPositions.buyValueTextLetterSpacing,\n            },\n        );\n        this.buyValueText.name = 'buyValueText';\n        this.valueContainer.addChild(this.buyValueText);\n\n        this.buyValueCurrencyText = new BitmapText(this.currency, {\n            fontName: 'bbBannerFont',\n            fontSize: this.componentConfiguration.bannerInnerPositions.buyValueCurrencyFontSize,\n            align: 'center',\n            letterSpacing: this.componentConfiguration.bannerInnerPositions.buyValueCurrencyLetterSpacing,\n        });\n        this.buyValueCurrencyText.name = 'buyValueCurrencyText';\n        this.valueContainer.addChild(this.buyValueCurrencyText);\n\n        this.maxBetContainer = new Sprite();\n        this.addChild(this.maxBetContainer);\n        this.maxBetBackground = new NineSlicePlane(\n            Core.assets.getTextureFromSpriteSheet('extendedMultipleBuyBonusMainAssets', 'maxBet.png'),\n            20,\n            2,\n            20,\n            2,\n        );\n        this.maxBetContainer.addChild(this.maxBetBackground);\n        this.maxBetContainer.anchor.set(0.5);\n\n        this.maxBetText = new Text(\n            Core.translator.translate('EXTENDED_MULTIPLE.BUY_BONUS.MAX_BET'),\n            this.componentConfiguration.bannerInnerPositions.maxBetTextStyle,\n        );\n        this.maxBetText.anchor.set(0.5);\n        this.maxBetContainer.addChild(this.maxBetText);\n    }\n\n    private createBannerBtns(): void {\n        this.bannerCancelBtn = new Sprite(\n            Core.assets.getTextureFromSpriteSheet('extendedMultipleBuyBonusMainAssets', 'cancelBtn.png'),\n        );\n        this.bannerCancelBtn.interactive = true;\n        this.bannerCancelBtn.cursor = 'pointer';\n        this.bannerCancelBtn.name = 'bannerCancelBtn';\n        this.addChild(this.bannerCancelBtn);\n\n        this.bannerConfirmBnt = new Sprite(\n            Core.assets.getTextureFromSpriteSheet('extendedMultipleBuyBonusMainAssets', 'activateBtn.png'),\n        );\n        this.bannerConfirmBnt.interactive = true;\n        this.bannerConfirmBnt.cursor = 'pointer';\n        this.bannerConfirmBnt.name = 'bannerConfirmBnt';\n        this.addChild(this.bannerConfirmBnt);\n    }\n\n    public updateBet(bet: number, denomination: number, playerBalance: number, guaranteedWinActivated: boolean): void {\n        const bonusFactor: number =\n            guaranteedWinActivated && this.bannerData.secondBonusFactor\n                ? this.bannerData.secondBonusFactor\n                : this.bannerData.bonusFactor;\n\n        const money = new MoneyFormatter(bet * denomination * bonusFactor);\n        if (!this.enable) {\n            if (money.moneyInUnits > this.bannerData.maxBet || money.moneyInUnits > playerBalance) {\n                return;\n            }\n        }\n        const text: string = money.stringMoney.length > 5 ? money.stringMoney.replace('.00', '') : money.stringMoney;\n        this.buyValueText.text = text;\n        if (money.moneyInUnits > this.bannerData.maxBet) {\n            this.maxBetText.text = Core.translator.translate('EXTENDED_MULTIPLE.BUY_BONUS.MAX_BET');\n            this.setMaxBet(true, guaranteedWinActivated);\n        } else if (money.moneyInUnits > playerBalance) {\n            this.maxBetText.text = Core.translator.translate('EXTENDED_MULTIPLE.BUY_BONUS.INSUFFICIENT_FUNDS');\n            this.setMaxBet(false, guaranteedWinActivated);\n        } else {\n            this.setNormal();\n        }\n        this.resizeMaxBetText();\n        this.setValueTextPosition();\n    }\n\n    public updateScaleValueToBeSameForAll(scaleFactor: number): void {\n        this.setValueTextPosition(scaleFactor);\n    }\n\n    public setSelected(selected: boolean) {\n        this.selected = selected;\n        if (selected && this.componentConfiguration.bannersHaveSelectedState) {\n            this.background.texture = Core.assets.getTextureFromSpriteSheet(\n                'extendedMultipleBuyBonusTranslatableAssets',\n                'bannerBackgroundSelected' + this.bannerId + Core.ORIENTATION.value.orientation + '.png',\n            );\n        } else {\n            this.background.texture = Core.assets.getTextureFromSpriteSheet(\n                'extendedMultipleBuyBonusTranslatableAssets',\n                'bannerBackground' + this.bannerId + Core.ORIENTATION.value.orientation + '.png',\n            );\n        }\n    }\n\n    public setOrientation(): void {\n        // this.btn.x = 46;\n        // this.btn.y = 334;\n\n        // this.btnText.x = 180;\n        // this.btnText.y = 369;\n\n        if (this.componentConfiguration.bannerInnerPositions.haveDescriptionText) {\n            this.descriptionText.x = this.componentConfiguration.bannerInnerPositions.descriptionTextX;\n            this.descriptionText.y = this.componentConfiguration.bannerInnerPositions.descriptionTextY;\n            this.descriptionText.style = this.componentConfiguration.bannerInnerPositions.descriptionTextStyle;\n        }\n\n        this.maxBetBackground.width = this.maxBetText.width + this.maxBetOffset * 2;\n        this.maxBetBackground.pivot.set(this.maxBetBackground.width / 2, this.maxBetBackground.height / 2);\n        // this.maxBetBackground.x = (this.maxBetText.width + this.maxBetOffset * 2) / 2 * -1;\n        this.maxBetContainer.x = this.componentConfiguration.bannerInnerPositions.maxBetContainerX;\n        this.maxBetContainer.y = this.componentConfiguration.bannerInnerPositions.maxBetContainerY;\n        this.maxBetContainer.scale.set(this.componentConfiguration.bannerInnerPositions.maxBetContainerScale);\n\n        this.setSelected(this.selected);\n        if (!this.componentConfiguration.bannersHaveSelectedState) {\n            this.bannerCancelBtn.x = this.componentConfiguration.bannerInnerPositions.btnCloseXPosition;\n            this.bannerCancelBtn.y = this.componentConfiguration.bannerInnerPositions.btnCloseYPosition;\n            this.bannerCancelBtn.scale.set(this.componentConfiguration.bannerInnerPositions.btnCloseScale);\n            this.bannerConfirmBnt.x = this.componentConfiguration.bannerInnerPositions.btnConfirmXPosition;\n            this.bannerConfirmBnt.y = this.componentConfiguration.bannerInnerPositions.btnConfirmYPosition;\n            this.bannerConfirmBnt.scale.set(this.componentConfiguration.bannerInnerPositions.btnConfirmScale);\n        }\n        this.setValueTextPosition();\n        this.resizeMaxBetText();\n    }\n\n    private setValueTextPosition(externalScaleFactor?: number): void {\n        this.buyValueText.x = 0;\n\n        this.buyValueCurrencyText.scale.set(this.componentConfiguration.bannerInnerPositions.valueTextsScale);\n        this.buyValueText.scale.set(this.componentConfiguration.bannerInnerPositions.valueTextsScale);\n\n        this.buyValueCurrencyText.x =\n            this.buyValueText.width + this.componentConfiguration.bannerInnerPositions.wordSpacing;\n        this.buyValueCurrencyText.y = this.componentConfiguration.bannerInnerPositions.buyValueCurrencyY;\n\n        let scaleFactor: number = 1;\n        this.valueContainer.scale.set(scaleFactor);\n        if (externalScaleFactor) {\n            scaleFactor = externalScaleFactor;\n            this.valueContainer.scale.set(scaleFactor);\n        } else {\n            if (\n                this.buyValueCurrencyText.width +\n                    this.buyValueText.width +\n                    this.componentConfiguration.bannerInnerPositions.wordSpacing >\n                this.componentConfiguration.bannerInnerPositions.buyValueCurrencyMaxWidth\n            ) {\n                scaleFactor =\n                    this.componentConfiguration.bannerInnerPositions.buyValueCurrencyMaxWidth /\n                    (this.buyValueCurrencyText.width +\n                        this.buyValueText.width +\n                        this.componentConfiguration.bannerInnerPositions.wordSpacing);\n                this.valueContainer.scale.set(scaleFactor);\n            }\n        }\n\n        this.valueContainer.x =\n            this.componentConfiguration.bannerInnerPositions.valueContainerX -\n            ((this.buyValueCurrencyText.width + this.buyValueText.width) * scaleFactor) / 2;\n        const scaleOffsetY: number = (this.buyValueText.height - this.buyValueText.height * scaleFactor) / 2;\n        this.valueContainer.y = this.componentConfiguration.bannerInnerPositions.valueContainerY + scaleOffsetY;\n\n        this.buyValueScale = scaleFactor;\n    }\n\n    private setMaxBet(useMaxBetValue: boolean, guaranteedWinActivated: boolean): void {\n        // this.alpha = 0.2;\n        const maxBetValue = new MoneyFormatter(\n            guaranteedWinActivated && this.bannerData.secondBonusFactor\n                ? this.bannerData.secondFactorMaxBetBannerValue\n                : this.bannerData.maxBetBannerValue,\n        );\n        const insufficientFundsValue = new MoneyFormatter(\n            guaranteedWinActivated && this.bannerData.secondBonusFactor\n                ? this.bannerData.secondFactorInsufficientFundsBannerValue\n                : this.bannerData.insufficientFundsBannerValue,\n        );\n\n        const insufficientFundsBannerValue =\n            guaranteedWinActivated && this.bannerData.secondBonusFactor\n                ? this.bannerData.secondFactorInsufficientFundsBannerValue\n                : this.bannerData.insufficientFundsBannerValue;\n\n        const maxBetMoney: MoneyFormatter =\n            useMaxBetValue ||\n            insufficientFundsBannerValue === Number.MAX_VALUE ||\n            insufficientFundsValue.moneyInUnits > maxBetValue.moneyInUnits\n                ? maxBetValue\n                : insufficientFundsValue;\n        const maxBetText =\n            maxBetMoney.stringMoney.length > 5 ? maxBetMoney.stringMoney.replace('.00', '') : maxBetMoney.stringMoney;\n        this.buyValueText.text = maxBetText;\n\n        this.background.tint = this.componentConfiguration.tintColor;\n\n        if (this.componentConfiguration.bannerInnerPositions.haveDescriptionText) {\n            this.descriptionText.tint = this.componentConfiguration.tintColor;\n        }\n        if (this.componentConfiguration.bannersHaveSelectedState) {\n            this.interactive = false;\n            this.cursor = 'normal';\n        } else {\n            this.bannerConfirmBnt.tint = this.componentConfiguration.tintColor;\n            // this.bannerCancelBtn.tint = this.componentConfiguration.tintColor;\n            this.bannerConfirmBnt.interactive = false;\n            this.bannerConfirmBnt.cursor = 'normal';\n            // this.bannerCancelBtn.interactive = false;\n            // this.bannerCancelBtn.cursor = 'normal';\n        }\n        // this.btn.interactive = false;\n        // this.btn.cursor = 'normal';\n        // this.buyValueText.text = 'MAX BET';\n        this.enable = false;\n        this.maxBetContainer.visible = true;\n    }\n\n    private resizeMaxBetText(): void {\n        this.maxBetText.scale.set(1);\n        if (Core.ORIENTATION.value.isLandscape) {\n            if (this.maxBetText.width > this.background.width - 20) {\n                this.maxBetText.scale.set((this.background.width - 20) / this.maxBetText.width);\n            }\n        } else {\n            if (this.maxBetText.width > (this.background.width - 80) / 2) {\n                this.maxBetText.scale.set((this.background.width - 80) / 2 / this.maxBetText.width);\n            }\n        }\n\n        this.maxBetBackground.width = this.maxBetText.width + this.maxBetOffset * 2;\n        this.maxBetBackground.pivot.set(this.maxBetBackground.width / 2, this.maxBetBackground.height / 2);\n    }\n\n    private setNormal(): void {\n        // this.alpha = 1;\n        this.background.tint = 0xffffff;\n        if (this.componentConfiguration.bannerInnerPositions.haveDescriptionText) {\n            this.descriptionText.tint = 0xffffff;\n        }\n        if (this.componentConfiguration.bannersHaveSelectedState) {\n            this.interactive = true;\n            this.cursor = 'pointer';\n        } else {\n            this.bannerConfirmBnt.tint = 0xffffff;\n            // this.bannerCancelBtn.tint = 0xffffff;\n            this.bannerConfirmBnt.interactive = true;\n            this.bannerConfirmBnt.cursor = 'pointer';\n            // this.bannerCancelBtn.interactive = true;\n            // this.bannerCancelBtn.cursor = 'pointer';\n        }\n        this.enable = true;\n        // this.btn.interactive = true;\n        // this.btn.cursor = 'pointer';\n        this.maxBetContainer.visible = false;\n    }\n}\n","import Core, { MoneyFormatter } from '@egt/core';\nimport { ViewContainer } from '@egt/ui-lib';\nimport { Graphics, Sprite, Text } from 'pixi.js';\nimport { IBuyBonusComponentConfigurationExtendedMultipleBuyBonus } from '../configuration/IBuyBonusComponentConfigurationExtendedMultipleBuyBonus';\n\nexport default class ExtendedMultipleBuyBonusBetControl extends ViewContainer {\n    public decreaseBtn: Sprite;\n    public decreaseBtnGraphics: Graphics;\n    public increaseBtn: Sprite;\n    public increaseBtnGraphics: Graphics;\n\n    private background: Sprite;\n    private buyValueText: Text;\n    private buyValueCurrency: Text;\n    private buyValueBet: Text;\n\n    constructor(\n        private currency: string,\n        private componentConfiguration: IBuyBonusComponentConfigurationExtendedMultipleBuyBonus,\n    ) {\n        super();\n        this.createBetControlBanner();\n    }\n\n    public updateBet(betMoney: number): void {\n        this.buyValueText.scale.set(1);\n\n        let betValue = new MoneyFormatter(betMoney).stringMoney;\n        if (betMoney > 9900) {\n            betValue = betValue.replace('.00', '');\n        }\n\n        this.buyValueText.text = betValue;\n        const maxWidth = this.componentConfiguration.betPanel.betValueMaxWidth;\n\n        if (this.buyValueText.width > maxWidth) {\n            const scaleFactor = maxWidth / this.buyValueText.width;\n            this.buyValueText.scale.set(scaleFactor);\n        }\n    }\n\n    public disableDecreaseBtn(disabled: boolean): void {\n        if (disabled) {\n            this.decreaseBtn.tint = this.componentConfiguration.tintColor;\n            this.setDecreaseBtnGraphics(false);\n        } else {\n            this.decreaseBtn.tint = 0xffffff;\n            this.setDecreaseBtnGraphics(true);\n        }\n        // this.decreaseBtn.texture = disabled\n        //     ? Core.assets.getAsset('arrowMinusInactive').texture\n        //     : Core.assets.getAsset('arrowMinusActive').texture;\n    }\n\n    public disableIncreaseBtn(disabled: boolean): void {\n        if (disabled) {\n            this.increaseBtn.tint = this.componentConfiguration.tintColor;\n            this.setIncreaseBtnGraphics(false);\n        } else {\n            this.increaseBtn.tint = 0xffffff;\n            this.setIncreaseBtnGraphics(true);\n        }\n        // this.increaseBtn.texture = disabled\n        //     ? Core.assets.getAsset('arrowPlusInactive').texture\n        //     : Core.assets.getAsset('arrowPlusActive').texture;\n    }\n\n    private createBetControlBanner(): void {\n        this.background = new Sprite(Core.assets.getAsset('betBase').texture);\n        this.background.name = 'background';\n        this.addChild(this.background);\n\n        this.decreaseBtn = new Sprite(Core.assets.getAsset('arrowMinus').texture);\n        this.decreaseBtn.name = 'decreaseBtn';\n        this.decreaseBtn.anchor.set(0, 0.5);\n        this.decreaseBtn.interactive = true;\n        this.setDecreaseBtnGraphics(true);\n        this.addChild(this.decreaseBtn);\n\n        this.increaseBtn = new Sprite(Core.assets.getAsset('arrowPlus').texture);\n        this.increaseBtn.name = 'increaseBtn';\n        this.increaseBtn.anchor.set(0, 0.5);\n        this.increaseBtn.interactive = true;\n        this.setIncreaseBtnGraphics(true);\n        this.addChild(this.increaseBtn);\n\n        this.buyValueText = new Text('', this.componentConfiguration.betPanel.buyValueTextStyle);\n        this.buyValueText.anchor.set(0.5);\n        this.buyValueText.name = 'buyValueText';\n\n        this.addChild(this.buyValueText);\n\n        this.buyValueCurrency = new Text(this.currency, this.componentConfiguration.betPanel.buyValueCurrencyStyle);\n        this.buyValueCurrency.anchor.set(0.5);\n        this.buyValueCurrency.name = 'buyValueCurrency';\n\n        this.addChild(this.buyValueCurrency);\n\n        this.buyValueBet = new Text(\n            Core.translator.translate('EXTENDED_MULTIPLE.BUY_BONUS.BET'),\n            this.componentConfiguration.betPanel.betValueBetStyle,\n        );\n        this.buyValueBet.anchor.set(0.5);\n        this.buyValueBet.name = 'buyValueBet';\n\n        this.addChild(this.buyValueBet);\n    }\n\n    public setOrientation(): void {\n        this.background.x = this.componentConfiguration.betPanel.backgroundX;\n        this.background.y = this.componentConfiguration.betPanel.backgroundY;\n\n        this.increaseBtn.x = this.componentConfiguration.betPanel.increaseBtnX;\n        this.increaseBtn.y = this.componentConfiguration.betPanel.increaseBtnY;\n\n        this.decreaseBtn.x = this.componentConfiguration.betPanel.decreaseBtnX;\n        this.decreaseBtn.y = this.componentConfiguration.betPanel.decreaseBtnY;\n\n        this.buyValueCurrency.x = this.componentConfiguration.betPanel.buyValueCurrencyX;\n        this.buyValueCurrency.y = this.componentConfiguration.betPanel.buyValueCurrencyY;\n\n        this.buyValueText.x = this.componentConfiguration.betPanel.buyValueTextX;\n        this.buyValueText.y = this.componentConfiguration.betPanel.buyValueTextY;\n\n        this.buyValueBet.x = this.componentConfiguration.betPanel.buyValueBetX;\n        this.buyValueBet.y = this.componentConfiguration.betPanel.buyValueBetY;\n    }\n\n    private setIncreaseBtnGraphics(interactive: boolean): void {\n        if (!this.increaseBtnGraphics) {\n            this.increaseBtnGraphics = new Graphics();\n            this.increaseBtnGraphics\n                .beginFill(0x000000, 0.1)\n                .drawPolygon(\n                    0,\n                    0, // Point 1 (x1, y1)\n                    this.increaseBtn.width,\n                    this.increaseBtn.width / 2, // Point 2 (x2, y2)\n                    0,\n                    this.increaseBtn.width,\n                )\n                .endFill();\n            this.increaseBtnGraphics.alpha = 0;\n            this.increaseBtn.addChild(this.increaseBtnGraphics);\n            this.increaseBtnGraphics.pivot.set(0, this.increaseBtnGraphics.height / 2);\n        }\n\n        this.increaseBtnGraphics.interactive = interactive;\n        this.increaseBtnGraphics.cursor = 'pointer';\n    }\n\n    private setDecreaseBtnGraphics(interactive: boolean): void {\n        if (!this.decreaseBtnGraphics) {\n            this.decreaseBtnGraphics = new Graphics();\n            this.decreaseBtnGraphics\n                .beginFill(0x000000, 0.1)\n                .drawPolygon(\n                    0,\n                    this.decreaseBtn.width / 2, // Point 1 (x1, y1)\n                    this.decreaseBtn.width,\n                    0, // Point 2 (x2, y2)\n                    this.decreaseBtn.width,\n                    this.decreaseBtn.width,\n                )\n                .endFill();\n            this.decreaseBtnGraphics.alpha = 0;\n            this.decreaseBtn.addChild(this.decreaseBtnGraphics);\n            this.decreaseBtnGraphics.pivot.set(0, this.decreaseBtnGraphics.height / 2);\n        }\n        this.decreaseBtnGraphics.interactive = interactive;\n        this.decreaseBtnGraphics.cursor = 'pointer';\n    }\n}\n","import Core from '@egt/core';\nimport { ViewContainer } from '@egt/ui-lib';\nimport { NineSlicePlane, Text } from 'pixi.js';\nimport { IBuyBonusComponentConfigurationExtendedMultipleBuyBonus } from '../configuration/IBuyBonusComponentConfigurationExtendedMultipleBuyBonus';\n\nexport default class ExtendedMultipleBuyBonusInfoText extends ViewContainer {\n    private text: Text;\n    private background: NineSlicePlane;\n    private gradientOffset: number = 30;\n    private shouldBeVisible: boolean = false;\n    private landscapeYOffset: number = 0;\n\n    private readonly portraitHorizontalMargin: number = 5;\n\n    constructor(private componentConfiguration: IBuyBonusComponentConfigurationExtendedMultipleBuyBonus) {\n        super();\n        this.createInfoText();\n    }\n\n    private createInfoText(): void {\n        this.background = new NineSlicePlane(\n            Core.assets.getTextureFromSpriteSheet('extendedMultipleBuyBonusMainAssets', 'infoBarBackground.png'),\n            50,\n            2,\n            50,\n            2,\n        );\n        this.addChild(this.background);\n\n        this.text = new Text('', this.componentConfiguration.infoText.infoTextStyle);\n        this.text.anchor.set(0.5);\n        this.addChild(this.text);\n        this.hideInfoText();\n    }\n\n    public showInfoText(activeText: string): void {\n        this.text.text = Core.translator.translate(activeText);\n        this.updateBackgroundPosition();\n\n        this.shouldBeVisible = true;\n        this.visible = true;\n    }\n\n    public hideInfoText(): void {\n        this.shouldBeVisible = false;\n        this.visible = false;\n    }\n\n    public setOrientation(): void {\n        const yOffset: number = Core.ORIENTATION.value.isLandscape ? this.landscapeYOffset : 0;\n        this.text.x = this.componentConfiguration.infoText.x;\n        this.text.y = this.componentConfiguration.infoText.y + yOffset;\n\n        this.updateBackgroundPosition();\n    }\n\n    public infoMessageYOffsetLandscape(offset: number): void {\n        this.landscapeYOffset = offset;\n        this.setOrientation();\n    }\n\n    private updateBackgroundPosition(): void {\n        this.updateTextScale();\n        this.background.width = this.text.width + this.gradientOffset * 2;\n        this.background.x =\n            this.text.x +\n            this.componentConfiguration.infoText.infoTextOffsetX -\n            this.text.width / 2 -\n            this.gradientOffset;\n        // this.background.y = this.text.y - this.text.height / 2 + this.componentConfiguration.infoText.infoTextOffset;\n        this.background.y =\n            this.text.y - this.background.height / 2 + this.componentConfiguration.infoText.infoTextOffset;\n    }\n\n    private updateTextScale(): void {\n        this.text.scale.set(1);\n\n        if (Core.ORIENTATION.value.isLandscape) {\n            return;\n        }\n\n        const stageWidth = Core.display.stage.width;\n        const maxHalfWidth = Math.min(this.text.x, stageWidth - this.text.x);\n        const maxTextWidth = maxHalfWidth * 2 - this.gradientOffset * 2 - this.portraitHorizontalMargin * 2;\n\n        if (maxTextWidth > 0 && this.text.width > maxTextWidth) {\n            this.text.scale.set(maxTextWidth / this.text.width);\n        }\n        this.background.y =\n            this.text.y - this.background.height / 2 + this.componentConfiguration.infoText.infoTextOffset;\n    }\n}\n","import Core, {\n    AssetPriority,\n    AssetsCollection,\n    BaseComponentConfiguration,\n    DefaultAssets,\n    DefaultValue,\n    DynamicPositionObject,\n    type IAsset,\n} from '@egt/core';\nimport { TextStyle } from 'pixi.js';\nimport {\n    IBuyBonusOverlaySettings,\n    IBuyBonusPopupHitAreaGraphics,\n    IBuyBonusTileOpacity,\n    IMultipleBuyBonusPositionPoint,\n    IMultipleBuyBonusTextInterface,\n    ITilePositionPoint,\n} from '../interfaces/InterfacesMultipleBuyBonus';\nimport { IBuyBonusComponentConfigurationMultipleBuyBonus } from './IBuyBonusComponentConfigurationMultipleBuyBonus';\n\nexport default class BuyBonusComponentConfigurationMultipleBuyBonus extends BaseComponentConfiguration {}\n\nexport function BuyBonusComponentConfigurationFactoryMultipleBuyBonus(): any {\n    const svgAsset = (id: string, width: number, height: number, desktopHeight = height): IAsset => ({\n        id,\n        url: '../assets/' + Core.configuration.gameKey + '/components/buy-bonus/multiple-buy-bonus/svg/' + id + '.svg',\n        priority: AssetPriority.HIGHEST,\n        type: 'svg',\n        config: {\n            mobile: { width, height },\n            desktop: { width, height: desktopHeight },\n        },\n    });\n\n    class MultipleBuyBonusConfigurationInternalClass\n        extends BuyBonusComponentConfigurationMultipleBuyBonus\n        implements IBuyBonusComponentConfigurationMultipleBuyBonus\n    {\n        @DefaultAssets([\n            svgAsset('arrowMinusActive', 90, 106),\n            svgAsset('arrowMinusInactive', 90, 106),\n            svgAsset('arrowPlusActive', 90, 106),\n            svgAsset('arrowPlusInactive', 90, 106),\n            svgAsset('betBase', 276, 118),\n            svgAsset('btnClose', 78, 78),\n            svgAsset('btnConfirmActive', 405, 120),\n            svgAsset('btnConfirmAnimation', 405, 120),\n            svgAsset('btnConfirmInactive', 405, 120),\n            svgAsset('popUpBase', 634, 948, 674),\n            svgAsset('popUpBaseDesktop', 634, 948, 674),\n            svgAsset('titleBase', 480, 90),\n        ])\n        public assets: AssetsCollection;\n\n        public get translatableAssets(): IAsset[] {\n            return [\n                {\n                    id: 'multipleBuyBonus',\n                    url:\n                        '../assets/' +\n                        Core.configuration.gameKey +\n                        '/components/buy-bonus/multiple-buy-bonus/multipleBuyBonus_' +\n                        Core.configuration.language.toLowerCase() +\n                        '.json',\n                    priority: AssetPriority.HIGHEST,\n                    type: 'texture',\n                },\n            ];\n        }\n\n        // -------------- TILE CONFIGURATION --------------\n        @DefaultValue<IBuyBonusTileOpacity>({\n            defaults: {\n                textOn: 1,\n                textOff: 1,\n                textActivated: 0,\n                tileOn: 1,\n                tileOff: 0.7,\n                tileActivated: 1,\n            },\n        })\n        public tileOpacity: DynamicPositionObject<IBuyBonusTileOpacity> & IBuyBonusTileOpacity;\n\n        @DefaultValue<ITilePositionPoint>({\n            defaults: {\n                x: 230,\n                y: 356,\n                scale: 0.5,\n                visible: true,\n                leftHandX: 0,\n            },\n            landscape: { leftHandX: 1286 },\n            portrait: {\n                x: 693,\n                y: 1158,\n            },\n        })\n        public tilePosition: DynamicPositionObject<ITilePositionPoint> & ITilePositionPoint;\n\n        @DefaultValue<IMultipleBuyBonusTextInterface>({\n            defaults: {\n                x: 0,\n                y: 80,\n                offSetY: 0,\n                textStyle: new TextStyle({\n                    fontFamily: 'Nunito-Black',\n                    align: 'center',\n                    fill: ['#FFFFFF', '#FFFDCF', '#FFC8A0'],\n                    fillGradientStops: [0.2, 0.6],\n                    fontSize: 66,\n                    strokeThickness: 7,\n                    stroke: '#820066',\n                    dropShadow: true,\n                    dropShadowDistance: 7,\n                    dropShadowBlur: 7,\n                    dropShadowColor: '#000000',\n                    dropShadowAlpha: 0.6,\n                    dropShadowAngle: 90,\n                }),\n            },\n        })\n        public buttonTextMoney: DynamicPositionObject<IMultipleBuyBonusTextInterface> & IMultipleBuyBonusTextInterface;\n\n        @DefaultValue<IMultipleBuyBonusPositionPoint>({\n            defaults: {\n                x: 0,\n                y: 0,\n                width: 100,\n                height: 33,\n            },\n        })\n        public buttonTextMoneyBounds: DynamicPositionObject<IMultipleBuyBonusPositionPoint> &\n            IMultipleBuyBonusPositionPoint;\n\n        @DefaultValue<IMultipleBuyBonusTextInterface>({\n            defaults: {\n                x: 0,\n                y: 15,\n                offSetY: 25,\n                textStyle: new TextStyle({\n                    fontFamily: 'Nunito-Black',\n                    align: 'center',\n                    fill: '#FFFFFF',\n                    fontSize: 34,\n                    strokeThickness: 4,\n                    stroke: '#820066',\n                    dropShadow: true,\n                    dropShadowDistance: 4,\n                    dropShadowBlur: 4,\n                    dropShadowColor: '#000000',\n                    dropShadowAlpha: 0.6,\n                    dropShadowAngle: 90,\n                }),\n            },\n        })\n        public buttonTextCurrency: DynamicPositionObject<IMultipleBuyBonusTextInterface> &\n            IMultipleBuyBonusTextInterface;\n\n        @DefaultValue<IMultipleBuyBonusTextInterface>({\n            defaults: {\n                x: 0,\n                y: -15,\n                offSetY: 0,\n                textStyle: new TextStyle({\n                    fontFamily: 'Nunito-Black',\n                    align: 'center',\n                    fill: '#FFFFFF',\n                    fontSize: 34,\n                    lineHeight: 34,\n                    strokeThickness: 4,\n                    stroke: '#820066',\n                    wordWrap: true,\n                    wordWrapWidth: 250,\n                }),\n            },\n        })\n        public buttonTextMaxBet: DynamicPositionObject<IMultipleBuyBonusTextInterface> & IMultipleBuyBonusTextInterface;\n        // ---------- END OF TILE CONFIGURATION ----------\n\n        // ---------- POPUP CONFIGURATION ----------\n        @DefaultValue<IBuyBonusOverlaySettings>({\n            defaults: {\n                color: 0x000000,\n                opacity: 0.6,\n            },\n        })\n        public overlay: DynamicPositionObject<IBuyBonusOverlaySettings> & IBuyBonusOverlaySettings;\n\n        @DefaultValue<IBuyBonusPopupHitAreaGraphics>({\n            defaults: {\n                color: 0x000000,\n                rectangleAlpha: 0,\n                x: -293,\n                y: 300,\n                width: 586,\n                height: 600,\n                alpha: 0,\n            },\n        })\n        public popupHitAreaGraphics: DynamicPositionObject<IBuyBonusPopupHitAreaGraphics> &\n            IBuyBonusPopupHitAreaGraphics;\n\n        public popupContainerPosition: Array<DynamicPositionObject<IMultipleBuyBonusPositionPoint>> = [\n            new DynamicPositionObject<IMultipleBuyBonusPositionPoint>({\n                defaults: {\n                    x: 0,\n                    y: 62,\n                    width: 646,\n                    height: 686,\n                },\n                portrait: {\n                    y: 236,\n                    height: 960,\n                },\n            }),\n            new DynamicPositionObject<IMultipleBuyBonusPositionPoint>({\n                defaults: {\n                    x: 0,\n                    y: 54,\n                    width: 736,\n                    height: 698,\n                },\n                portrait: {\n                    y: 236,\n                    height: 924,\n                },\n            }),\n            new DynamicPositionObject<IMultipleBuyBonusPositionPoint>({\n                defaults: {\n                    x: 0,\n                    y: 45,\n                    width: 852,\n                    height: 692,\n                },\n                portrait: {\n                    y: 263,\n                    width: 736,\n                    height: 877,\n                },\n            }),\n        ];\n\n        @DefaultValue<IMultipleBuyBonusPositionPoint>({\n            defaults: {\n                x: 0,\n                y: 0,\n                width: 480,\n                height: 90,\n            },\n            portrait: {\n                y: -1,\n            },\n        })\n        public titleBasePosition: DynamicPositionObject<IMultipleBuyBonusPositionPoint> &\n            IMultipleBuyBonusPositionPoint;\n\n        public btnClosePosition: Array<DynamicPositionObject<IMultipleBuyBonusPositionPoint>> = [\n            new DynamicPositionObject<IMultipleBuyBonusPositionPoint>({\n                defaults: {\n                    x: 947,\n                    y: 31,\n                    width: 78,\n                    height: 78,\n                },\n                portrait: {\n                    x: 649,\n                    y: 205,\n                },\n            }),\n            new DynamicPositionObject<IMultipleBuyBonusPositionPoint>({\n                defaults: {\n                    x: 982,\n                    y: 23,\n                    width: 78,\n                    height: 78,\n                },\n                portrait: {\n                    x: 684,\n                    y: 205,\n                },\n            }),\n            new DynamicPositionObject<IMultipleBuyBonusPositionPoint>({\n                defaults: {\n                    x: 1052,\n                    y: 23,\n                    width: 78,\n                    height: 78,\n                },\n                portrait: {\n                    x: 685,\n                    y: 236,\n                },\n            }),\n        ];\n\n        public betBasePosition: Array<DynamicPositionObject<IMultipleBuyBonusPositionPoint>> = [\n            new DynamicPositionObject<IMultipleBuyBonusPositionPoint>({\n                defaults: {\n                    x: 0,\n                    y: 510,\n                    width: 276,\n                    height: 118,\n                },\n                portrait: {\n                    y: 768,\n                },\n            }),\n            new DynamicPositionObject<IMultipleBuyBonusPositionPoint>({\n                defaults: {\n                    x: 0,\n                    y: 534,\n                    width: 256,\n                    height: 102,\n                },\n                portrait: {\n                    y: 738,\n                },\n            }),\n            new DynamicPositionObject<IMultipleBuyBonusPositionPoint>({\n                defaults: {\n                    x: 0,\n                    y: 529,\n                    width: 256,\n                    height: 102,\n                },\n                portrait: {\n                    y: 692,\n                },\n            }),\n        ];\n\n        @DefaultValue<IMultipleBuyBonusTextInterface>({\n            defaults: {\n                x: 0,\n                y: 0,\n                offSetY: 0,\n                textStyle: new TextStyle({\n                    fontFamily: 'Roboto-Bold',\n                    align: 'center',\n                    fill: '#E9E8FF',\n                    fontSize: 50,\n                }),\n            },\n        })\n        public betValueProperties: DynamicPositionObject<IMultipleBuyBonusTextInterface> &\n            IMultipleBuyBonusTextInterface;\n\n        @DefaultValue<IMultipleBuyBonusTextInterface>({\n            defaults: {\n                x: 0,\n                y: 0,\n                offSetY: 5,\n                textStyle: new TextStyle({\n                    fontFamily: 'Roboto-Bold',\n                    align: 'center',\n                    fill: '#FFD200',\n                    fontSize: 20,\n                }),\n            },\n        })\n        public betTextProperties: DynamicPositionObject<IMultipleBuyBonusTextInterface> &\n            IMultipleBuyBonusTextInterface;\n\n        @DefaultValue<IMultipleBuyBonusTextInterface>({\n            defaults: {\n                x: 0,\n                y: -7,\n                offSetY: 0,\n                textStyle: new TextStyle({\n                    fontFamily: 'Roboto-Bold',\n                    align: 'center',\n                    fill: '#FFD200',\n                    fontSize: 24,\n                }),\n            },\n        })\n        public balanceTextProperties: DynamicPositionObject<IMultipleBuyBonusTextInterface> &\n            IMultipleBuyBonusTextInterface;\n\n        public balanceValueProperties: Array<DynamicPositionObject<IMultipleBuyBonusTextInterface>> = [\n            new DynamicPositionObject<IMultipleBuyBonusTextInterface>({\n                defaults: {\n                    x: 0,\n                    y: 627,\n                    offSetY: 0,\n                    textStyle: new TextStyle({\n                        fontFamily: 'Roboto-Bold',\n                        align: 'center',\n                        fill: '#FFFFFF',\n                        fontSize: 36,\n                    }),\n                },\n                portrait: {\n                    y: 895,\n                },\n            }),\n            new DynamicPositionObject<IMultipleBuyBonusTextInterface>({\n                defaults: {\n                    x: 0,\n                    y: 650,\n                    offSetY: 0,\n                    textStyle: new TextStyle({\n                        fontFamily: 'Roboto-Bold',\n                        align: 'center',\n                        fill: '#FFFFFF',\n                        fontSize: 36,\n                    }),\n                },\n                portrait: {\n                    y: 864,\n                },\n            }),\n            new DynamicPositionObject<IMultipleBuyBonusTextInterface>({\n                defaults: {\n                    x: 0,\n                    y: 650,\n                    offSetY: 0,\n                    textStyle: new TextStyle({\n                        fontFamily: 'Roboto-Bold',\n                        align: 'center',\n                        fill: '#FFFFFF',\n                        fontSize: 36,\n                    }),\n                },\n                portrait: {\n                    y: 821,\n                },\n            }),\n        ];\n        // ---------- END OF POPUP CONFIGURATION ----------\n\n        // ----------- POP UP OPTION CONFIGURATION -----------\n        public buyFeatureOptionPosition: Array<DynamicPositionObject<IMultipleBuyBonusPositionPoint>> = [\n            new DynamicPositionObject<IMultipleBuyBonusPositionPoint>({\n                defaults: {\n                    x: 0,\n                    y: 54,\n                    width: 400,\n                    height: 429,\n                },\n                portrait: {\n                    y: 64,\n                    width: 616,\n                    height: 660,\n                },\n            }),\n            new DynamicPositionObject<IMultipleBuyBonusPositionPoint>({\n                defaults: {\n                    x: 0,\n                    y: 58,\n                    width: 298,\n                    height: 409,\n                },\n                portrait: {\n                    y: 122,\n                    width: 350,\n                    height: 481,\n                },\n            }),\n            new DynamicPositionObject<IMultipleBuyBonusPositionPoint>({\n                defaults: {\n                    x: 0,\n                    y: 53,\n                    width: 234,\n                    height: 424,\n                },\n                portrait: {\n                    y: 122,\n                },\n            }),\n        ];\n\n        public optionTextMaxBet: Array<DynamicPositionObject<IMultipleBuyBonusTextInterface>> = [\n            new DynamicPositionObject<IMultipleBuyBonusTextInterface>({\n                defaults: {\n                    x: 0,\n                    y: 330,\n                    offSetY: 0,\n                    textStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 28,\n                        align: 'center',\n                        fill: '#FFFFFF',\n                        strokeThickness: 2,\n                        stroke: '#AA005C',\n                    }),\n                },\n                portrait: {\n                    y: 488,\n                },\n            }),\n            new DynamicPositionObject<IMultipleBuyBonusTextInterface>({\n                defaults: {\n                    x: 0,\n                    y: 325,\n                    offSetY: 0,\n                    textStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 28,\n                        align: 'center',\n                        fill: '#FFFFFF',\n                        strokeThickness: 2,\n                        stroke: '#AA005C',\n                    }),\n                },\n                portrait: {\n                    y: 440,\n                },\n            }),\n            new DynamicPositionObject<IMultipleBuyBonusTextInterface>({\n                defaults: {\n                    x: 0,\n                    y: 333,\n                    offSetY: 0,\n                    textStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 28,\n                        align: 'center',\n                        fill: '#FFFFFF',\n                        strokeThickness: 2,\n                        stroke: '#AA005C',\n                    }),\n                },\n                portrait: {\n                    y: 417,\n                },\n            }),\n        ];\n\n        public popUpTextMoneyProperties: Array<DynamicPositionObject<IMultipleBuyBonusTextInterface>> = [\n            new DynamicPositionObject<IMultipleBuyBonusTextInterface>({\n                defaults: {\n                    x: 0,\n                    y: 340,\n                    offSetY: 0,\n                    textStyle: { fontName: 'BuyBonusFont', fontSize: 13, align: 'center' },\n                },\n                portrait: {\n                    y: 505,\n                    textStyle: { fontName: 'BuyBonusFont', fontSize: 20, align: 'center' },\n                },\n            }),\n            new DynamicPositionObject<IMultipleBuyBonusTextInterface>({\n                defaults: {\n                    x: 0,\n                    y: 366,\n                    offSetY: 0,\n                    textStyle: { fontName: 'BuyBonusFont', fontSize: 16, align: 'center' },\n                },\n                portrait: {\n                    y: 489,\n                },\n            }),\n            new DynamicPositionObject<IMultipleBuyBonusTextInterface>({\n                defaults: {\n                    x: 0,\n                    y: 379,\n                    offSetY: 0,\n                    textStyle: { fontName: 'BuyBonusFont', fontSize: 16, align: 'center' },\n                },\n                portrait: {\n                    y: 463,\n                },\n            }),\n        ];\n\n        public popUpTextCurrencyProperties: Array<DynamicPositionObject<IMultipleBuyBonusTextInterface>> = [\n            new DynamicPositionObject<IMultipleBuyBonusTextInterface>({\n                defaults: {\n                    x: 0,\n                    y: 0,\n                    offSetY: 10,\n                    textStyle: { fontName: 'BuyBonusFont', fontSize: 6, align: 'center' },\n                },\n                portrait: {\n                    offSetY: 14,\n                    textStyle: { fontName: 'BuyBonusFont', fontSize: 9, align: 'center' },\n                },\n            }),\n            new DynamicPositionObject<IMultipleBuyBonusTextInterface>({\n                defaults: {\n                    x: 0,\n                    y: 0,\n                    offSetY: 8,\n                    textStyle: { fontName: 'BuyBonusFont', fontSize: 11, align: 'center' },\n                },\n            }),\n            new DynamicPositionObject<IMultipleBuyBonusTextInterface>({\n                defaults: {\n                    x: 0,\n                    y: 0,\n                    offSetY: 8,\n                    textStyle: { fontName: 'BuyBonusFont', fontSize: 11, align: 'center' },\n                },\n            }),\n        ];\n\n        public popUpAmountBounds: Array<DynamicPositionObject<IMultipleBuyBonusPositionPoint>> = [\n            new DynamicPositionObject<IMultipleBuyBonusPositionPoint>({\n                defaults: {\n                    x: 0,\n                    y: 0,\n                    width: 234,\n                    height: 60,\n                },\n                portrait: {\n                    width: 360,\n                    height: 91,\n                },\n            }),\n            new DynamicPositionObject<IMultipleBuyBonusPositionPoint>({\n                defaults: {\n                    x: 0,\n                    y: 0,\n                    width: 234,\n                    height: 60,\n                },\n                portrait: {\n                    width: 360,\n                    height: 91,\n                },\n            }),\n            new DynamicPositionObject<IMultipleBuyBonusPositionPoint>({\n                defaults: {\n                    x: 0,\n                    y: 0,\n                    width: 234,\n                    height: 60,\n                },\n                portrait: {\n                    width: 360,\n                    height: 91,\n                },\n            }),\n        ];\n\n        public btnConfirmPosition: Array<DynamicPositionObject<IMultipleBuyBonusPositionPoint>> = [\n            new DynamicPositionObject<IMultipleBuyBonusPositionPoint>({\n                defaults: {\n                    x: 0,\n                    y: 408,\n                    width: 290,\n                    height: 93,\n                },\n                portrait: {\n                    y: 608,\n                    width: 405,\n                    height: 120,\n                },\n            }),\n            new DynamicPositionObject<IMultipleBuyBonusPositionPoint>({\n                defaults: {\n                    x: 0,\n                    y: 433,\n                    width: 240,\n                    height: 72,\n                },\n                portrait: {\n                    y: 572,\n                },\n            }),\n            new DynamicPositionObject<IMultipleBuyBonusPositionPoint>({\n                defaults: {\n                    x: 0,\n                    y: 443,\n                    width: 240,\n                    height: 72,\n                },\n                portrait: {\n                    y: 527,\n                },\n            }),\n        ];\n\n        // ----------- END OF POP UP OPTION CONFIGURATION -----------\n    }\n    return MultipleBuyBonusConfigurationInternalClass;\n}\n","import Core, { AnalyticsDispatcher, BaseController } from '@egt/core';\nimport {\n    BonusTypes,\n    FeatureController,\n    ISlotConfiguration,\n    InitialSettings,\n    RootStore,\n    ServerState,\n    SlotComponents,\n    Subjects,\n    UIState,\n} from '@egt/slot';\nimport { fromEvent } from 'rxjs';\nimport { filter, mapTo, takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport BuyBonusViewMultipleBuyBonus from '../views/BuyBonusViewMultipleBuyBonus';\n@injectable()\nexport default class BuyBonusControllerMultipleBuyBonus extends BaseController {\n    public ready: () => Promise<void>;\n\n    constructor(\n        @inject('BuyBonusView') protected view: BuyBonusViewMultipleBuyBonus,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('SlotSubjects') public readonly subjects: Subjects,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('FeatureController') protected featureController: FeatureController,\n    ) {\n        super(view);\n    }\n\n    public async onGameStarted(_initialSettings: any): Promise<void> {\n        this.subjects.FACTOR_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(this.onBuyBonusDisable.bind(this));\n        this.subjects.DISABLED_BUY_BONUS.pipe(takeUntil(this.DESTROY)).subscribe(this.onBuyBonusDisable.bind(this));\n        this.subjects.REELS_START.pipe(takeUntil(this.DESTROY)).subscribe(this.onReelsStart.bind(this));\n        this.subjects.GAMBLE_OPENED.pipe(takeUntil(this.DESTROY)).subscribe(this.onSettingsPopupOpened.bind(this));\n        this.rootStore.subjects.OPEN_SETTINGS_POPUP.pipe(takeUntil(this.DESTROY), mapTo(true)).subscribe(\n            this.onSettingsPopupOpened.bind(this, true),\n        );\n        this.rootStore.subjects.CLOSE_SETTINGS_POPUP.pipe(takeUntil(this.DESTROY), mapTo(false)).subscribe(\n            this.onSettingsPopupOpened.bind(this, false),\n        );\n        this.rootStore.subjects.KEY_UP.pipe(takeUntil(this.DESTROY)).subscribe(this.onKeyPressed.bind(this));\n        this.subjects.BUY_BONUS_AND_DOUBLE_CHANCE_VISIBLE.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.hideWhenRecovery.bind(this),\n        );\n        Core.ON_SERVER_MESSAGE.pipe(takeUntil(this.DESTROY)).subscribe(this.onServerMessage.bind(this));\n\n        this.onBuyBonusDisable();\n        this.view.init();\n        this.rootStore.uiStore.STATE.pipe(takeUntil(this.DESTROY)).subscribe(this.onStateChanged.bind(this));\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/multiple-buy-bonus/controllers/BuyBonusControllerMultipleBuyBonus.ts:52:9\",(this.view.buyFeatureButton),\"pointertap\"]), fromEvent(this.view.buyFeatureButton, 'pointertap'))\n            .pipe(\n                filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.onBuyFeatureClicked.bind(this));\n\n        for (let i: number = 0; i < this.view.btnConfirm.length; i++) {\n            (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/multiple-buy-bonus/controllers/BuyBonusControllerMultipleBuyBonus.ts:60:13\",(this.view.btnConfirm[i]),\"pointertap\"]), fromEvent(this.view.btnConfirm[i], 'pointertap'))\n                .pipe(takeUntil(this.DESTROY))\n                .subscribe(this.onBuyConfirmed.bind(this));\n        }\n\n        if (Core.isReplayer) {\n            Core.REPLAYER_ACTION.pipe(\n                filter((p) => p.module === SlotComponents.BUY_BONUS),\n                takeUntil(this.DESTROY),\n            ).subscribe((params) => {\n                this.view.state = params.data;\n            });\n        }\n\n        // fromEvent(this.view.btnConfirm, 'pointertap')\n        //     .pipe(takeUntil(this.DESTROY))\n        //     .subscribe(this.onBuyConfirmed.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/multiple-buy-bonus/controllers/BuyBonusControllerMultipleBuyBonus.ts:78:9\",(this.view.btnClose),\"pointertap\"]), fromEvent(this.view.btnClose, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onCancelClicked.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/multiple-buy-bonus/controllers/BuyBonusControllerMultipleBuyBonus.ts:82:9\",(this.view.overlay),\"pointertap\"]), fromEvent(this.view.overlay, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onCancelClicked.bind(this));\n\n        if (\n            this.settings.state === ServerState.FREESPIN &&\n            this.settings.settings.game.state.rounds?.filter((round) => round.type === 'FREESPIN')[0]?.count !==\n                this.settings.settings.game.state.rounds?.filter((round) => round.type === 'FREESPIN')[0]?.remain\n        ) {\n            this.view.state = 'Off';\n            await this.ready();\n            this.view.visible = false;\n        }\n        if (\n            this.settings.state === ServerState.IDLE ||\n            (this.rootStore.domainStore.betResponse &&\n                this.rootStore.domainStore.betResponse.bonus &&\n                this.rootStore.domainStore.betResponse.bonus.type !== BonusTypes.GIFT_SPIN &&\n                this.rootStore.domainStore.betResponse.bonus.type !== BonusTypes.BUY_BONUS)\n        ) {\n            this.view.state = 'On';\n        } else {\n            this.view.state = 'Off';\n        }\n        if (this.settings.settings.game && this.settings.state !== ServerState.IDLE) {\n            this.view.recovery = true;\n        }\n    }\n\n    private onBuyFeatureClicked(): void {\n        if (this.view.state === 'Off' || this.rootStore.subjects.SHOW_JP_STATS.value.type !== -1) {\n            return;\n        }\n        AnalyticsDispatcher.buyBonusClickEvent();\n        this.rootStore.subjects.CLOSE_ALL_POPUPS.next();\n        this.rootStore.subjects.TAB_OPENED.next(true);\n        Core.sounds.play('buyBonus');\n        this.view.state = 'Off';\n        this.subjects.DISABLED_DOUBLE_CHANCE.next(true);\n\n        if (this.rootStore.domainStore.SERVER_STATE?.value === ServerState.WIN) {\n            this.rootStore.domainStore.collect();\n            this.rootStore.uiStore.COLLECT_CHANGED.next();\n        }\n\n        this.view.showPopUp();\n    }\n\n    private onBuyConfirmed(): void {\n        if (this.rootStore.uiStore.STATE.value === UIState.DISABLED) {\n            return;\n        }\n        const win = this.rootStore.uiStore.WIN.value.amount || 0;\n        this.rootStore.subjects.MODAL_PRESSED.next();\n        Core.sounds.play('buyBonusYes');\n\n        this.subjects.DISABLED_DOUBLE_CHANCE.next(false);\n        this.view.finalBetAmount = true;\n        this.view.closePopUp();\n\n        // change denomination when bet confirmed\n        this.rootStore.uiStore.SELECTED_BET.next(this.view.finalBet);\n        this.rootStore.subjects.SETTINGS_BET_CHANGED.next();\n        this.rootStore.subjects.CHANGE_SELECTED_BET_BTN_EXTERNALLY.next({\n            betVal: this.rootStore.uiStore.SELECTED_BET.value,\n            changedFromPopUp: false,\n        });\n        Core.SELECTED_DENOMINATION.next(this.view.finalDenomination);\n        const settingsDenomination = this.settings.denominations.indexOf(this.view.finalDenomination) + 1;\n        this.rootStore.subjects.SETTINGS_DENOMINATION_CHANGED.next({\n            denomination: settingsDenomination,\n            playDenomChangeSound: false,\n        });\n        this.settings.factor = this.settings.getFactorByUniqueGameMode('BUY_BONUS');\n        this.settings.gameMode = 'BUY_BONUS';\n\n        this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_RESPONSE);\n        this.rootStore.subjects.CLOSE_ALL_POPUPS.next();\n        this.rootStore.subjects.BEFORE_SPIN.next();\n        this.rootStore.subjects.SPIN_STARTED.next();\n\n        this.rootStore.uiStore.BALANCE.next(this.rootStore.uiStore.BALANCE.value - this.getBetAmount() + win);\n        this.rootStore.domainStore.bet();\n        this.settings.factor = this.settings.getFactorByUniqueGameMode('NORMAL_MODE');\n        this.settings.gameMode = 'NORMAL_MODE';\n        this.view.state = 'Activated';\n        if (Core.sounds.isPlaying('backgroundNoPlay')) {\n            this.rootStore.uiStore.BACKGROUND_SOUND_PLAY.next({ sound: 'backgroundMusic', ms: 800 });\n        }\n    }\n\n    private onBuyCanceled(): void {\n        this.view.state = 'On';\n        this.subjects.DISABLED_DOUBLE_CHANCE.next(false);\n        this.view.closePopUp();\n    }\n\n    private onCancelClicked(): void {\n        this.onBuyCanceled();\n        Core.sounds.play('buyBonusNo');\n    }\n\n    private onStateChanged(): void {\n        if (\n            this.view.state === 'Activated' &&\n            (this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_RESPONSE ||\n                this.rootStore.uiStore.STATE.value === UIState.FREESPIN)\n        ) {\n            return;\n        }\n        if (this.view.popUpOpened) {\n            this.subjects.DISABLED_DOUBLE_CHANCE.next(true);\n            return;\n        }\n\n        if (\n            this.rootStore.settings.haveGameMode('DOUBLE_CHANCE') &&\n            this.settings.factor !== this.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE') &&\n            (this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value === 0 ||\n                this.rootStore.subjects.SPECIAL_STOP_CONDITION_REACHED.value) &&\n            this.rootStore.domainStore.SERVER_STATE.value !== ServerState.BONUS_SUMMARY &&\n            (this.rootStore.uiStore.STATE.value === UIState.IDLE ||\n                this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT) &&\n            !this.rootStore.uiStore.fastSpinMode &&\n            (!this.rootStore.domainStore.betResponse?.bonus ||\n                this.rootStore.domainStore.betResponse?.bonus?.remaining === 0) &&\n            this.checkForMaxBet()\n        ) {\n            this.view.state = 'On';\n            this.rootStore.subjects.DISABLED_BUY_BONUS.next({ disabled: false, doNotChangeVisual: false });\n        } else {\n            this.view.state = 'Off';\n        }\n    }\n\n    private checkForMaxBet(): boolean {\n        const buyBonusValue: number =\n            this.rootStore.settings.buyBonusOptions[0] *\n            Core.SELECTED_DENOMINATION.value *\n            this.rootStore.uiStore.SELECTED_BET.value;\n        const limits = this.settings.clientSettings?.maxBetLimits;\n\n        if (limits && buyBonusValue > limits[Core.PLAYER_BALANCE.value.currency] * 100) {\n            return false;\n        }\n        return true;\n    }\n\n    private onBuyBonusDisable(): void {\n        if (\n            this.rootStore.subjects.DISABLED_BUY_BONUS.value.disabled ||\n            this.subjects.GAMBLE_OPENED.value ||\n            (this.rootStore.settings.haveGameMode('DOUBLE_CHANCE') &&\n                this.settings.factor === this.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE')) ||\n            this.rootStore.domainStore.SERVER_STATE.value === ServerState.BONUS_IDLE ||\n            (this.rootStore.domainStore.betResponse &&\n                this.rootStore.domainStore.betResponse.bonus &&\n                (this.rootStore.domainStore.betResponse.bonus.type === BonusTypes.GIFT_SPIN ||\n                    this.rootStore.domainStore.betResponse.bonus.type === BonusTypes.BUY_BONUS) &&\n                this.rootStore.domainStore.betResponse.state === ServerState.WIN)\n        ) {\n            this.view.state = 'Off';\n        } else {\n            this.view.state = 'On';\n        }\n    }\n\n    private getBetAmount(): number {\n        return (\n            this.rootStore.uiStore.SELECTED_BET.value *\n            this.settings.buyBonusOptions[0] *\n            Core.SELECTED_DENOMINATION.value\n        );\n    }\n\n    private onSettingsPopupOpened(opened?: boolean): void {\n        if (opened || this.subjects.GAMBLE_OPENED.value || this.featureController.isInGiftSpins) {\n            this.view.state = 'Off';\n            if (this.view.popUpOpened) {\n                this.view.closePopUp();\n            }\n        } else if (\n            this.rootStore.settings.haveGameMode('DOUBLE_CHANCE') &&\n            this.settings.factor !== this.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE')\n        ) {\n            this.view.state = 'On';\n            this.subjects.DISABLED_DOUBLE_CHANCE.next(false);\n        }\n    }\n\n    private onKeyPressed(e: KeyboardEvent): void {\n        if (e === null) {\n            return;\n        }\n        // close modal when popup if space/enter/letter/digit is pressed\n        if (\n            this.view.overlay.visible &&\n            ((e.code !== undefined &&\n                (e.code === 'Space' ||\n                    e.code === 'Enter' ||\n                    e.code === 'NumpadEnter' ||\n                    e.code === 'ArrowDown' ||\n                    e.code.indexOf('key') !== -1 ||\n                    e.code.indexOf('Digit') !== -1)) ||\n                (e.keyCode !== undefined && (e.keyCode === 32 || e.keyCode === 13)) ||\n                (e.keyCode >= 65 && e.keyCode <= 90) ||\n                (e.keyCode >= 48 && e.keyCode <= 57))\n        ) {\n            this.onCancelClicked();\n        }\n    }\n\n    private onReelsStart(): void {\n        this.view.recovery = false;\n        if (this.view.popUpOpened) {\n            this.view.closePopUp();\n        }\n    }\n\n    private onServerMessage(response): void {\n        switch (response.event) {\n            case 'spin':\n                if (\n                    response.state === ServerState.WIN &&\n                    this.rootStore.settings.haveGameMode('DOUBLE_CHANCE') &&\n                    this.settings.factor !== this.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE') &&\n                    this.rootStore.domainStore.SERVER_STATE.value !== ServerState.BONUS_IDLE\n                ) {\n                    this.view.state = 'On';\n                }\n                break;\n            case 'balance':\n                if (!this.view.popUpContainer.visible) {\n                    this.onStateChanged();\n                }\n                break;\n        }\n    }\n\n    private hideWhenRecovery(zOrder: number): void {\n        this.view.visible = Boolean(zOrder);\n\n        this.view.zIndex = zOrder;\n    }\n}\n","import Core, { Money } from '@egt/core';\nimport {\n    BangupActionConsts,\n    BonusTypes,\n    Features,\n    ISlotConfiguration,\n    InitialSettings,\n    RootStore,\n    ServerState,\n    UIState,\n} from '@egt/slot';\nimport { MoneyText, MoneyTextConfig, ViewContainer } from '@egt/ui-lib';\nimport gsap from 'gsap';\nimport { BitmapText, Graphics, Sprite, Text } from 'pixi.js';\nimport { fromEvent, merge } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { IBuyBonusComponentConfigurationMultipleBuyBonus } from '../configuration/IBuyBonusComponentConfigurationMultipleBuyBonus';\n\n@injectable()\nexport default class BuyBonusViewMultipleBuyBonus extends ViewContainer {\n    public btnConfirm: Sprite[] = [];\n    public btnClose: Sprite;\n\n    public overlay: Graphics;\n    public recovery: boolean = false;\n\n    public popUpOpened: boolean = false;\n    public popUpContainer: Sprite;\n    private popUpBackground: Sprite;\n    private titleBase: Sprite;\n    private titleText: Sprite;\n    private arrowMinus: Sprite;\n    private arrowMinusGraphics: Graphics;\n    private arrowPlus: Sprite;\n    private arrowPlusGraphics: Graphics;\n    private betBase: Sprite;\n\n    private betContainer: Sprite;\n    private betText: Text;\n    private currencyText: Text;\n    private nextBet: string;\n    private betValue: Text;\n    private higherDenominationBetsMap: Map<string, { denomination: number; bet: number }> = new Map();\n    private betValuesArray: string[] = [];\n    public finalBetAmount: boolean = false;\n\n    private balanceContainer: Sprite;\n    private balanceText: Text;\n    private balanceValue: MoneyText;\n\n    public buyFeatureButton: Sprite;\n    private buttonTextMoney: Text;\n    private buttonTextCurrency: Text;\n    protected buttonTextMaxBet: Text;\n    private _state: 'On' | 'Off' | 'Activated';\n    private maxBetLimitHit: boolean = false;\n    private lastAvailableBetReached: boolean = false;\n    private maxBetOptionHit: boolean[] = [];\n\n    private money: Money[] = [];\n    private buyFeatureOption: Sprite[] = [];\n    private buyAmountHolder: Sprite[] = [];\n    private popUpTextMoney: BitmapText[] = [];\n    private popUpTextCurrency: BitmapText[] = [];\n    private optionTextMaxBet: Text[] = [];\n\n    public finalDenomination: number;\n    public finalBet: number;\n\n    private tweensDelayedCreation: any = null;\n    private scaleIntervals: any[] = [];\n    private scaleTweens: any[] = [];\n    private lightTweens: any[] = [];\n\n    private buyOptionsIndex: number;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('BuyBonusComponentConfiguration')\n        protected componentConfiguration: IBuyBonusComponentConfigurationMultipleBuyBonus,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n    ) {\n        super();\n        this.name = 'BuyBonusView';\n    }\n\n    public destroy(): void {\n        this.popUpContainer.removeChildren();\n        this.removeChild(this.popUpContainer);\n        this.popUpContainer.destroy();\n        this.btnClose.destroy();\n        super.destroy();\n    }\n\n    public init(): void {\n        this.buyOptionsIndex = this.rootStore.settings.buyBonusOptions.length - 1;\n        const orientation = merge(Core.ORIENTATION, Core.LEFT_HAND_MODE, this.rootStore.subjects.ACTIVE_FEATURE);\n        orientation.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n        Core.MONEY_MODE_IN_CREDITS.pipe(takeUntil(Core.ON_GAME_UNLOADED)).subscribe(this.onMoneyModeChanged.bind(this));\n        Core.SELECTED_DENOMINATION.pipe(takeUntil(Core.ON_GAME_UNLOADED)).subscribe(\n            this.onDenominationOrBetChanged.bind(this),\n        );\n        this.rootStore.uiStore.SELECTED_BET.pipe(takeUntil(Core.ON_GAME_UNLOADED)).subscribe(\n            this.onDenominationOrBetChanged.bind(this),\n        );\n        this.rootStore.uiStore.BALANCE.pipe(takeUntil(this.DESTROY)).subscribe(this.onBalanceChanged.bind(this));\n\n        this.createButton();\n        this.createPopUp();\n\n        this.setOrientation();\n        this.getBetValues();\n    }\n\n    public set state(value: 'On' | 'Off' | 'Activated') {\n        if (\n            (value === 'On' &&\n                this.money.length > 0 &&\n                this.money[this.money.length - 1].moneyInUnits >\n                    this.rootStore.uiStore.BALANCE.value + this.getWinAmount()) ||\n            (this.settings.state !== ServerState.IDLE && this.settings.state !== ServerState.WIN && this.recovery) ||\n            this.rootStore.domainStore.SPIN_MODE.value === Features.AUTO_PLAY\n        ) {\n            value = 'Off';\n        }\n        this.recovery = false;\n\n        if (this.maxBetLimitHit) {\n            value = 'Off';\n        }\n\n        if (this.buyFeatureButton) {\n            if (value === 'On') {\n                this.buyFeatureButton.cursor = 'pointer';\n                this.buyFeatureButton.interactive = true;\n            } else {\n                this.buyFeatureButton.cursor = 'normal';\n                this.buyFeatureButton.interactive = false;\n            }\n        }\n\n        this._state = value;\n        this.setState();\n    }\n\n    public get state(): 'On' | 'Off' | 'Activated' {\n        return this._state;\n    }\n\n    public showPopUp(): void {\n        this.popUpOpened = true;\n        this.popUpContainer.visible = true;\n        this.popUpBackground.visible = true;\n        this.titleBase.visible = true;\n        this.overlay.visible = true;\n        this.betValue.text = this.getCurrentBet();\n        this.balanceValue.money = this.rootStore.uiStore.BALANCE.value;\n        this.onDenominationOrBetChanged();\n        this.rootStore.subjects.BUY_BONUS_POPUP_OPENED.next(true);\n        this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(true);\n        this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(true);\n        this.rootStore.subjects.HIDE_BET_BUTTONS.next();\n        this.rootStore.subjects.SHOW_HIDE_MAIN_VIEW_COMPONENTS.next({\n            name: 'winContainer',\n            actions: 'visible',\n            values: false,\n        });\n        this.rootStore.subjects.SHOW_HIDE_MAIN_VIEW_COMPONENTS.next({\n            name: 'balanceContainer',\n            actions: 'visible',\n            values: false,\n        });\n        Core.UI_BLOCKER.next(true);\n    }\n\n    public closePopUp(): void {\n        this.popUpOpened = false;\n        if (this.popUpContainer && this.popUpContainer.visible) {\n            this.popUpContainer.visible = false;\n            this.popUpBackground.visible = false;\n            this.overlay.visible = false;\n            this.rootStore.subjects.BUY_BONUS_POPUP_OPENED.next(false);\n            this.rootStore.subjects.TAB_OPENED.next(false);\n            this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(false);\n            this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(false);\n            if (this.finalBetAmount) {\n                const denominationBetMap: { denomination: number; bet: number } = this.searchForDenomination(\n                    this.betValue.text,\n                    0,\n                    true,\n                );\n                this.finalBet = Number(denominationBetMap.bet);\n                this.finalDenomination = Number(denominationBetMap.denomination);\n            }\n        }\n        if (this.betValue) {\n            this.betValue.text = this.getCurrentBet();\n        }\n        this.finalBetAmount = false;\n        this.onDenominationOrBetChanged();\n        // destroy animation and timers\n        if (this.tweensDelayedCreation) {\n            this.tweensDelayedCreation.kill();\n            this.tweensDelayedCreation = null;\n        }\n        if (this.scaleIntervals?.length) {\n            for (let i = 0; i < this.scaleIntervals.length; i++) {\n                this.enableConfirmAnimation(false, i);\n            }\n        }\n        this.rootStore.subjects.SHOW_BET_BUTTONS.next();\n        this.rootStore.subjects.SHOW_HIDE_MAIN_VIEW_COMPONENTS.next({\n            name: 'winContainer',\n            actions: 'visible',\n            values: true,\n        });\n        this.rootStore.subjects.SHOW_HIDE_MAIN_VIEW_COMPONENTS.next({\n            name: 'balanceContainer',\n            actions: 'visible',\n            values: true,\n        });\n        Core.UI_BLOCKER.next(false);\n    }\n    private createButton(): void {\n        // create small plate\n        this.buyFeatureButton = new Sprite();\n        this.buyFeatureButton.name = 'Buy bonus button';\n        this.buyFeatureButton.interactive = true;\n        this.addChild(this.buyFeatureButton);\n        this.buyFeatureButton.anchor.set(0.5);\n\n        if (this.money.length === 1) {\n            this.buttonTextMoney = new Text(\n                this.money[0].stringMoneyWithoutCents,\n                this.componentConfiguration.buttonTextMoney.textStyle,\n            );\n            this.buttonTextMoney.resolution = 2;\n            this.buttonTextMoney.anchor.set(0.5);\n            this.buyFeatureButton.addChild(this.buttonTextMoney);\n\n            this.buttonTextCurrency = new Text(\n                this.rootStore.uiStore.currency,\n                this.componentConfiguration.buttonTextCurrency.textStyle,\n            );\n            this.buttonTextCurrency.resolution = 2;\n            this.buttonTextCurrency.anchor.set(0.5);\n            this.buyFeatureButton.addChild(this.buttonTextCurrency);\n\n            this.buttonTextMaxBet = new Text(\n                Core.translator.translate('MAX_BET'),\n                this.componentConfiguration.buttonTextMaxBet.textStyle,\n            );\n            this.buttonTextMaxBet.resolution = 2;\n            this.buttonTextMaxBet.visible = false;\n            this.buttonTextMaxBet.name = 'Max bet button';\n            this.buttonTextMaxBet.anchor.set(0.5, 0);\n            this.buyFeatureButton.addChild(this.buttonTextMaxBet);\n        }\n    }\n\n    private setState(): void {\n        if (!this.buyFeatureButton) {\n            return;\n        }\n\n        if (Core.ORIENTATION.value.isLandscape) {\n            this.buyFeatureButton.texture = Core.assets.getTextureFromSpriteSheet(\n                'multipleBuyBonus',\n                'buyFeature' + this._state + 'Landscape.png',\n            );\n        } else {\n            this.buyFeatureButton.texture = Core.assets.getTextureFromSpriteSheet(\n                'multipleBuyBonus',\n                'buyFeature' + this._state + 'Portrait.png',\n            );\n        }\n        this.updateButtonTextsOpacity();\n    }\n\n    private updateButtonTextsOpacity(): void {\n        if (this.buyFeatureButton) {\n            let textOpacity: number = this.componentConfiguration.tileOpacity.textOn;\n            let btnOpacity: number = this.componentConfiguration.tileOpacity.tileOn;\n            this.buyFeatureButton.cursor = 'pointer';\n            this.buyFeatureButton.interactive = true;\n            if (this.state === 'Off') {\n                textOpacity = this.componentConfiguration.tileOpacity.textOff;\n                btnOpacity = this.componentConfiguration.tileOpacity.tileOff;\n                this.buyFeatureButton.cursor = 'normal';\n                this.buyFeatureButton.interactive = false;\n            } else if (this.state === 'Activated') {\n                textOpacity = this.componentConfiguration.tileOpacity.textActivated;\n                btnOpacity = this.componentConfiguration.tileOpacity.tileActivated;\n                this.buyFeatureButton.cursor = 'normal';\n                this.buyFeatureButton.interactive = false;\n            }\n            this.buyFeatureButton.alpha = btnOpacity;\n            if (this.buttonTextMoney && this.buttonTextCurrency) {\n                this.buttonTextMoney.alpha = textOpacity;\n                this.buttonTextCurrency.alpha = textOpacity;\n            }\n        }\n    }\n\n    private setPositionsButton(): void {\n        if (!this.buyFeatureButton) {\n            return;\n        }\n        this.setState();\n\n        this.buyFeatureButton.scale.set(this.componentConfiguration.tilePosition.scale);\n        this.buyFeatureButton.x = this.componentConfiguration.tilePosition.x;\n        this.buyFeatureButton.y = this.componentConfiguration.tilePosition.y;\n        this.buyFeatureButton.visible = this.componentConfiguration.tilePosition.visible !== false;\n\n        let scaleFactor: number = 1;\n        if (this.buttonTextMoney) {\n            this.buttonTextMoney.y = this.componentConfiguration.buttonTextMoney.y;\n            this.buttonTextMoney.scale.set(scaleFactor);\n            this.buttonTextCurrency.y = this.componentConfiguration.buttonTextCurrency.y;\n            if (\n                this.buttonTextMoney.width * this.componentConfiguration.tilePosition.scale >\n                this.componentConfiguration.buttonTextMoneyBounds.width\n            ) {\n                scaleFactor =\n                    this.componentConfiguration.buttonTextMoneyBounds.width /\n                    (this.buttonTextMoney.width * this.componentConfiguration.tilePosition.scale);\n                this.buttonTextMoney.scale.set(scaleFactor);\n            }\n\n            if (\n                this.buttonTextMaxBet.width * this.componentConfiguration.tilePosition.scale >\n                this.componentConfiguration.buttonTextMoneyBounds.width\n            ) {\n                scaleFactor =\n                    this.componentConfiguration.buttonTextMoneyBounds.width /\n                    (this.buttonTextMaxBet.width * this.componentConfiguration.tilePosition.scale);\n                this.buttonTextMaxBet.scale.set(scaleFactor);\n            } else if (\n                this.buttonTextMaxBet.height * this.componentConfiguration.tilePosition.scale >\n                this.componentConfiguration.buttonTextMoneyBounds.height\n            ) {\n                this.buttonTextMaxBet.scale.set(1);\n                scaleFactor =\n                    this.componentConfiguration.buttonTextMoneyBounds.height /\n                    (this.buttonTextMaxBet.height * this.componentConfiguration.tilePosition.scale);\n                this.buttonTextMaxBet.scale.set(scaleFactor);\n            }\n\n            if (this.maxBetLimitHit) {\n                this.buttonTextMaxBet.visible = true;\n                this.buttonTextMaxBet.y = this.componentConfiguration.buttonTextMaxBet.y;\n                this.buttonTextCurrency.y +=\n                    this.componentConfiguration.buttonTextMaxBet.y + this.buttonTextMaxBet.height;\n                this.buttonTextMoney.y =\n                    this.buttonTextCurrency.y +\n                    this.buttonTextCurrency.height +\n                    this.componentConfiguration.buttonTextMoney.offSetY;\n            } else {\n                this.buttonTextMaxBet.visible = false;\n                this.buttonTextCurrency.y = this.componentConfiguration.buttonTextCurrency.y;\n                this.buttonTextMoney.y = this.componentConfiguration.buttonTextMoney.y;\n            }\n        }\n    }\n\n    private createPopUp(): void {\n        this.overlay = new Graphics();\n        this.overlay\n            .beginFill(this.componentConfiguration.overlay.color, this.componentConfiguration.overlay.opacity)\n            .drawRect(this.x * -1, this.y * -1, Core.display.stage.width, Core.display.stage.height)\n            .endFill();\n        this.addChild(this.overlay);\n        this.overlay.interactive = true;\n        this.overlay.visible = false;\n\n        this.popUpBackground = new Sprite();\n        this.popUpBackground.name = 'popUpBackground';\n        this.popUpBackground.texture = Core.assets.getAsset('popUpBase').texture;\n        if (Core.isDesktopMode) {\n            this.popUpBackground.texture = Core.assets.getAsset('popUpBaseDesktop').texture;\n        }\n        this.popUpBackground.anchor.set(0.5, 0);\n        this.popUpBackground.visible = false;\n        this.popUpBackground.interactive = true;\n        this.addChild(this.popUpBackground);\n\n        this.popUpContainer = new Sprite();\n        this.popUpContainer.name = 'popUpContainer';\n        this.popUpContainer.anchor.set(0.5, 0);\n        this.popUpContainer.visible = false;\n        this.addChild(this.popUpContainer);\n\n        this.titleBase = new Sprite();\n        this.titleBase.texture = Core.assets.getAsset('titleBase').texture;\n        this.titleBase.anchor.set(0.5);\n        this.popUpContainer.addChild(this.titleBase);\n\n        this.titleText = new Sprite();\n        this.titleText.texture = Core.assets.getTextureFromSpriteSheet('multipleBuyBonus', 'buyBonusTitle.png');\n        this.titleText.anchor.set(0.5);\n        this.titleBase.addChild(this.titleText);\n\n        this.btnClose = new Sprite();\n        this.btnClose.texture = Core.assets.getAsset('btnClose').texture;\n        this.btnClose.anchor.set(0.5);\n        this.btnClose.interactive = true;\n        this.btnClose.cursor = 'pointer';\n        this.popUpContainer.addChild(this.btnClose);\n\n        this.betBase = new Sprite();\n        this.betBase.name = 'betBase';\n        this.betBase.texture = Core.assets.getAsset('betBase').texture;\n        this.betBase.anchor.set(0.5);\n        this.popUpContainer.addChild(this.betBase);\n\n        this.arrowMinus = new Sprite();\n        this.arrowMinus.anchor.set(1, 0.5);\n        this.arrowMinus.interactive = true;\n        this.popUpContainer.addChild(this.arrowMinus);\n\n        this.arrowPlus = new Sprite();\n        this.arrowPlus.anchor.set(0, 0.5);\n        this.arrowPlus.interactive = true;\n        this.popUpContainer.addChild(this.arrowPlus);\n\n        this.betContainer = new Sprite();\n        this.betContainer.anchor.set(0.5);\n        this.betContainer.name = 'betContainer';\n        this.betBase.addChild(this.betContainer);\n\n        this.currencyText = new Text(\n            this.rootStore.uiStore.currency,\n            this.componentConfiguration.betTextProperties.textStyle,\n        );\n        this.betContainer.addChild(this.currencyText);\n\n        this.betValue = new Text(this.getCurrentBet(), this.componentConfiguration.betValueProperties.textStyle);\n        this.betContainer.addChild(this.betValue);\n\n        this.betText = new Text(\n            Core.translator.translate('BET'),\n            this.componentConfiguration.betTextProperties.textStyle,\n        );\n        this.betContainer.addChild(this.betText);\n\n        this.balanceContainer = new Sprite();\n        this.balanceContainer.anchor.set(0.5, 1);\n        this.balanceContainer.name = 'balanceContainer';\n        this.popUpContainer.addChild(this.balanceContainer);\n\n        this.balanceText = new Text(\n            Core.translator.translate('BALANCE') + ':',\n            this.componentConfiguration.balanceTextProperties.textStyle,\n        );\n\n        const balanceValueConfig: MoneyTextConfig = new MoneyTextConfig();\n        balanceValueConfig.currency = this.rootStore.uiStore.currency;\n        balanceValueConfig.moneyFontSize =\n            this.componentConfiguration.balanceValueProperties[this.buyOptionsIndex].get('textStyle').fontSize;\n        balanceValueConfig.centsFontSize =\n            this.componentConfiguration.balanceValueProperties[this.buyOptionsIndex].get('textStyle').fontSize;\n        balanceValueConfig.currencyFontSize = this.componentConfiguration.balanceTextProperties.textStyle.fontSize;\n        this.balanceValue = new MoneyText(\n            balanceValueConfig,\n            this.rootStore.uiStore.BALANCE.value,\n            this.componentConfiguration.balanceValueProperties[this.buyOptionsIndex].get('textStyle'),\n        );\n\n        this.balanceContainer.addChild(this.balanceText);\n        this.balanceContainer.addChild(this.balanceValue);\n\n        for (let i: number = 0; i < this.rootStore.settings.buyBonusOptions.length; i++) {\n            this.addOptionInfo(i, this.buyOptionsIndex);\n        }\n    }\n\n    private addOptionInfo(optionIndex: number, buyOptions: number): void {\n        const buyFeatureOption = new Sprite();\n        this.buyFeatureOption.push(buyFeatureOption);\n        buyFeatureOption.name = 'buyFeatureOption' + optionIndex;\n        buyFeatureOption.texture = Core.assets.getTextureFromSpriteSheet(\n            'multipleBuyBonus',\n            'buyFeaturePopUp' + optionIndex + '.png',\n        );\n        buyFeatureOption.anchor.set(0.5, 0);\n        this.popUpContainer.addChild(buyFeatureOption);\n\n        const optionTextMaxBet = new Text(\n            Core.translator.translate('MAX_BET'),\n            this.componentConfiguration.optionTextMaxBet[buyOptions].get('textStyle'),\n        );\n        this.optionTextMaxBet.push(optionTextMaxBet);\n        optionTextMaxBet.name = 'MaxBetSign' + optionIndex;\n        optionTextMaxBet.visible = false;\n        optionTextMaxBet.anchor.set(0.5);\n        this.popUpContainer.addChild(optionTextMaxBet);\n\n        const buyAmountHolder = new Sprite();\n        this.buyAmountHolder.push(buyAmountHolder);\n        buyAmountHolder.anchor.set(0.5);\n        this.popUpContainer.addChild(buyAmountHolder);\n\n        const popUpTextMoney = new BitmapText(\n            '0',\n            this.componentConfiguration.popUpTextMoneyProperties[buyOptions].get('textStyle'),\n        );\n        this.popUpTextMoney.push(popUpTextMoney);\n        buyAmountHolder.addChild(popUpTextMoney);\n\n        const popUpTextCurrency = new BitmapText(\n            ' ' + this.rootStore.uiStore.currency,\n            this.componentConfiguration.popUpTextCurrencyProperties[buyOptions].get('textStyle'),\n        );\n        this.popUpTextCurrency.push(popUpTextCurrency);\n        buyAmountHolder.addChild(popUpTextCurrency);\n\n        const btnConfirm = new Sprite();\n        this.btnConfirm.push(btnConfirm);\n        btnConfirm.name = 'btnConfirm' + optionIndex;\n        btnConfirm.anchor.set(0.5);\n        btnConfirm.interactive = true;\n        btnConfirm.cursor = 'pointer';\n        this.popUpContainer.addChild(btnConfirm);\n\n        const btnConfirmAnimation = new Sprite();\n        btnConfirmAnimation.texture = Core.assets.getAsset('btnConfirmAnimation').texture;\n        btnConfirmAnimation.alpha = 0;\n        btnConfirmAnimation.anchor.set(0.5);\n        btnConfirmAnimation.cursor = 'pointer';\n        btnConfirm.addChild(btnConfirmAnimation);\n\n        const buyConfirmText = new Sprite();\n        buyConfirmText.anchor.set(0.5);\n        buyConfirmText.texture = Core.assets.getTextureFromSpriteSheet('multipleBuyBonus', 'btnConfirmText.png');\n        btnConfirm.addChild(buyConfirmText);\n    }\n\n    private setPositionsPopUp(): void {\n        if (!this.popUpContainer) {\n            return;\n        }\n\n        this.overlay.width = Core.display.stage.width;\n        this.overlay.height = Core.display.stage.height;\n\n        this.popUpBackground.width =\n            this.componentConfiguration.popupContainerPosition[this.buyOptionsIndex].get('width');\n        this.popUpBackground.height =\n            this.componentConfiguration.popupContainerPosition[this.buyOptionsIndex].get('height');\n        this.popUpBackground.x = Core.display.stage.width / 2;\n        this.popUpBackground.y = this.componentConfiguration.popupContainerPosition[this.buyOptionsIndex].get('y');\n\n        this.popUpContainer.x = Core.display.stage.width / 2;\n        this.popUpContainer.y = this.popUpBackground.y;\n\n        this.titleBase.width = this.componentConfiguration.titleBasePosition.width;\n        this.titleBase.height = this.componentConfiguration.titleBasePosition.height;\n        this.titleBase.x = 0;\n        this.titleBase.y = this.componentConfiguration.titleBasePosition.y;\n\n        this.titleText.x = 0;\n        this.titleText.y = 0;\n\n        this.btnClose.x =\n            this.componentConfiguration.btnClosePosition[this.buyOptionsIndex].get('x') -\n            Core.display.stage.width / 2 +\n            this.btnClose.width / 2;\n        this.btnClose.y =\n            this.componentConfiguration.btnClosePosition[this.buyOptionsIndex].get('y') -\n            this.popUpBackground.y +\n            this.btnClose.height / 2;\n\n        this.betBase.x = this.componentConfiguration.betBasePosition[this.buyOptionsIndex].get('x');\n        this.betBase.y =\n            this.componentConfiguration.betBasePosition[this.buyOptionsIndex].get('y') + this.betBase.height / 2;\n\n        this.arrowMinus.y = this.arrowPlus.y = this.betBase.y;\n        this.arrowMinus.x = this.betBase.x - this.betBase.width / 2;\n        this.arrowPlus.x = this.betBase.x + this.betBase.width / 2;\n\n        this.currencyText.pivot.set(this.currencyText.width / 2, this.currencyText.height);\n        this.betValue.pivot.set(this.betValue.width / 2, this.betValue.height / 2);\n        this.betText.pivot.set(this.betText.width / 2, 0);\n        this.betValue.x = this.betText.x = this.currencyText.x = 0;\n        this.betValue.y = 0;\n        this.currencyText.y =\n            this.betValue.y - this.betValue.height / 2 + this.componentConfiguration.betTextProperties.offSetY;\n        this.betText.y =\n            this.betValue.y + this.betValue.height / 2 - this.componentConfiguration.betTextProperties.offSetY;\n        this.betContainer.x = 0;\n        this.betContainer.y = 0;\n        // this.betContainer.pivot.set(0, (this.betValue.height + this.betText.height + this.currencyText.height) / 2);\n\n        this.balanceContainer.x = 0;\n        this.balanceContainer.y =\n            this.componentConfiguration.balanceValueProperties[this.buyOptionsIndex].get('y') +\n            this.balanceValue.height;\n        this.balanceText.pivot.set(this.balanceText.width / 2, this.balanceText.height);\n        this.balanceValue.pivot.set(this.balanceValue.width / 2, this.balanceValue.height);\n        this.balanceText.x = -this.balanceValue.width / 2 - 5;\n        this.balanceText.y = this.componentConfiguration.balanceTextProperties.y;\n        this.balanceValue.x = +this.balanceText.width / 2;\n    }\n\n    private setPositionsOptions(i: number): void {\n        if (!this.buyFeatureOption[i]) {\n            return;\n        }\n        this.buyFeatureOption[i].width =\n            this.componentConfiguration.buyFeatureOptionPosition[this.buyOptionsIndex].get('width');\n        this.buyFeatureOption[i].height =\n            this.componentConfiguration.buyFeatureOptionPosition[this.buyOptionsIndex].get('height');\n        this.buyFeatureOption[i].x =\n            this.componentConfiguration.buyFeatureOptionPosition[this.buyOptionsIndex].get('x');\n        if (this.buyOptionsIndex === 1) {\n            this.buyFeatureOption[0].x = -this.buyFeatureOption[i].width / 2;\n            this.buyFeatureOption[1].x = +this.buyFeatureOption[i].width / 2;\n        }\n        if (this.buyOptionsIndex === 2) {\n            this.buyFeatureOption[0].x = -this.buyFeatureOption[i].width;\n            this.buyFeatureOption[1].x = 0;\n            this.buyFeatureOption[2].x = +this.buyFeatureOption[i].width;\n        }\n        this.buyFeatureOption[i].y =\n            this.componentConfiguration.buyFeatureOptionPosition[this.buyOptionsIndex].get('y');\n\n        this.optionTextMaxBet[i].x = this.buyFeatureOption[i].x;\n        this.optionTextMaxBet[i].y =\n            this.componentConfiguration.optionTextMaxBet[this.buyOptionsIndex].get('y') +\n            this.optionTextMaxBet[i].height / 2;\n\n        this.popUpTextMoney[i].fontSize =\n            this.componentConfiguration.popUpTextMoneyProperties[this.buyOptionsIndex].get('textStyle').fontSize;\n        this.popUpTextCurrency[i].fontSize =\n            this.componentConfiguration.popUpTextCurrencyProperties[this.buyOptionsIndex].get('textStyle').fontSize;\n        this.buyAmountHolder[i].x = this.buyFeatureOption[i].x;\n        this.buyAmountHolder[i].y =\n            this.componentConfiguration.popUpTextMoneyProperties[this.buyOptionsIndex].get('y') +\n            this.popUpTextMoney[i].height / 2;\n\n        this.popUpTextMoney[i].pivot.set(this.popUpTextMoney[i].width / 2, this.popUpTextMoney[i].height / 2);\n        this.popUpTextCurrency[i].pivot.set(this.popUpTextCurrency[i].width / 2, this.popUpTextCurrency[i].height / 2);\n        this.popUpTextMoney[i].x = -this.popUpTextCurrency[i].width / 2;\n        this.popUpTextCurrency[i].x = +this.popUpTextMoney[i].width / 2;\n        this.popUpTextCurrency[i].y =\n            this.componentConfiguration.popUpTextCurrencyProperties[this.buyOptionsIndex].get('offSetY');\n\n        this.btnConfirm[i].width = this.componentConfiguration.btnConfirmPosition[this.buyOptionsIndex].get('width');\n        this.btnConfirm[i].height = this.componentConfiguration.btnConfirmPosition[this.buyOptionsIndex].get('height');\n        this.btnConfirm[i].x = this.buyFeatureOption[i].x;\n        this.btnConfirm[i].y =\n            this.componentConfiguration.btnConfirmPosition[this.buyOptionsIndex].get('y') +\n            this.btnConfirm[i].height / 2;\n\n        if (\n            this.popUpTextMoney[i].width + this.popUpTextCurrency[i].width >\n            this.componentConfiguration.popUpAmountBounds[i].get('width')\n        ) {\n            const scaleFactor =\n                this.componentConfiguration.popUpAmountBounds[i].get('width') /\n                (this.popUpTextMoney[i].width + this.popUpTextCurrency[i].width);\n            this.buyAmountHolder[i].scale.set(scaleFactor);\n        }\n    }\n\n    private setOrientation(): void {\n        this.setPositionsButton();\n        this.setPositionsPopUp();\n        for (let i: number = 0; i < this.buyFeatureOption.length; i++) {\n            // the second parameter is needed so we can get the proper index from the config array\n            // if we have 2 options we need the configs from 1st index of the config array\n            this.setPositionsOptions(i);\n            if (this.scaleIntervals[i]) {\n                this.enableConfirmAnimation(false, i);\n                this.tweensDelayedCreation = null;\n                this.enableConfirmAnimation(true, i);\n            }\n        }\n    }\n    private onBalanceChanged(): void {\n        if (this.balanceValue) {\n            this.balanceValue.money = this.rootStore.uiStore.BALANCE.value;\n            if (this.popUpOpened) {\n                this.onDenominationOrBetChanged();\n            }\n        }\n    }\n\n    private onDenominationOrBetChanged(): void {\n        this.money = [];\n        this.maxBetOptionHit = [];\n        const buyBonusAmounts: number[] = [];\n        const nextBuyBonusAmounts: number[] = [];\n        this.maxBetLimitHit = false;\n        this.lastAvailableBetReached = false;\n        for (let i: number = 0; i < this.rootStore.settings.buyBonusOptions.length; i++) {\n            let buyBonusValue: number =\n                this.rootStore.settings.buyBonusOptions[i] *\n                Core.SELECTED_DENOMINATION.value *\n                this.rootStore.uiStore.SELECTED_BET.value;\n\n            let nextbuyBonusValue: number = buyBonusValue;\n\n            if (this.betValue && this.popUpOpened) {\n                const buybonus = this.higherDenominationBetsMap.get(this.betValue.text);\n                for (let i: number = 0; i < this.betValuesArray.length; i++) {\n                    if (this.betValuesArray[i] === this.betValue.text) {\n                        if (this.betValuesArray[i + 1]) {\n                            this.nextBet = this.betValuesArray[i + 1];\n                        }\n                    }\n                }\n                const nextBuyBonus = this.higherDenominationBetsMap.get(this.nextBet);\n                if (buybonus && nextBuyBonus) {\n                    buyBonusValue = this.rootStore.settings.buyBonusOptions[i] * buybonus?.denomination * buybonus?.bet;\n                    nextbuyBonusValue =\n                        this.rootStore.settings.buyBonusOptions[i] * nextBuyBonus?.denomination * nextBuyBonus?.bet;\n                }\n            }\n            buyBonusAmounts.push(buyBonusValue);\n            nextBuyBonusAmounts.push(nextbuyBonusValue);\n\n            if (this.settings.clientSettings?.maxBetLimits || this.settings.maxBet) {\n                const maxBetForBonus: number = Math.min(\n                    this.settings.clientSettings?.maxBetLimits\n                        ? this.settings.clientSettings?.maxBetLimits[Core.PLAYER_BALANCE.value.currency]\n                        : Infinity,\n                    this.settings.maxBet ?? Infinity,\n                );\n                if (maxBetForBonus && buyBonusValue > maxBetForBonus * 100) {\n                    this.maxBetOptionHit.push(Boolean(maxBetForBonus && buyBonusValue > maxBetForBonus * 100));\n                    buyBonusValue = maxBetForBonus * 100;\n                } else {\n                    this.maxBetOptionHit.push(Boolean(maxBetForBonus && buyBonusValue > maxBetForBonus * 100));\n                }\n                if (maxBetForBonus && Math.min(...buyBonusAmounts) > maxBetForBonus * 100) {\n                    this.maxBetLimitHit = true;\n                } else if (Math.min(...nextBuyBonusAmounts) > maxBetForBonus * 100) {\n                    this.lastAvailableBetReached = true;\n                }\n            }\n\n            if (this.rootStore.uiStore.BALANCE.value < nextbuyBonusValue) {\n                this.lastAvailableBetReached = true;\n            }\n\n            const money = new Money(buyBonusValue);\n            this.money.push(money);\n\n            this.onOptionsButtonsStateChanged(i);\n            this.onMoneyModeChanged(i);\n        }\n        this.onPopUpButtonsStateChanged();\n\n        this.state = this.shouldDisableBuyBonus() ? 'Off' : 'On';\n    }\n\n    private shouldDisableBuyBonus(): boolean {\n        return (\n            this.popUpOpened ||\n            this.isDoubleChanceFactorActive() ||\n            this.isInBonusIdleState() ||\n            this.isBonusWinState() ||\n            this.rootStore.uiStore.STATE.value === UIState.SLIDING_BETS\n        );\n    }\n\n    private isDoubleChanceFactorActive(): boolean {\n        return (\n            this.rootStore.settings.haveGameMode('DOUBLE_CHANCE') &&\n            this.settings.factor === this.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE')\n        );\n    }\n\n    private isInBonusIdleState(): boolean {\n        return this.rootStore.domainStore.SERVER_STATE.value === ServerState.BONUS_IDLE;\n    }\n\n    private isBonusWinState(): boolean {\n        const betResponse = this.rootStore.domainStore.betResponse;\n        if (!betResponse?.bonus) return false;\n\n        const isGiftSpinOrBuyBonus =\n            betResponse.bonus.type === BonusTypes.GIFT_SPIN || betResponse.bonus.type === BonusTypes.BUY_BONUS;\n\n        return isGiftSpinOrBuyBonus && betResponse.state === ServerState.WIN;\n    }\n\n    private onOptionsButtonsStateChanged(i: number): void {\n        if (!this.btnConfirm[i]) {\n            return;\n        }\n        // set max limit states\n        if (this.maxBetOptionHit[i]) {\n            this.btnConfirm[i].texture = Core.assets.getAsset('btnConfirmInactive').texture;\n            this.btnConfirm[i].interactive = false;\n            this.enableConfirmAnimation(false, i);\n            this.optionTextMaxBet[i].visible = true;\n        } else {\n            this.btnConfirm[i].texture = Core.assets.getAsset('btnConfirmActive').texture;\n            this.btnConfirm[i].interactive = true;\n            this.optionTextMaxBet[i].visible = false;\n            this.enableConfirmAnimation(true, i);\n            // bug ON-69386 - we have very heavi operations when +/- clicked\n            // and animations start to lag. Solution: complete current animations,\n            // stop interval and recreate it again.\n            // I can not find other easy way without rewritten of the component\n            if (this.scaleIntervals[i]) {\n                clearInterval(this.scaleIntervals[i]);\n                this.scaleIntervals[i] = null;\n                this.scaleTweens[i]?.totalProgress(1);\n                this.lightTweens[i]?.totalProgress(1);\n                const scaleInterval = setInterval(() => {\n                    this.scaleTweens[i].restart();\n                    this.lightTweens[i].restart();\n                }, 2000);\n                this.scaleIntervals[i] = scaleInterval;\n            }\n        }\n    }\n\n    private onPopUpButtonsStateChanged(): void {\n        if (this.optionTextMaxBet.length <= 0) {\n            return;\n        }\n        this.betValue.text.replace(/\\s/g, '');\n\n        // set arrow states\n        if (this.betValue.text === this.betValuesArray[0]) {\n            this.arrowMinus.texture = Core.assets.getAsset('arrowMinusInactive').texture;\n            this.setArrowMinusGraphics(false);\n        } else {\n            this.arrowMinus.texture = Core.assets.getAsset('arrowMinusActive').texture;\n            this.setArrowMinusGraphics(true);\n        }\n\n        if (\n            this.lastAvailableBetReached ||\n            this.betValue.text == this.betValuesArray[this.betValuesArray.length - 1] ||\n            this.maxBetLimitHit\n        ) {\n            this.arrowPlus.texture = Core.assets.getAsset('arrowPlusInactive').texture;\n            this.setArrowPlusGraphics(false);\n        } else {\n            this.arrowPlus.texture = Core.assets.getAsset('arrowPlusActive').texture;\n            this.setArrowPlusGraphics(true);\n        }\n    }\n\n    private getNextBet(): string {\n        for (let i: number = 0; i < this.betValuesArray.length; i++) {\n            if (this.betValuesArray[i] === this.betValue.text && this.betValuesArray[i + 1]) {\n                return this.betValuesArray[i + 1];\n            }\n        }\n        return '';\n    }\n\n    private setArrowMinusGraphics(interactive: boolean): void {\n        if (!this.arrowMinusGraphics) {\n            this.arrowMinusGraphics = new Graphics();\n            this.arrowMinusGraphics\n                .beginFill(0x000000, 0.1)\n                .drawPolygon(\n                    0,\n                    this.arrowMinus.width / 2, // Point 1 (x1, y1)\n                    this.arrowMinus.width,\n                    0, // Point 2 (x2, y2)\n                    this.arrowMinus.width,\n                    this.arrowMinus.width,\n                )\n                .endFill();\n            this.arrowMinusGraphics.alpha = 0;\n            this.arrowMinus.addChild(this.arrowMinusGraphics);\n            this.arrowMinusGraphics.pivot.set(this.arrowMinusGraphics.width, this.arrowMinusGraphics.height / 2);\n\n            (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/multiple-buy-bonus/views/BuyBonusViewMultipleBuyBonus.ts:880:13\",(this.arrowMinusGraphics),\"pointertap\"]), fromEvent(this.arrowMinusGraphics, 'pointertap'))\n                .pipe(takeUntil(this.DESTROY))\n                .subscribe(this.onDecreaseBetAmount.bind(this));\n        }\n        this.arrowMinusGraphics.interactive = interactive;\n        this.arrowMinusGraphics.cursor = 'pointer';\n    }\n\n    private setArrowPlusGraphics(interactive: boolean): void {\n        if (!this.arrowPlusGraphics) {\n            this.arrowPlusGraphics = new Graphics();\n            this.arrowPlusGraphics\n                .beginFill(0x000000, 0.1)\n                .drawPolygon(\n                    0,\n                    0, // Point 1 (x1, y1)\n                    this.arrowPlus.width,\n                    this.arrowPlus.width / 2, // Point 2 (x2, y2)\n                    0,\n                    this.arrowPlus.width,\n                )\n                .endFill();\n            this.arrowPlusGraphics.alpha = 0;\n            this.arrowPlus.addChild(this.arrowPlusGraphics);\n            this.arrowPlusGraphics.pivot.set(0, this.arrowPlusGraphics.height / 2);\n\n            (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/buy-bonus/src/egt/modes/multiple-buy-bonus/views/BuyBonusViewMultipleBuyBonus.ts:906:13\",(this.arrowPlusGraphics),\"pointertap\"]), fromEvent(this.arrowPlusGraphics, 'pointertap'))\n                .pipe(takeUntil(this.DESTROY))\n                .subscribe(this.onIncreaseBetAmount.bind(this));\n        }\n\n        this.arrowPlusGraphics.interactive = interactive;\n        this.arrowPlusGraphics.cursor = 'pointer';\n    }\n\n    private getBetValues(): void {\n        const betValuesSet: Set<string> = new Set();\n        for (const denomination of this.settings.denominations) {\n            for (const bet of this.settings.bets) {\n                const betValue = new Money(denomination * bet * this.settings.factors[0]);\n                this.higherDenominationBetsMap.set(betValue.stringMoney, { denomination: denomination, bet: bet });\n                betValuesSet.add(betValue.stringMoney);\n            }\n        }\n        // for (let i: number = this.settings.denominations.length; i < this.settings.denominations.length; i--) {\n        //     for (const bet of this.settings.bets) {\n        //         const betValue = new Money(this.settings.denominations[i] * bet * this.settings.factors[0]);\n        //         this.lowerDenominationBetsMap.set(betValue.stringMoney, { denomination: this.settings.denominations[i], bet: bet });\n        //     }\n        // }\n\n        const unsortedArray = Array.from(betValuesSet);\n        this.betValuesArray = unsortedArray.sort((a, b) => {\n            // remove spaces before parsing\n            const numA = parseFloat(a.replace(/\\s/g, ''));\n            const numB = parseFloat(b.replace(/\\s/g, ''));\n            return numA - numB;\n        });\n    }\n\n    // private onDenominationChanged(): void {\n    //     this.setCurrentDenominationsBetsValue();\n    //     this.onDenominationOrBetChanged();\n    // }\n\n    // private setCurrentDenominationsBetsValue(): void {\n    //     this.currentDenominationBetsMap.clear();\n    //     for (const bet of this.settings.bets) {\n    //         const betValue = new Money(Core.SELECTED_DENOMINATION.value * bet * this.settings.factors[0]);\n    //         this.currentDenominationBetsMap.set(betValue.stringMoney, {\n    //             denomination: Core.SELECTED_DENOMINATION.value,\n    //             bet: bet,\n    //         });\n    //     }\n    // }\n\n    private searchForDenomination(\n        bet: string,\n        denominationOffset: number,\n        checkInBiggerDenomination: boolean,\n    ): { denomination: number; bet: number } {\n        let denomination: number = -1;\n        let currentDenominationIndex: number = 0;\n        for (let i: number = 0; i < this.settings.denominations.length; i++) {\n            if (this.settings.denominations[i] === Core.SELECTED_DENOMINATION.value) {\n                currentDenominationIndex = i;\n            }\n        }\n        if (checkInBiggerDenomination) {\n            if (currentDenominationIndex + denominationOffset < this.settings.denominations.length) {\n                denomination = this.settings.denominations[currentDenominationIndex + denominationOffset];\n            } else {\n                return this.searchForDenomination(bet, denominationOffset, false);\n            }\n        } else {\n            if (currentDenominationIndex - denominationOffset >= 0) {\n                denomination = this.settings.denominations[currentDenominationIndex - denominationOffset];\n                denominationOffset++;\n            } else {\n                denominationOffset++;\n                return this.searchForDenomination(bet, denominationOffset, true);\n            }\n        }\n        const denominationMap: Map<string, { denomination: number; bet: number }> = new Map();\n        for (const bet of this.settings.bets) {\n            const betValue = new Money(denomination * bet * this.settings.factors[0]);\n            denominationMap.set(betValue.stringMoney, {\n                denomination: denomination,\n                bet: bet,\n            });\n        }\n        if (denominationMap.has(bet)) {\n            return denominationMap.get(bet) as { denomination: number; bet: number };\n        } else {\n            return this.searchForDenomination(bet, denominationOffset, !checkInBiggerDenomination);\n        }\n    }\n\n    private getCurrentBet(): string {\n        const betValue = new Money(\n            Core.SELECTED_DENOMINATION.value *\n                this.rootStore.uiStore.SELECTED_BET.value *\n                this.rootStore.settings.factor,\n        );\n        return betValue.stringMoney;\n    }\n    private onMoneyModeChanged(i: number): void {\n        if (!this.money[i] || !this.popUpTextMoney[i]) {\n            return;\n        }\n        this.popUpTextMoney[i].text = this.money[i].stringMoneyWithoutCents;\n\n        if (this.buttonTextMoney) {\n            this.buttonTextMoney.text = this.money[i].stringMoneyWithoutCents;\n        }\n        this.state = this.state;\n\n        this.setOrientation();\n    }\n\n    private getWinAmount(): number {\n        const collectBalance = this.rootStore.domainStore.collectResponse?.balance;\n        const isIdleState = this.rootStore.uiStore.STATE.value === UIState.IDLE;\n        const isCollectAction = this.rootStore.uiStore.WIN.value.action === BangupActionConsts.COLLECT;\n        const hasBalanceChanged = collectBalance !== this.rootStore.uiStore.BALANCE.value;\n        // Check for condition where the game enters IDLE state after collect\n        // but balance is not yet updated due to animations.\n        if (collectBalance && isIdleState && isCollectAction && hasBalanceChanged) {\n            // Use prev win amount as after collect the win amount is set to 0\n            const winAmount = Number(this.rootStore.uiStore.WIN.prevValue.amount);\n            return winAmount ? winAmount : 0;\n        }\n        // In all other cases, use the current win amount.\n        const winAmount = Number(this.rootStore.uiStore.WIN.value.amount);\n        return winAmount ? winAmount : 0;\n    }\n\n    private onIncreaseBetAmount(): void {\n        Core.sounds.play('buyBonusSelect');\n        for (let i: number = 0; i < this.betValuesArray.length; i++) {\n            if (this.betValuesArray[i] === this.betValue.text && this.betValuesArray[i + 1]) {\n                this.betValue.text = this.betValuesArray[i + 1];\n                this.onDenominationOrBetChanged();\n                return;\n            }\n        }\n    }\n\n    private onDecreaseBetAmount(): void {\n        Core.sounds.play('buyBonusSelect');\n        for (let i: number = 0; i < this.betValuesArray.length; i++) {\n            if (this.betValuesArray[i] === this.betValue.text && this.betValuesArray[i - 1]) {\n                this.betValue.text = this.betValuesArray[i - 1];\n                this.onDenominationOrBetChanged();\n                return;\n            }\n        }\n    }\n\n    private enableConfirmAnimation(play: boolean, i: number): void {\n        if (play) {\n            // if animation and repeat interval are already created - skip all\n            if (this.tweensDelayedCreation) {\n                return;\n            }\n            this.tweensDelayedCreation = gsap.delayedCall(2, () => {\n                const scaleToX = this.btnConfirm[0].scale._x + 0.05;\n                const scaleToY = this.btnConfirm[0].scale._y + 0.05;\n\n                const scaleTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/buy-bonus/src/egt/modes/multiple-buy-bonus/views/BuyBonusViewMultipleBuyBonus.ts:1069:36\",null]), gsap.to(this.btnConfirm[i].scale, {\n                    x: scaleToX,\n                    y: scaleToY,\n                    duration: 0.2,\n                    yoyo: true,\n                    repeat: 3,\n                }));\n                const lightTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/buy-bonus/src/egt/modes/multiple-buy-bonus/views/BuyBonusViewMultipleBuyBonus.ts:1076:36\",null]), gsap.to(this.btnConfirm[i].getChildAt(0), {\n                    alpha: 1,\n                    duration: 0.2,\n                    yoyo: true,\n                    repeat: 3,\n                }));\n\n                if (!this.scaleTweens) {\n                    this.scaleTweens = [];\n                }\n                if (!this.lightTweens) {\n                    this.lightTweens = [];\n                }\n                this.scaleTweens[i] = scaleTween;\n                this.lightTweens[i] = lightTween;\n\n                const scaleInterval = setInterval(() => {\n                    scaleTween.restart();\n                    lightTween.restart();\n                }, 2000);\n\n                this.scaleIntervals[i] = scaleInterval;\n            });\n        } else {\n            if (this.scaleIntervals[i]) {\n                clearInterval(this.scaleIntervals[i]);\n                delete this.scaleIntervals[i];\n            }\n            if (this.scaleTweens && this.scaleTweens[i]) {\n                this.scaleTweens[i].kill();\n                delete this.scaleTweens[i];\n            }\n            if (this.lightTweens && this.lightTweens[i]) {\n                this.lightTweens[i].kill();\n                delete this.lightTweens[i];\n                this.btnConfirm[i].getChildAt(0).alpha = 0;\n            }\n        }\n    }\n}\n","import { BaseComponent, IBaseComponentView, IModeConfig } from '@egt/core';\nimport { SlotComponents, ZOrders } from '@egt/slot';\nimport { Lifecycle } from 'tsyringe';\nimport ClockModesConfigurations, { ClockModes } from './ClockFactory';\nimport { clockConfigFactoryDefault } from './modes/default/configuration/ClockComponentConfigurationDefault';\nimport { IClockComponentConfigurationDefault } from './modes/default/configuration/IClockComponentConfigurationDefault';\n\nexport default class ClockComponent extends BaseComponent {\n    public static configurationName = 'ClockComponent';\n\n    public clockView: IBaseComponentView;\n    public componentType = SlotComponents.CLOCK;\n    public configuration: IClockComponentConfigurationDefault;\n    public rootView;\n\n    constructor(modeConfig: IModeConfig) {\n        super();\n        const baseConfigs = {\n            [ClockModes.DEFAULT]: clockConfigFactoryDefault,\n        };\n\n        this.modeFactory = this.initMode<ClockModesConfigurations>(modeConfig, {\n            defaultModeType: ClockModes.DEFAULT,\n            baseConfigs,\n            defaultFactory: ClockModesConfigurations,\n        });\n    }\n\n    public destroy(): void {\n        this.clockView.destroy();\n        // @ts-ignore\n        this.clockView = null;\n        // @ts-ignore\n        this.configuration.destroy();\n        // @ts-ignore\n        this.configuration = null;\n        // @ts-ignore\n        this.rootView = null;\n        // @ts-ignore\n        this.config = null;\n\n        super.destroy();\n    }\n\n    public onAfterGameConfigurationCreated(): void {\n        super.onAfterGameConfigurationCreated();\n        this.configuration = this.dependencyContainer.resolve('ClockComponentConfiguration');\n    }\n\n    // public onPrepareResources(_container: any): void {\n    //     Core.assets.addAssets(this.modeConfig.getAssets());\n    // }\n\n    public onRegisterDependencies(container: any): void {\n        super.onRegisterDependencies(container);\n\n        this.dependencyContainer.register(\n            'ClockView',\n            { useClass: this.mode.view },\n            { lifecycle: Lifecycle.Singleton },\n        );\n        // if (this.config) {\n        //     this.dependencyContainer.register('ClockComponentConfiguration', this.config(clockConfigFactory()));\n        // } else {\n        //     this.dependencyContainer.register('ClockComponentConfiguration', clockConfigFactory());\n        // }\n        this.dependencyContainer.register('ClockComponentConfiguration', this.mode.configuration);\n    }\n\n    public onResolveDependencies(container: any): void {\n        super.onResolveDependencies(container);\n\n        this.rootView = this.dependencyContainer.resolve('RootView');\n        this.clockView = this.dependencyContainer.resolve('ClockView');\n        this.clockView.zIndex = ZOrders.UI_LEVEL + 3;\n        this.rootView.addChild(this.clockView);\n    }\n    public onInit(_view: any): void {\n        this.clockView.init();\n    }\n\n    public onInitComplete(_view: any): void {\n        this.clockView.initComplete();\n    }\n}\n","import { BaseModesConfigurations, IForceSetConfig, IModes } from '@egt/core';\nimport ClockViewDefault from './modes/default/views/ClockViewDefault';\nimport { clockConfigFactoryDefault } from './modes/default/configuration/ClockComponentConfigurationDefault';\n\nexport default class ClockModesConfigurations extends BaseModesConfigurations<ClockModes> {\n    constructor(modeType: ClockModes, forceSetConfig?: IForceSetConfig) {\n        super(modeType, forceSetConfig);\n    }\n\n    protected createBaseModesConfig(modeType: ClockModes): IModes {\n        switch (modeType) {\n            default:\n                return {\n                    view: ClockViewDefault,\n                    configuration: clockConfigFactoryDefault(),\n                };\n        }\n    }\n\n    // protected createAssetsConfig(): Array<IAsset | ISoundAsset> {\n    //     const baseAssets: Array<IAsset | ISoundAsset> = [\n    //         {\n    //             id: 'baseClockAssets',\n    //             url: '../assets/components/slot/clock/base/baseClockAssets.json',\n    //             priority: AssetPriority.HIGHEST,\n    //             type: 'texture',\n    //         },\n    //     ];\n    //     let modAssets: Array<IAsset | ISoundAsset>;\n    //     switch (this.modeType) {\n    //         case ClockModes.EXTRA:\n    //             modAssets = [\n    //                 {\n    //                     id: 'clockAssets',\n    //                     url: '../assets/components/slot/clock/modes/extra/clockAssets.json',\n    //                     priority: AssetPriority.HIGHEST,\n    //                     type: 'texture',\n    //                 },\n    //             ];\n    //             break;\n    //         default:\n    //             modAssets = [\n    //                 {\n    //                     id: 'clockAssets',\n    //                     url: '../assets/components/slot/clock/modes/default/clockAssets.json',\n    //                     priority: AssetPriority.HIGHEST,\n    //                     type: 'texture',\n    //                 },\n    //             ];\n    //             break;\n    //     }\n    //     return [...baseAssets, ...modAssets];\n    // }\n}\n\nexport enum ClockModes {\n    DEFAULT = 'default',\n}\n","import ClockComponent from './ClockComponent';\nimport {\n    IClockComponentConfigurationDefault,\n    IClockTextStyle,\n} from './modes/default/configuration/IClockComponentConfigurationDefault';\nimport ClockModesConfigurations, { ClockModes } from './ClockFactory';\nimport ClockComponentConfigurationDefault, {\n    clockConfigFactoryDefault,\n} from './modes/default/configuration/ClockComponentConfigurationDefault';\nimport ClockViewDefault from './modes/default/views/ClockViewDefault';\n\nexport {\n    IClockComponentConfigurationDefault,\n    ClockComponentConfigurationDefault,\n    IClockTextStyle,\n    ClockModesConfigurations,\n    ClockModes,\n    ClockViewDefault,\n    clockConfigFactoryDefault,\n};\n\nexport default ClockComponent;\n","import {\n    AddPriority,\n    BaseComponentConfiguration,\n    ConditionObject,\n    DefaultValue,\n    DynamicPositionObject,\n    IPositionPoint,\n} from '@egt/core';\nimport { SlotComponents } from '@egt/slot';\nimport { TextStyle } from 'pixi.js';\nimport { IClockComponentConfigurationDefault, IClockTextStyle } from './IClockComponentConfigurationDefault';\nimport { FooterBackgroundModes } from '@egt/footer-background';\n\nexport default class ClockComponentConfigurationDefault extends BaseComponentConfiguration {}\nexport function clockConfigFactoryDefault(): any {\n    class ClockComponentConfigurationInternalClassDefault\n        extends ClockComponentConfigurationDefault\n        implements IClockComponentConfigurationDefault\n    {\n        public dependsOn: { [SlotComponents.GAME_TITLE]: ConditionObject } = {\n            [SlotComponents.GAME_TITLE]: new ConditionObject({ landscape: false, portrait: false, desktop: true }),\n        };\n\n        @DefaultValue<IClockTextStyle>({\n            defaults: {\n                clockTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fontSize: 15,\n                    fill: '#888888',\n                    align: 'right',\n                }),\n                blurredFooterClockTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fontSize: 17,\n                    // fontWeight: 'bold',\n                    fill: 'rgba(255, 255, 255)',\n                    align: 'right',\n                    dropShadow: true,\n                    dropShadowColor: '#000000',\n                    dropShadowBlur: 2,\n                    dropShadowDistance: 1,\n                }),\n            },\n            portrait: {\n                blurredFooterClockTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fontSize: 17,\n                    // fontWeight: 'bold',\n                    fill: 'rgba(255, 255, 255, 0.8)',\n                    align: 'right',\n                }),\n            },\n        })\n        public clockTextStyles: DynamicPositionObject<IClockTextStyle> & IClockTextStyle;\n\n        @AddPriority<IPositionPoint>([\n            {\n                priorityType: { feature: SlotComponents.FOOTER_BACKGROUND, mode: FooterBackgroundModes.BLURRED },\n                priority: 2,\n                value: {\n                    landscape: { x: 1303, y: 674 },\n                    portrait: { x: 708, y: 1337 },\n                    desktop: { x: 1303, y: 674 },\n                },\n            },\n        ])\n        @DefaultValue<IPositionPoint>({\n            defaults: {\n                x: 0,\n                y: 0,\n                visible: true,\n                scale: 1,\n                width: 100,\n                height: 100,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n            },\n            landscape: { x: 1265, y: 738 },\n            portrait: { x: 701, y: 1329 },\n            desktop: { x: 174, y: 738 },\n        })\n        public clockPosition: DynamicPositionObject<IPositionPoint> & IPositionPoint;\n    }\n    return ClockComponentConfigurationInternalClassDefault;\n}\n","import Core, { Timers } from '@egt/core';\nimport { RootStore, SlotComponents } from '@egt/slot';\nimport { ViewContainer } from '@egt/ui-lib';\nimport { Text } from 'pixi.js';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { IClockComponentConfigurationDefault } from '../configuration/IClockComponentConfigurationDefault';\nimport { FooterBackgroundModes } from '@egt/footer-background';\n\n@injectable()\nexport default class ClockViewDefault extends ViewContainer {\n    public clock: Text;\n    protected id: any;\n\n    constructor(\n        @inject('ClockComponentConfiguration') protected componentConfiguration: IClockComponentConfigurationDefault,\n        @inject('RootStore') protected rootStore: RootStore,\n    ) {\n        super();\n        this.name = 'ClockViewDefault';\n    }\n\n    public init(): void {\n        this.clock = new Text(\n            '',\n            Core.hasComponent(SlotComponents.FOOTER_BACKGROUND, FooterBackgroundModes.BLURRED)\n                ? this.componentConfiguration.clockTextStyles.blurredFooterClockTextStyle\n                : this.componentConfiguration.clockTextStyles.clockTextStyle,\n        );\n        this.clock.resolution = 2;\n        this.addChild(this.clock);\n\n        this.id = Timers.setInterval(this.tick.bind(this), 500);\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n    }\n\n    public initComplete(): void {\n        this.setOrientation();\n    }\n\n    public destroy(): void {\n        Timers.clearInterval(this.id);\n        this.id = null;\n        this.removeChildren();\n        this.clock.destroy({ children: true, texture: true, baseTexture: true });\n        // @ts-ignore\n        this.clock = null;\n        super.destroy();\n    }\n\n    protected tick(): void {\n        const date: any = new Date();\n        const h: any = date.getHours();\n        let m: any = date.getMinutes();\n        m = this.checkTime(m);\n        this.clock.text = h + ':' + m;\n    }\n\n    private checkTime(i: any): void {\n        if (i < 10) {\n            i = '0' + i;\n        }\n        return i;\n    }\n\n    private setOrientation(): void {\n        this.clock.x = this.componentConfiguration.clockPosition.x;\n        this.clock.y = this.componentConfiguration.clockPosition.y;\n        if (this.componentConfiguration.dependsOn.GAME_TITLE.condition) {\n            this.clock.x = this.componentConfiguration.clockPosition.x + this.rootStore.subjects.GAME_TITLE_WIDTH.value;\n        }\n        this.clock.style = Core.hasComponent(SlotComponents.FOOTER_BACKGROUND, FooterBackgroundModes.BLURRED)\n            ? this.componentConfiguration.clockTextStyles.blurredFooterClockTextStyle\n            : this.componentConfiguration.clockTextStyles.clockTextStyle;\n    }\n}\n","import Core, { BaseComponent, IModeConfig } from '@egt/core';\nimport { SlotComponents, ZOrders } from '@egt/slot';\nimport { Lifecycle } from 'tsyringe';\nimport DenominationPopupModesConfigurations, { DenominationPopupModes } from './DenominationPopupFactory';\nimport { DenominationPopupConfigFactoryDefault } from './modes/default/configuration/DenominationPopupComponentConfigurationDefault';\nimport DenominationPopupSubjectsDefault from './modes/default/subjects/DenominationPopupSubjectsDefault';\nimport DenominationPopupComponentConfigurationExtended, {\n    DenominationPopupConfigFactoryExtended,\n} from './modes/extended/configuration/DenominationPopupComponentConfigurationExtended';\nimport DenominationPopupControllerExtended from './modes/extended/controllers/DenominationPopupControllerExtended';\nimport { IDenominationPopupComponentConfigurationExtended } from './modes/extended/interfaces/InterfacesExtended';\nimport DenominationPopupViewExtended from './modes/extended/views/DenominationPopupViewExtended';\nimport { DenominationPopupConfigFactoryMaxBet } from './modes/max-bet/configuration/DenominationPopupComponentConfigurationMaxBet';\nimport DenominationPopupShadowViewMaxBet from './modes/max-bet/views/DenominationPopupShadowViewMaxBet';\n\nexport default class DenominationPopupComponent extends BaseComponent {\n    public static configurationName = 'DenominationPopupComponent';\n\n    public denominationPopupView: DenominationPopupViewExtended;\n    public denominationPopupShadowView: DenominationPopupShadowViewMaxBet;\n    public denominationPopupController: DenominationPopupControllerExtended;\n    public componentType = SlotComponents.DENOMINATION_POPUP;\n    public configuration: IDenominationPopupComponentConfigurationExtended;\n    public rootView;\n\n    constructor(modeConfig: IModeConfig) {\n        super();\n\n        const baseConfigs = {\n            [DenominationPopupModes.DEFAULT]: DenominationPopupConfigFactoryDefault,\n            [DenominationPopupModes.EXTENDED]: DenominationPopupConfigFactoryExtended,\n            [DenominationPopupModes.MAX_BET]: DenominationPopupConfigFactoryMaxBet,\n        };\n\n        this.modeFactory = this.initMode<DenominationPopupModesConfigurations>(modeConfig, {\n            defaultModeType: DenominationPopupModes.DEFAULT,\n            baseConfigs,\n            defaultFactory: DenominationPopupModesConfigurations,\n        });\n    }\n\n    public destroy(): void {\n        this.denominationPopupController.destroy();\n        // @ts-ignore\n        this.denominationPopupController = null;\n        // @ts-ignore\n        this.denominationPopupView = null;\n        (this.configuration as unknown as DenominationPopupComponentConfigurationExtended).destroy();\n        // @ts-ignore\n        this.configuration = null;\n        // @ts-ignore\n        this.dependencyContainer = null;\n\n        // @ts-ignore\n        this.config = null;\n\n        // @ts-ignore\n        this.rootView = null;\n\n        super.destroy();\n    }\n\n    public onAfterGameConfigurationCreated(): void {\n        super.onAfterGameConfigurationCreated();\n        this.configuration = this.dependencyContainer.resolve('DenominationPopupComponentConfiguration');\n    }\n\n    public onRegisterDependencies(container: any): void {\n        super.onRegisterDependencies(container);\n\n        this.dependencyContainer.register(\n            'DenominationPopupView',\n            { useClass: this.mode.view },\n            { lifecycle: Lifecycle.Singleton },\n        );\n\n        this.dependencyContainer.register(\n            'DenominationPopupController',\n            { useClass: this.mode.controller },\n            { lifecycle: Lifecycle.Singleton },\n        );\n\n        if (this.modeFactory.modeType === DenominationPopupModes.MAX_BET) {\n            this.dependencyContainer.register(\n                'DenominationPopupShadowView',\n                { useClass: this.mode.secondView },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n\n        if (this.modeFactory.modeType === DenominationPopupModes.DEFAULT) {\n            this.dependencyContainer.register(\n                'DenominationPopupSubjects',\n                { useClass: DenominationPopupSubjectsDefault },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n\n        this.dependencyContainer.register('DenominationPopupComponentConfiguration', this.mode.configuration);\n    }\n\n    public onPrepareResources(_container: any): void {\n        // Core.fonts.addAssets([\n        //     {\n        //         id: 'RobotoCondensed-Regular',\n        //         url: '../assets/Fonts/Roboto/RobotoCondensed-Regular.ttf',\n        //         priority: AssetPriority.HIGHEST,\n        //         type: 'font',\n        //     },\n        //     {\n        //         id: 'RobotoCondensed-Bold',\n        //         url: '../assets/Fonts/Roboto/RobotoCondensed-Bold.ttf',\n        //         priority: AssetPriority.HIGHEST,\n        //         type: 'font',\n        //     },\n        // ]);\n        if (this.modeFactory.modeType !== DenominationPopupModes.DEFAULT) {\n            Core.assets.addAssets(this.configuration?.assets?.toArray() || []);\n        }\n    }\n\n    public onResolveDependencies(container: any): void {\n        super.onResolveDependencies(container);\n\n        this.rootView = this.dependencyContainer.resolve('RootView');\n        this.denominationPopupView = this.dependencyContainer.resolve('DenominationPopupView');\n        this.denominationPopupView.zIndex = ZOrders.POPUP_LEVEL;\n        this.rootView.addChild(this.denominationPopupView);\n\n        if (this.modeFactory.modeType === DenominationPopupModes.MAX_BET) {\n            this.denominationPopupShadowView = this.dependencyContainer.resolve('DenominationPopupShadowView');\n            this.denominationPopupShadowView.zIndex = ZOrders.REELS_LEVEL;\n            this.rootView.addChild(this.denominationPopupShadowView);\n        }\n\n        this.denominationPopupController = this.dependencyContainer.resolve('DenominationPopupController');\n    }\n\n    public onInit(): void {\n        this.denominationPopupView.init();\n        if (this.modeFactory.modeType === DenominationPopupModes.MAX_BET) {\n            this.denominationPopupShadowView.init();\n        }\n        this.denominationPopupController.init();\n    }\n}\n","import { BaseModesConfigurations, IForceSetConfig, IModes } from '@egt/core';\nimport { DenominationPopupConfigFactoryDefault } from './modes/default/configuration/DenominationPopupComponentConfigurationDefault';\nimport DenominationPopupControllerDefault from './modes/default/controllers/DenominationPopupControllerDefault';\nimport DenominationPopupViewDefault from './modes/default/views/DenominationPopupViewDefault';\nimport { DenominationPopupConfigFactoryExtended } from './modes/extended/configuration/DenominationPopupComponentConfigurationExtended';\nimport DenominationPopupControllerExtended from './modes/extended/controllers/DenominationPopupControllerExtended';\nimport DenominationPopupViewExtended from './modes/extended/views/DenominationPopupViewExtended';\nimport { DenominationPopupConfigFactoryMaxBet } from './modes/max-bet/configuration/DenominationPopupComponentConfigurationMaxBet';\nimport DenominationPopupControllerMaxBet from './modes/max-bet/controllers/DenominationPopupControllerMaxBet';\nimport DenominationPopupViewMaxBet from './modes/max-bet/views/DenominationPopupViewMaxBet';\nimport DenominationPopupShadowViewMaxBet from './modes/max-bet/views/DenominationPopupShadowViewMaxBet';\n\nexport default class DenominationPopupModesConfigurations extends BaseModesConfigurations<DenominationPopupModes> {\n    constructor(modeType: DenominationPopupModes, forceSetConfig?: IForceSetConfig) {\n        super(modeType, forceSetConfig);\n    }\n\n    protected createBaseModesConfig(modeType: DenominationPopupModes): IModes {\n        switch (modeType) {\n            case DenominationPopupModes.EXTENDED:\n                return {\n                    controller: DenominationPopupControllerExtended,\n                    view: DenominationPopupViewExtended,\n                    configuration: DenominationPopupConfigFactoryExtended(),\n                };\n            case DenominationPopupModes.MAX_BET:\n                return {\n                    controller: DenominationPopupControllerMaxBet,\n                    view: DenominationPopupViewMaxBet,\n                    secondView: DenominationPopupShadowViewMaxBet,\n                    configuration: DenominationPopupConfigFactoryMaxBet(),\n                };\n            default:\n                return {\n                    controller: DenominationPopupControllerDefault,\n                    view: DenominationPopupViewDefault,\n                    configuration: DenominationPopupConfigFactoryDefault(),\n                };\n        }\n    }\n}\n\nexport enum DenominationPopupModes {\n    DEFAULT = 'default',\n    EXTENDED = 'extended',\n    MAX_BET = 'max-bet',\n}\n","import DenominationPopupComponent from './DenominationPopupComponent';\nimport DenominationPopupComponentConfigurationDefault, {\n    DenominationPopupConfigFactoryDefault,\n} from './modes/default/configuration/DenominationPopupComponentConfigurationDefault';\nimport {\n    IDenominationButtonInterfaceDefault,\n    IDenominationPopupComponentConfigurationDefault,\n    IDenominationPopupInterfaceDefault,\n} from './modes/default/interfaces/InterfacesDefault';\nimport DenominationPopupComponentConfigurationExtended, {\n    DenominationPopupConfigFactoryExtended,\n} from './modes/extended/configuration/DenominationPopupComponentConfigurationExtended';\nimport DenominationPopupControllerExtended from './modes/extended/controllers/DenominationPopupControllerExtended';\nimport {\n    IDenomArrowPositionsExtended,\n    IBalanceAndBetTextExtended,\n    IDenominationBackgroundPopUpPositionsExtended,\n    IDenominationPopUpTitleTextExtended,\n    IDenominationSelectedBtnPositionsExtended,\n    IDenominationPopupComponentConfigurationExtended,\n    IDenominationPopupInterfaceExtended,\n    IMainContainerPositionExtended,\n} from './modes/extended/interfaces/InterfacesExtended';\nimport DenominationPopupViewExtended from './modes/extended/views/DenominationPopupViewExtended';\nimport DenominationPopupModesConfigurations, { DenominationPopupModes } from './DenominationPopupFactory';\nimport DenominationPopupComponentConfigurationMaxBet, {\n    DenominationPopupConfigFactoryMaxBet,\n} from './modes/max-bet/configuration/DenominationPopupComponentConfigurationMaxBet';\nimport DenominationPopupControllerDefault from './modes/default/controllers/DenominationPopupControllerDefault';\nimport DenominationPopupViewDefault from './modes/default/views/DenominationPopupViewDefault';\nimport DenominationPopupControllerMaxBet from './modes/max-bet/controllers/DenominationPopupControllerMaxBet';\nimport DenominationPopupViewMaxBet from './modes/max-bet/views/DenominationPopupViewMaxBet';\nimport {\n    IBetMultiplierPanel,\n    IBetPanel,\n    ICurvePositionObjectMaxBet,\n    IDenomArrowPositionsMaxBet,\n    IDenominationBackgroundPopUpPositionsMaxBet,\n    IDenominationSelectedBtnPositionsMaxBet,\n    IMainContainerPositionMaxBet,\n    IMaxBetButtonPosition,\n    ITotalBet,\n} from './modes/max-bet/interfaces/InterfacesMaxBet';\n\nexport {\n    DenominationPopupComponentConfigurationDefault,\n    DenominationPopupComponentConfigurationExtended,\n    DenominationPopupModesConfigurations,\n    DenominationPopupModes,\n    IDenomArrowPositionsExtended,\n    IDenominationBackgroundPopUpPositionsExtended,\n    IDenominationButtonInterfaceDefault,\n    IDenominationPopupComponentConfigurationDefault,\n    IDenominationPopupInterfaceDefault,\n    IDenominationPopUpTitleTextExtended,\n    IDenominationSelectedBtnPositionsExtended,\n    IDenominationPopupComponentConfigurationExtended,\n    IDenominationPopupInterfaceExtended,\n    DenominationPopupComponentConfigurationMaxBet,\n    DenominationPopupControllerDefault,\n    DenominationPopupViewDefault,\n    DenominationPopupControllerExtended,\n    DenominationPopupViewExtended,\n    DenominationPopupControllerMaxBet,\n    DenominationPopupViewMaxBet,\n    IMainContainerPositionExtended,\n    IBalanceAndBetTextExtended,\n    IDenominationSelectedBtnPositionsMaxBet,\n    IMainContainerPositionMaxBet,\n    IBetMultiplierPanel,\n    IBetPanel,\n    ICurvePositionObjectMaxBet,\n    IDenominationBackgroundPopUpPositionsMaxBet,\n    IMaxBetButtonPosition,\n    ITotalBet,\n    IDenomArrowPositionsMaxBet,\n    DenominationPopupConfigFactoryDefault,\n    DenominationPopupConfigFactoryExtended,\n    DenominationPopupConfigFactoryMaxBet,\n};\nexport default DenominationPopupComponent;\n","import { BaseComponentConfiguration, DefaultValue, DynamicPositionObject } from '@egt/core';\nimport {\n    IDenominationButtonInterfaceDefault,\n    IDenominationPopupComponentConfigurationDefault,\n    IDenominationPopupInterfaceDefault,\n} from '../interfaces/InterfacesDefault';\n\nexport default class DenominationPopupComponentConfigurationDefault extends BaseComponentConfiguration {}\nexport function DenominationPopupConfigFactoryDefault(): any {\n    class InternalDenominationPopupComponentConfigurationDefault\n        extends DenominationPopupComponentConfigurationDefault\n        implements IDenominationPopupComponentConfigurationDefault\n    {\n        @DefaultValue<IDenominationPopupInterfaceDefault>({\n            defaults: {\n                x: 482,\n                y: [960, 960, 960, 960, 960, 960],\n                width: 196,\n                leftHandX: 0,\n                arrowYOffset: [9, 9, 9, 9, 9, 9],\n                arrowXOffset: 96,\n                arrowAngle: 90,\n                arrowLeftHandAngle: 0,\n                buttonsContainerYOffset: 20,\n                hasOverlayBackground: false,\n                titleStyle: undefined,\n                hasShadow: true,\n                headerBorderColor: 0x787878,\n                headerColor: 0x141414,\n                borderRadius: 10,\n                borderColor: 0xf1f1f1,\n                borderSize: 2,\n                useArcs: true,\n                revertPivotPoint: false,\n                backgroundColor: 0x0,\n                backgroundAlpha: 1,\n            },\n            landscape: {\n                x: 999,\n                y: [667, 667, 667, 667, 667, 735],\n                leftHandX: 165,\n                arrowYOffset: [136, 136, 136, 136, 136, 204],\n                arrowXOffset: 9,\n                arrowAngle: 0,\n                arrowLeftHandAngle: 180,\n            },\n        })\n        public popupProps: DynamicPositionObject<IDenominationPopupInterfaceDefault> &\n            IDenominationPopupInterfaceDefault;\n\n        @DefaultValue<IDenominationButtonInterfaceDefault>({\n            defaults: {\n                buttonTextures: ['svgBet', 'svgBetPressed', 'svgBet', 'svgBet'],\n                buttonSelectedTextures: ['svgBetBlue', 'svgBetBluePressed', 'svgBetBlue', 'svgBetBlue'],\n                buttonWidth: 106,\n                buttonHeight: 86,\n                buttonTextureHeight: 95,\n                buttonTextureWidth: 120,\n                buttonOffsetY: 10,\n                additionalButtonOffsetY: 80,\n            },\n        })\n        public denominationButtonProps: DynamicPositionObject<IDenominationButtonInterfaceDefault> &\n            IDenominationButtonInterfaceDefault;\n    }\n    return InternalDenominationPopupComponentConfigurationDefault;\n}\n","import Core, { BaseController } from '@egt/core';\nimport { RootStore } from '@egt/slot';\nimport { DenominationButton } from '@egt/ui-lib';\nimport { merge } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport DenominationPopupSubjectsDefault from '../subjects/DenominationPopupSubjectsDefault';\nimport DenominationPopupViewDefault from '../views/DenominationPopupViewDefault';\n\n@injectable()\nexport default class DenominationPopupControllerDefault extends BaseController {\n    constructor(\n        @inject('DenominationPopupView') protected denominationPopup: DenominationPopupViewDefault,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('DenominationPopupSubjects') protected subjects: DenominationPopupSubjectsDefault,\n    ) {\n        super(denominationPopup);\n    }\n\n    public destroy(): void {\n        super.destroy();\n    }\n\n    public init(): void {\n        this.attachEventListeners();\n        this.rootStore.subjects.DENOMINATIONS_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onDenominationsChanged.bind(this),\n        );\n\n        this.rootStore.subjects.TOGGLE_DENOMINATION_POPUP.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.toggleDenominationPopup.bind(this),\n        );\n        this.rootStore.subjects.SETTINGS_DENOMINATION_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onDenominationChanged.bind(this, true),\n        );\n        this.rootStore.subjects.CLOSE_ALL_POPUPS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.forceClosePopup.bind(this),\n        );\n        const closeFlow = merge(this.DESTROY, this.rootStore.subjects.CLOSE_DENOMINATION_POPUP);\n        closeFlow.pipe(takeUntil(closeFlow)).subscribe(this.closePopup.bind(this, false));\n\n        this.rootStore.subjects.MODAL_PRESSED.pipe(takeUntil(this.DESTROY)).subscribe(this.closePopup.bind(this, true));\n    }\n\n    protected onDenominationsChanged(): void {\n        this.denominationPopup.onDenominationsChanged();\n        this.attachEventListeners();\n    }\n\n    private attachEventListeners(): void {\n        this.rootStore.uiStore.denominations.forEach((_denomination, index) => {\n            const i = index + 1;\n\n            this.denominationPopup\n                .find('denominationButton' + i)\n                .CLICK.pipe(takeUntil(this.DESTROY))\n                .subscribe(\n                    this.onDenominationChanged.bind(this, false, { denomination: i, playDenomChangeSound: true }),\n                );\n        });\n    }\n\n    private onDenominationChanged(dispatchedFromSettings: boolean = false, data: any): void {\n        if (data.playDenomChangeSound) {\n            Core.sounds.play('changeDenominationSound');\n        }\n        if (!dispatchedFromSettings) {\n            this.rootStore.subjects.CLOSE_DENOMINATION_POPUP.next();\n        }\n\n        const denominationButton: DenominationButton = this.denominationPopup.find(\n            'denominationButton' + data.denomination,\n        );\n\n        if (!denominationButton.selected) {\n            this.clearDenominationSelection();\n            denominationButton.selected = true;\n            if (\n                this.rootStore.settings.numberOfLinesPerDenomination &&\n                this.rootStore.settings.numberOfLinesPerDenomination.length\n            ) {\n                const chosenDenomination = this.rootStore.uiStore.denominations[data.denomination - 1];\n                const [, numberOfLines] = (\n                    this.rootStore.settings.numberOfLinesPerDenomination as [number, number][]\n                ).find(([denomination]) => denomination === chosenDenomination)!;\n                if (!!numberOfLines && this.rootStore.uiStore.LINES.value !== numberOfLines) {\n                    this.rootStore.uiStore.LINES.next(numberOfLines!);\n                }\n            }\n            Core.SELECTED_DENOMINATION.next(denominationButton.denominationValue);\n        }\n    }\n\n    private clearDenominationSelection(): void {\n        this.rootStore.uiStore.denominations.forEach((_denomination, index) => {\n            this.denominationPopup.find('denominationButton' + (index + 1)).selected = false;\n        });\n    }\n\n    private toggleDenominationPopup(): void {\n        if (this.denominationPopup.isOpened) {\n            Core.sounds.play('hideDenominationsSound');\n            this.closePopup();\n        } else {\n            Core.sounds.play('showDenominationsSound');\n            this.openPopup();\n        }\n    }\n\n    private closePopup(animation: boolean = true): void {\n        if (this.denominationPopup.isOpened) {\n            this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(false);\n            this.denominationPopup.close(animation);\n        }\n    }\n\n    private forceClosePopup(): void {\n        if (this.denominationPopup.isOpened) {\n            this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(false);\n        }\n        this.denominationPopup.forceClose();\n    }\n\n    private openPopup(animation: boolean = true): void {\n        if (!this.denominationPopup.isOpened) {\n            this.rootStore.subjects.CLOSE_ALL_POPUPS.next();\n            this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(true);\n            this.denominationPopup.open(animation);\n        }\n    }\n}\n","import { Subject } from 'rxjs';\nimport { injectable } from 'tsyringe';\n\n@injectable()\nexport default class DenominationPopupSubjectsDefault {\n    public readonly BEFORE_CLOSE: Subject<void> = new Subject();\n    public readonly BEFORE_OPEN: Subject<void> = new Subject();\n    public readonly AFTER_OPEN: Subject<void> = new Subject();\n}\n","import Core, { IOrientation } from '@egt/core';\nimport { ISlotConfiguration, RootStore } from '@egt/slot';\nimport { ButtonStates, DenominationButton, ITitledWindowConfig, TitledWindow, ViewContainer } from '@egt/ui-lib';\nimport { gsap } from 'gsap';\nimport { Container, Graphics, Sprite } from 'pixi.js';\nimport { fromEvent } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { IDenominationPopupComponentConfigurationDefault } from '../interfaces/InterfacesDefault';\nimport DenominationPopupSubjectsDefault from '../subjects/DenominationPopupSubjectsDefault';\n\n@injectable()\nexport default class DenominationPopupViewDefault extends ViewContainer {\n    private backgroundWindow: TitledWindow;\n    private buttonsContainer: Container;\n    private arrowSprite: Sprite;\n    private config = {} as ITitledWindowConfig;\n    private _isOpened: boolean = false;\n    private animationTween: any;\n    private overlay: Graphics;\n    private buttonsCount = 0;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected configuration: ISlotConfiguration,\n        @inject('DenominationPopupSubjects') protected subjects: DenominationPopupSubjectsDefault,\n        @inject('DenominationPopupComponentConfiguration')\n        protected componentConfiguration: IDenominationPopupComponentConfigurationDefault,\n    ) {\n        super();\n    }\n\n    public init(): void {\n        this.initialRender();\n\n        Core.LEFT_HAND_MODE.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.setOrientation(Core.ORIENTATION.value);\n        });\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n        Core.MONEY_MODE_IN_CREDITS.pipe(takeUntil(Core.ON_GAME_UNLOADED)).subscribe(this.onMoneyModeChanged.bind(this));\n        this.rootStore.subjects.FACTOR_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.maxBetBuyBonusCheck.bind(this),\n        );\n        this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.maxBetBuyBonusCheck.bind(this),\n        );\n    }\n\n    public get isOpened(): boolean {\n        return this._isOpened;\n    }\n\n    public set isOpened(value: boolean) {\n        this._isOpened = value;\n    }\n\n    public destroy(): void {\n        this.killAllAnimations();\n        this.subjects.BEFORE_CLOSE.complete();\n        this.subjects.BEFORE_OPEN.complete();\n        this.subjects.AFTER_OPEN.complete();\n        // @ts-ignore\n        this.BEFORE_CLOSE = null;\n        // @ts-ignore\n        this.BEFORE_OPEN = null;\n        // @ts-ignore\n        this.AFTER_OPEN = null;\n\n        if (this.overlay) {\n            this.removeChild(this.overlay);\n            this.overlay.destroy();\n            // @ts-ignore\n            this.overlay = null;\n        }\n\n        if (this.buttonsContainer) {\n            this.buttonsContainer.removeChildren();\n            this.buttonsContainer.destroy({ children: true, texture: true });\n            // @ts-ignore\n            this.buttonsContainer = null;\n        }\n\n        if (this.backgroundWindow) {\n            this.backgroundWindow.destroy();\n            // @ts-ignore\n            this.backgroundWindow = null;\n        }\n        if (this.arrowSprite) {\n            this.arrowSprite.destroy();\n            // @ts-ignore\n            this.arrowSprite = null;\n        }\n        // @ts-ignore\n        this.config = null;\n\n        super.destroy();\n    }\n\n    public open(animation: boolean): void {\n        this.subjects.BEFORE_OPEN.next();\n        this.killAllAnimations();\n\n        // Reset\n        this.alpha = 0;\n        this.visible = true;\n\n        if (animation) {\n            this.animationTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/denomination-popup/src/egt/modes/default/views/DenominationPopupViewDefault.ts:108:35\",null]), gsap.to(this, {\n                duration: 0.2,\n                alpha: 1,\n                ease: 'power2.in',\n                onComplete: () => {\n                    this.isOpened = true;\n                    this.subjects.AFTER_OPEN.next();\n                },\n            }));\n        } else {\n            this.isOpened = true;\n            this.alpha = 1;\n            this.subjects.AFTER_OPEN.next();\n        }\n    }\n\n    public close(animation: boolean): void {\n        this.subjects.BEFORE_CLOSE.next();\n        this.killAllAnimations();\n\n        // Reset\n        this.alpha = 1;\n\n        if (animation) {\n            this.animationTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/denomination-popup/src/egt/modes/default/views/DenominationPopupViewDefault.ts:132:35\",null]), gsap.to(this, {\n                duration: 0.2,\n                alpha: 0,\n                ease: 'power2.in',\n                onComplete: () => {\n                    this.visible = false;\n                    this.isOpened = false;\n                },\n            }));\n        } else {\n            this.alpha = 0;\n            this.visible = false;\n            this.isOpened = false;\n        }\n    }\n\n    public forceClose(): void {\n        this.killAllAnimations();\n        this.alpha = 0;\n        this.visible = false;\n        this.isOpened = false;\n    }\n\n    public onDenominationsChanged() {\n        this.removeChildren();\n        if (this.overlay) {\n            this.removeChild(this.overlay);\n            // @ts-ignore\n            this.overlay = null;\n        }\n        if (this.buttonsContainer) {\n            this.buttonsContainer.removeChildren();\n            // @ts-ignore\n            this.buttonsContainer = null;\n        }\n        if (this.backgroundWindow) {\n            // @ts-ignore\n            this.backgroundWindow = null;\n        }\n        if (this.arrowSprite) {\n            // @ts-ignore\n            this.arrowSprite = null;\n        }\n        this.initialRender();\n        this.setOrientation(Core.ORIENTATION.value);\n        this.maxBetBuyBonusCheck();\n    }\n\n    protected maxBetBuyBonusCheck(): void {\n        const maxBetBuyBonus =\n            this.rootStore.settings.settings.settings.clientSettings.maxBetLimits &&\n            this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value\n                ? this.rootStore.settings.settings.settings.clientSettings.maxBetLimits[\n                      this.rootStore.settings.currency\n                  ]\n                : undefined;\n        if (!maxBetBuyBonus) {\n            return;\n        }\n\n        const factor = this.rootStore.settings.factor\n            ? this.rootStore.settings.factor\n            : this.rootStore.uiStore.LINES.value;\n\n        this.rootStore.uiStore.denominations.forEach((_denom, index) => {\n            const denomination: DenominationButton = this.buttonsContainer.getChildByName(\n                'denominationButton' + (index + 1),\n            );\n            const hasActiveButtons = this.rootStore.uiStore.bets.every(\n                (bet: number) =>\n                    bet * denomination.denominationValue * factor > maxBetBuyBonus * Core.PLAYER_BALANCE.value.units,\n            );\n            denomination.enableButton(!hasActiveButtons);\n        });\n    }\n\n    protected setOrientation(orientation: IOrientation): void {\n        if (this._isOpened) {\n            this.close(false);\n            this.open(false);\n        }\n\n        const isLandscape: boolean = orientation.isLandscape;\n\n        this.componentConfiguration.popupProps.revertPivotPoint\n            ? this.pivot.set(0, 0)\n            : this.pivot.set(0, this.config.height);\n\n        if (isLandscape) {\n            this.x = this.componentConfiguration.popupProps.x;\n            this.y = this.componentConfiguration.popupProps.y[this.rootStore.uiStore.denominations.length - 1];\n\n            if (Core.LEFT_HAND_MODE.value) {\n                this.config.shadow = 'right';\n                this.arrowSprite.angle = this.componentConfiguration.popupProps.arrowLeftHandAngle;\n                this.arrowSprite.x = -this.componentConfiguration.popupProps.arrowXOffset;\n            } else {\n                this.config.shadow = 'left';\n                this.arrowSprite.angle = this.componentConfiguration.popupProps.arrowAngle;\n                this.arrowSprite.x = this.config.width + this.componentConfiguration.popupProps.arrowXOffset;\n            }\n\n            if (this.componentConfiguration.popupProps.revertPivotPoint) {\n                this.arrowSprite.pivot.set(this.arrowSprite.width / 2, this.arrowSprite.height / 2);\n                this.arrowSprite.y =\n                    this.componentConfiguration.popupProps.arrowYOffset[\n                        this.rootStore.uiStore.denominations.length - 1\n                    ];\n            } else {\n                this.arrowSprite.pivot.set(this.arrowSprite.width / 2, this.arrowSprite.height);\n                this.arrowSprite.y = Core.LEFT_HAND_MODE.value\n                    ? this.config.height -\n                      this.componentConfiguration.popupProps.arrowYOffset[\n                          this.rootStore.uiStore.denominations.length - 1\n                      ] -\n                      this.arrowSprite.height\n                    : this.config.height -\n                      this.componentConfiguration.popupProps.arrowYOffset[\n                          this.rootStore.uiStore.denominations.length - 1\n                      ];\n            }\n        } else {\n            this.x = this.componentConfiguration.popupProps.x;\n            this.y = this.componentConfiguration.popupProps.revertPivotPoint\n                ? this.componentConfiguration.popupProps.y[this.rootStore.uiStore.denominations.length - 1] -\n                  this.config.height\n                : this.componentConfiguration.popupProps.y[this.rootStore.uiStore.denominations.length - 1];\n\n            this.config.shadow = 'left';\n            this.arrowSprite.pivot.set(this.arrowSprite.width / 2, this.arrowSprite.height / 2);\n            this.arrowSprite.angle = this.componentConfiguration.popupProps.arrowAngle;\n            this.arrowSprite.x = this.componentConfiguration.popupProps.arrowXOffset;\n            this.arrowSprite.y =\n                this.config.height +\n                this.componentConfiguration.popupProps.arrowYOffset[this.rootStore.uiStore.denominations.length - 1];\n        }\n        if (this.overlay) {\n            this.overlay.width = orientation.width;\n            this.overlay.height = orientation.height;\n            this.overlay.x = -this.componentConfiguration.popupProps.x;\n            this.overlay.y = isLandscape\n                ? -this.componentConfiguration.popupProps.y\n                : -this.componentConfiguration.popupProps.y + this.config.height;\n        }\n        this.backgroundWindow.redrawShadows();\n    }\n\n    protected initialRender(): void {\n        this.alpha = 0;\n        this.visible = false;\n\n        // add buttons and jackpots\n        this.buttonsContainer = new Container();\n        this.buttonsContainer.name = 'Buttons container';\n\n        this.createDenominationButtons();\n        this.createDenominationBackground();\n\n        if (this.componentConfiguration.popupProps.hasOverlayBackground) {\n            this.createOverlayBackground();\n        }\n\n        this.addChild(this.buttonsContainer);\n        this.buttonsContainer.y =\n            this.config.headerHeight + this.componentConfiguration.popupProps.buttonsContainerYOffset;\n        this.buttonsContainer.x = (this.config.width - this.buttonsContainer.width) / 2;\n\n        // add arrow\n        this.arrowSprite = new Sprite(Core.assets.getTextureFromSpriteSheet('miscellaneous', 'arrowBlack.png'));\n        this.arrowSprite.name = 'Arrow';\n        this.arrowSprite.interactive = true;\n        this.addChild(this.arrowSprite);\n        this.interactive = true;\n    }\n\n    private createDenominationBackground(): void {\n        this.config.borderLeftUpTexture = Core.assets.getTextureFromSpriteSheet('miscellaneous', 'windowCornerLu.png');\n\n        if (this.componentConfiguration.popupProps.hasShadow) {\n            this.config.textureShadow = Core.assets.getTextureFromSpriteSheet('miscellaneous', 'shadow.png');\n            this.config.shadow = 'left';\n        }\n        this.config.backgroundColor = this.componentConfiguration.popupProps.backgroundColor;\n        this.config.backgroundAlpha = this.componentConfiguration.popupProps.backgroundAlpha;\n        this.config.useArcs = this.componentConfiguration.popupProps.useArcs;\n        this.config.headerBorderColor = this.componentConfiguration.popupProps.headerBorderColor;\n        this.config.headerColor = this.componentConfiguration.popupProps.headerColor;\n        this.config.borderRadius = this.componentConfiguration.popupProps.borderRadius;\n        this.config.borderSize = this.componentConfiguration.popupProps.borderSize;\n        this.config.borderColor = this.componentConfiguration.popupProps.borderColor;\n\n        this.config.width = this.componentConfiguration.popupProps.width;\n\n        // this.config.width = 196;\n        // this.config.height = this.config.headerHeight + this.rootStore.uiStore.denominations.length * (96 + 10) + 30;\n        this.config.height =\n            this.buttonsCount *\n                (this.componentConfiguration.denominationButtonProps.buttonTextureHeight +\n                    this.componentConfiguration.denominationButtonProps.buttonOffsetY) +\n            this.componentConfiguration.denominationButtonProps.additionalButtonOffsetY;\n\n        this.config.title = Core.translator.translate('DENOMINATION');\n        this.config.titleStyle = this.componentConfiguration.popupProps.titleStyle;\n        this.backgroundWindow = new TitledWindow(this.config);\n        this.backgroundWindow.name = 'Buttons window background';\n        this.backgroundWindow.interactive = true;\n        this.addChild(this.backgroundWindow);\n    }\n\n    private createOverlayBackground(): void {\n        this.overlay = new Graphics();\n        this.overlay.name = 'Overlay';\n        this.overlay\n            .beginFill(0x000000, 0.75)\n            .drawRect(0, 0, Core.ORIENTATION.value.width, Core.ORIENTATION.value.height)\n            .endFill();\n        this.addChildAt(this.overlay, 0);\n        this.overlay.interactive = true;\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/denomination-popup/src/egt/modes/default/views/DenominationPopupViewDefault.ts:351:9\",(this.overlay),\"pointerup\"]), fromEvent(this.overlay, 'pointerup')).pipe(takeUntil(this.DESTROY)).subscribe(this.close.bind(this, true));\n    }\n\n    private createDenominationButtons(): void {\n        this.buttonsCount = 0;\n        this.rootStore.uiStore.denominations.forEach((denomination, index) => {\n            const denominationButton: DenominationButton = this.createDenomination(\n                denomination,\n                'denominationButton' + (index + 1),\n                index,\n            );\n            denominationButton.interactive = true;\n            denominationButton.y =\n                (denominationButton.height + this.componentConfiguration.denominationButtonProps.buttonOffsetY) *\n                this.buttonsCount;\n            this.buttonsContainer.addChild(denominationButton);\n            this.buttonsCount++;\n        });\n    }\n\n    private createDenomination(denomination: number, name: string, index: number): DenominationButton {\n        const denominationButtonTextures = [\n            Core.assets.getAsset(\n                this.componentConfiguration.denominationButtonProps.buttonTextures[ButtonStates.Normal],\n            ).texture,\n            Core.assets.getAsset(\n                this.componentConfiguration.denominationButtonProps.buttonTextures[ButtonStates.Pressed],\n            ).texture,\n            Core.assets.getAsset(\n                this.componentConfiguration.denominationButtonProps.buttonTextures[ButtonStates.Normal],\n            ).texture,\n            Core.assets.getAsset(\n                this.componentConfiguration.denominationButtonProps.buttonTextures[ButtonStates.Disabled],\n            ).texture,\n        ];\n        const denominationSelectedTextures = [\n            Core.assets.getAsset(\n                this.componentConfiguration.denominationButtonProps.buttonSelectedTextures[ButtonStates.Normal],\n            ).texture,\n            Core.assets.getAsset(\n                this.componentConfiguration.denominationButtonProps.buttonSelectedTextures[ButtonStates.Pressed],\n            ).texture,\n            Core.assets.getAsset(\n                this.componentConfiguration.denominationButtonProps.buttonSelectedTextures[ButtonStates.Normal],\n            ).texture,\n            Core.assets.getAsset(\n                this.componentConfiguration.denominationButtonProps.buttonSelectedTextures[ButtonStates.Disabled],\n            ).texture,\n        ];\n\n        const denominationButton: DenominationButton = new DenominationButton(\n            name,\n            '1 ' + Core.translator.translate('CREDIT') + ' =',\n            denomination,\n            this.rootStore.uiStore.currency,\n            this.componentConfiguration.denominationButtonProps.buttonWidth,\n            this.componentConfiguration.denominationButtonProps.buttonHeight,\n            index,\n            denominationButtonTextures,\n            denominationSelectedTextures,\n            denomination === Core.SELECTED_DENOMINATION.value,\n            this.configuration.denomButtonStyles,\n        );\n        return denominationButton;\n    }\n\n    private killAllAnimations(): void {\n        if (this.animationTween) {\n            this.animationTween.kill();\n            this.animationTween = null;\n        }\n    }\n\n    private onMoneyModeChanged(): void {\n        this.backgroundWindow.title = Core.MONEY_MODE_IN_CREDITS.value\n            ? Core.translator.translate('DENOMINATION')\n            : Core.translator.translate('BET LEVELS');\n    }\n}\n","import {\n    AssetPriority,\n    AssetsCollection,\n    BaseComponentConfiguration,\n    DefaultAssets,\n    DefaultValue,\n    DynamicPositionObject,\n} from '@egt/core';\nimport { TextStyle } from 'pixi.js';\nimport {\n    IBalanceAndBetTextExtended,\n    IDenomArrowPositionsExtended,\n    IDenominationBackgroundPopUpPositionsExtended,\n    IDenominationPopUpTitleTextExtended,\n    IDenominationSelectedBtnPositionsExtended,\n    IDenominationPopupComponentConfigurationExtended,\n    IMainContainerPositionExtended,\n} from '../interfaces/InterfacesExtended';\n\nexport default class DenominationPopupComponentConfigurationExtended extends BaseComponentConfiguration {}\nexport function DenominationPopupConfigFactoryExtended(): any {\n    class DenominationPopupComponentConfigurationExtendedInternalClass\n        extends DenominationPopupComponentConfigurationExtended\n        implements IDenominationPopupComponentConfigurationExtended\n    {\n        public buttonsToHide = ['betButtons', 'denominationButton'];\n\n        public mainViewComponentsToHide = ['balanceContainer', 'winContainer'];\n\n        @DefaultAssets([\n            {\n                id: 'denominationResources',\n                url: '../assets/components/slot/denomination-popup/extended/denominationResources.json',\n                priority: AssetPriority.HIGHEST,\n                type: 'texture',\n            },\n            {\n                id: 'svgDenominationSelected',\n                url: '../assets/components/slot/denomination-popup/extended/ui-svg/denominationSelected.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 132, height: 132 },\n                    desktop: { width: 99, height: 99 },\n                },\n            },\n        ])\n        public assets: AssetsCollection;\n\n        @DefaultValue<IMainContainerPositionExtended>({\n            defaults: {\n                x: 0,\n                y: [-133, -153, -153, -102, -51, 0, -6], // [1 denom, 2 denom, 3 denom ...]\n                leftHandX: -276,\n            },\n            portrait: {\n                x: 0,\n                y: 0,\n            },\n        })\n        public mainContainerPosition: DynamicPositionObject<IMainContainerPositionExtended> &\n            IMainContainerPositionExtended;\n\n        @DefaultValue<IDenominationPopUpTitleTextExtended>({\n            defaults: {\n                yOffset: 30,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                    fontSize: 36,\n                    fill: '#FFFFFF',\n                    align: 'center',\n                }),\n            },\n        })\n        public popUpTitle: DynamicPositionObject<IDenominationPopUpTitleTextExtended> &\n            IDenominationPopUpTitleTextExtended;\n\n        @DefaultValue<IDenominationBackgroundPopUpPositionsExtended>({\n            defaults: {\n                width: 744,\n                height: 149,\n                popupRollHeight: 102, // roll height + space between rolls\n                x: 448,\n                y: 763,\n            },\n            portrait: {\n                x: 10,\n                y: 939,\n            },\n        })\n        public popUpGraphicsContainer: DynamicPositionObject<IDenominationBackgroundPopUpPositionsExtended> &\n            IDenominationBackgroundPopUpPositionsExtended;\n\n        @DefaultValue<IDenomArrowPositionsExtended>({\n            defaults: {\n                x: 1188,\n                y: 526,\n                angle: 270,\n                leftHandX: 176,\n                leftHandY: 475,\n                leftHandAngle: 90,\n            },\n            portrait: {\n                x: 553,\n                y: 935,\n                angle: 0,\n            },\n            desktop: {\n                y: 544,\n            },\n        })\n        public arrowPosition: DynamicPositionObject<IDenomArrowPositionsExtended> & IDenomArrowPositionsExtended;\n\n        @DefaultValue<IBalanceAndBetTextExtended>({\n            defaults: {\n                x: 468,\n                y: 743,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFD200',\n                    fontSize: 33,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                valueStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 48,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                currencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 24,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n            },\n            portrait: {\n                x: 30,\n                y: 919,\n            },\n        })\n        public balanceText: DynamicPositionObject<IBalanceAndBetTextExtended> & IBalanceAndBetTextExtended;\n\n        @DefaultValue<IBalanceAndBetTextExtended>({\n            defaults: {\n                x: 1173,\n                y: 743,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFD200',\n                    fontSize: 33,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                valueStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 48,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                currencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 24,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n            },\n            portrait: {\n                x: 735,\n                y: 919,\n            },\n        })\n        public betText: DynamicPositionObject<IBalanceAndBetTextExtended> & IBalanceAndBetTextExtended;\n\n        @DefaultValue<IDenominationSelectedBtnPositionsExtended>({\n            defaults: {\n                x: 1285,\n                y: 502,\n                leftHandX: 75,\n                scale: 1,\n            },\n            portrait: {\n                x: 578,\n                y: 1061,\n            },\n            desktop: {\n                x: 1272,\n                y: 522,\n            },\n        })\n        public selectedButton: DynamicPositionObject<IDenominationSelectedBtnPositionsExtended> &\n            IDenominationSelectedBtnPositionsExtended;\n    }\n    return DenominationPopupComponentConfigurationExtendedInternalClass;\n}\n","import { BuyBonusModes } from '@egt/buy-bonus';\nimport Core, { BaseController, ErrorTypes } from '@egt/core';\nimport { RootStore, SlotComponents } from '@egt/slot';\nimport { fromEvent } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { IDenominationPopupComponentConfigurationExtended } from '../interfaces/InterfacesExtended';\nimport DenominationPopupViewExtended from '../views/DenominationPopupViewExtended';\n@injectable()\nexport default class DenominationPopupControllerExtended extends BaseController {\n    private errorType: number | null = null;\n    constructor(\n        @inject('DenominationPopupView') protected extendedDenominationPopup: DenominationPopupViewExtended,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('DenominationPopupComponentConfiguration')\n        protected componentConfiguration: IDenominationPopupComponentConfigurationExtended,\n    ) {\n        super(extendedDenominationPopup);\n    }\n\n    public destroy(): void {\n        super.destroy();\n    }\n\n    public init(): void {\n        this.attachEventListeners();\n    }\n\n    public attachEventListeners(): void {\n        this.addSelectedButtonEventListener();\n\n        this.rootStore.subjects.DENOMINATIONS_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onDenominationsChanged.bind(this),\n        );\n\n        this.rootStore.uiStore.BALANCE.pipe(takeUntil(this.DESTROY)).subscribe(this.onBalanceChanged.bind(this));\n\n        this.rootStore.subjects.TOGGLE_DENOMINATION_POPUP.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.toggleExtendedDenominationPopup.bind(this),\n        );\n        this.rootStore.subjects.CLOSE_ALL_POPUPS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.forceClosePopup.bind(this),\n        );\n        this.rootStore.subjects.CLOSE_DENOMINATION_POPUP.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.closePopup(null, 'chosenDenominationSound');\n        });\n\n        this.rootStore.subjects.MODAL_PRESSED.pipe(takeUntil(this.DESTROY)).subscribe(this.closePopup.bind(this));\n\n        this.rootStore.subjects.KEY_UP.pipe(takeUntil(this.DESTROY)).subscribe(this.onKeyReleased.bind(this));\n\n        this.rootStore.uiStore.STATE.pipe(takeUntil(this.DESTROY)).subscribe(this.onStateChanged.bind(this));\n\n        this.rootStore.uiStore.SELECTED_BET.pipe(takeUntil(this.DESTROY)).subscribe(this.updateBetValue.bind(this));\n        Core.SELECTED_DENOMINATION.pipe(takeUntil(this.DESTROY)).subscribe(this.updateBetValue.bind(this));\n        this.rootStore.subjects.FACTOR_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(this.updateBetValue.bind(this));\n\n        Core.SHOW_ERROR.pipe(takeUntil(this.DESTROY)).subscribe(this.onErrorChanged.bind(this));\n        Core.HIDE_ERROR.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.errorType = null;\n        });\n\n        Core.UI_BLOCKER.pipe(takeUntil(this.DESTROY)).subscribe((isUiBlocked) => {\n            if (Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS)) {\n                if (this.errorType === ErrorTypes.CONFIRMATION) {\n                    return;\n                }\n                this.changeBuyBonusParameters(isUiBlocked);\n            }\n            this.extendedDenominationPopup.isInteractive = isUiBlocked;\n        });\n    }\n\n    protected onErrorChanged(errorData: any): void {\n        this.errorType = Number(errorData.type);\n\n        this.changeBuyBonusParameters();\n    }\n\n    protected changeBuyBonusParameters(isUiBlocked: boolean = false): void {\n        if (this.errorType === ErrorTypes.CONFIRMATION) {\n            this.rootStore.subjects.DISABLED_BUY_BONUS.next({ disabled: false, doNotChangeVisual: true });\n        }\n\n        this.rootStore.subjects.DISABLED_BUY_BONUS.next({ disabled: isUiBlocked, doNotChangeVisual: true });\n    }\n\n    protected toggleCustomButtons(visible: boolean): void {\n        this.componentConfiguration.buttonsToHide.forEach((btnName) => {\n            if (btnName === 'betButtons') {\n                this.rootStore.uiStore.SHOW_HIDE_BET_BUTTONS.next(visible);\n            } else {\n                this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                    name: btnName,\n                    actions: 'visible',\n                    values: visible,\n                });\n            }\n        });\n\n        this.componentConfiguration.mainViewComponentsToHide.forEach((mainViewComponent) => {\n            this.rootStore.subjects.SHOW_HIDE_MAIN_VIEW_COMPONENTS.next({\n                name: mainViewComponent,\n                actions: 'visible',\n                values: visible,\n            });\n        });\n    }\n\n    protected onKeyReleased(e: KeyboardEvent): void {\n        if (\n            e &&\n            this.rootStore.uiStore.SHOW_SETTINGS.value &&\n            ['ArrowDown', 'KeyC', 'KeyV', 'KeyB', 'KeyN', 'KeyM'].indexOf(e.code) > -1\n        ) {\n            return;\n        }\n        if (e === null || Core.UI_BLOCKER.value) {\n            return;\n        }\n\n        const blockKeys = ['KeyC', 'KeyV', 'KeyB', 'KeyN', 'KeyM'];\n        const blockKeyCodes = [67, 86, 66, 78, 77];\n\n        if (\n            (e.code !== undefined && blockKeys.includes(e.code)) ||\n            (e.keyCode !== undefined && blockKeyCodes.includes(e.keyCode))\n        ) {\n            this.forceClosePopup();\n        }\n    }\n\n    private onDenominationsChanged(): void {\n        this.extendedDenominationPopup.onDenominationsChanged();\n        this.addSelectedButtonEventListener();\n    }\n\n    private addSelectedButtonEventListener() {\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/denomination-popup/src/egt/modes/extended/controllers/DenominationPopupControllerExtended.ts:139:9\",(this.extendedDenominationPopup.selectedBtn),\"pointerup\"]), fromEvent(this.extendedDenominationPopup.selectedBtn, 'pointerup'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.closePopup.bind(this));\n    }\n\n    private onBalanceChanged(): void {\n        this.extendedDenominationPopup.updateBalance();\n    }\n\n    // private onDenominationChanged(_dispatchedFromSettings: boolean = false, data: any): void {\n    //     if (data.playDenomChangeSound) {\n    //         Core.sounds.play('changeDenominationSound');\n    //     }\n    //     Core.SELECTED_DENOMINATION.next(this.rootStore.uiStore.denominations[data.denomination - 1]);\n    // }\n\n    // private onBetChanged(): void {\n    //     const denomIndex = this.rootStore.uiStore.denominations.indexOf(Core.SELECTED_DENOMINATION.value);\n    //     const betIndex = this.rootStore.uiStore.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value);\n    //     const button: BetSettingButton = this.extendedDenominationPopup.betButtons[denomIndex][betIndex];\n    //     this.extendedDenominationPopup.updateSelectedRoll(denomIndex, button);\n    //     button.setSelected();\n    //     this.extendedDenominationPopup.updateBetValue();\n    // }\n\n    // private onBetOptionButtonPressed(betButton: any): void {\n    //     for (let i: number = 0; i < this.extendedDenominationPopup.betButtons.length; i++) {\n    //         for (const betBtn of this.extendedDenominationPopup.betButtons[i]) {\n    //             if (betButton.currentTarget === betBtn) {\n    //                 this.extendedDenominationPopup.animateDownScaleBtn(betBtn);\n    //             }\n    //         }\n    //     }\n    // }\n\n    // private onBetOptionButtonReleased(betButton: any): void {\n    //     for (let i: number = 0; i < this.extendedDenominationPopup.betButtons.length; i++) {\n    //         for (const betBtn of this.extendedDenominationPopup.betButtons[i]) {\n    //             if (betButton.currentTarget === betBtn) {\n    //                 this.extendedDenominationPopup.animateUpScaleBtn(betBtn, i);\n    //             }\n    //         }\n    //     }\n    // }\n\n    // private onBetOptionButtonClicked(betButton: BetSettingButton, dispatchedFromPopup: boolean): void {\n    //     if (this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_RESPONSE) {\n    //         return;\n    //     }\n    //     Core.UI_BLOCKER.next(true);\n    //     for (let i: number = 0; i < this.extendedDenominationPopup.betButtons.length; i++) {\n    //         for (const betBtn of this.extendedDenominationPopup.betButtons[i]) {\n    //             if (betButton === betBtn) {\n    //                 if (!Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS)) {\n    //                     this.rootStore.subjects.DISABLED_BUY_BONUS.next(\n    //                         this.checkForMaxBet(betBtn.betLevel, betBtn.denominationLevel),\n    //                     );\n    //                 }\n\n    //                 Timers.setTimeout(() => {\n    //                     this.extendedDenominationPopup.updateSelectedRoll(i, betBtn);\n    //                     betBtn.setPressed();\n    //                 }, 10);\n\n    //                 Timers.setTimeout(() => {\n    //                     if (this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_RESPONSE) {\n    //                         return;\n    //                     }\n    //                     betBtn.setSelected();\n    //                     this.updateBet(betButton, dispatchedFromPopup);\n    //                     Core.UI_BLOCKER.next(false);\n    //                 }, 100);\n    //             }\n    //         }\n    //     }\n    //     if (!this.extendedDenominationPopup.isInteractive) {\n    //         this.extendedDenominationPopup.isInteractive = true;\n    //     }\n    // }\n\n    // private checkForMaxBet(bet: number, denomination: number): boolean {\n    //     let buyBonusValue: number =\n    //         denomination *\n    //         bet *\n    //         (this.rootStore.settings.factors[this.rootStore.settings.factors.length - 1] /\n    //             this.rootStore.uiStore.units);\n\n    //     if (this.rootStore.settings.clientSettings?.maxBetLimits || this.rootStore.settings.maxBet) {\n    //         const maxBetForBonus: number = Math.min(\n    //             this.rootStore.settings.clientSettings?.maxBetLimits\n    //                 ? this.rootStore.settings.clientSettings?.maxBetLimits[Core.PLAYER_BALANCE.value.currency]\n    //                 : Infinity,\n    //             this.rootStore.settings.maxBet ?? Infinity,\n    //         );\n    //         if (maxBetForBonus && buyBonusValue > maxBetForBonus) {\n    //             buyBonusValue = maxBetForBonus;\n    //             return true;\n    //         }\n    //     }\n    //     return false;\n    // }\n\n    private toggleExtendedDenominationPopup(): void {\n        if (this.extendedDenominationPopup.isOpened) {\n            this.closePopup();\n        } else {\n            this.openPopup();\n        }\n    }\n\n    private closePopup(_data?: any, hideSound: string = 'hideDenominationsSound'): void {\n        // this.onBetChanged();\n        if (this.extendedDenominationPopup.isOpened) {\n            Core.sounds.play(hideSound);\n            this.toggleCustomButtons(true);\n            this.extendedDenominationPopup.close(true);\n            this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(false);\n            this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_OUTSIDE_BETS_VISIBLE.next(true);\n            this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(false);\n        }\n    }\n\n    private forceClosePopup(): void {\n        // this.onBetChanged();\n        if (this.extendedDenominationPopup.isOpened) {\n            this.toggleCustomButtons(true);\n            this.extendedDenominationPopup.forceClose();\n            this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(false);\n            this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_OUTSIDE_BETS_VISIBLE.next(true);\n            this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(false);\n        }\n    }\n\n    private openPopup(animation: boolean = true): void {\n        // this.onBetChanged();\n        if (!this.extendedDenominationPopup.isOpened) {\n            Core.sounds.play('showDenominationsSound');\n            this.rootStore.subjects.CLOSE_ALL_POPUPS.next();\n            this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(true);\n            this.extendedDenominationPopup.open(animation);\n            this.toggleCustomButtons(false);\n            this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(false);\n            this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_OUTSIDE_BETS_VISIBLE.next(false);\n        }\n    }\n\n    protected onStateChanged(): void {\n        if (this.extendedDenominationPopup.isOpened) {\n            this.toggleCustomButtons(false);\n        }\n    }\n\n    private updateBetValue(): void {\n        this.extendedDenominationPopup.updateBetValue();\n    }\n}\n","import { BetCalculatorViewDefault } from '@egt/bet-calculator';\nimport Core, { Money } from '@egt/core';\nimport { ISlotConfiguration, RootStore } from '@egt/slot';\nimport { Button, ButtonShapes, ViewContainer } from '@egt/ui-lib';\nimport { gsap } from 'gsap';\nimport { Container, NineSlicePlane, Sprite, Text } from 'pixi.js';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\n\nimport { IDenominationPopupComponentConfigurationExtended } from '../interfaces/InterfacesExtended';\n\n@injectable()\nexport default class DenominationPopupViewExtended extends ViewContainer {\n    // public readonly UPDATE_BET: BehaviorSubject<BetSettingButton | null> = new BehaviorSubject(null);\n\n    public oneDenomView: boolean = false;\n\n    public mainContainer: Container;\n    public graphicsContainer: Sprite;\n\n    public selectedBtn: Button;\n\n    protected pressingAnimation: gsap.core.Timeline | null;\n\n    // private betBtnTextures: Map<string, Texture> = new Map();\n\n    // private rollsBackgrounds: NineSlicePlane[] = [];\n    // private rollsBackgroundsSelected: NineSlicePlane[] = [];\n\n    private popUpBackground: NineSlicePlane;\n    private popUpShadow: NineSlicePlane;\n    private popUpTitleText: Text;\n    private balanceContainer: Sprite;\n    private balanceText: Text;\n    private balanceTextValue: Text;\n    private balanceTextCurrency: Text;\n    private betContainer: Sprite;\n    private betText: Text;\n    private betTextValue: Text;\n    private betTextCurrency: Text;\n    private balanceMoneyFormatter: Money;\n    private betMoneyFormatter: Money;\n    private wordSpacing: number = 6;\n    private arrow: Sprite;\n    private animationTween: any;\n    private _isOpened: boolean = false;\n\n    private mainContainerY: number;\n    private startingPoint: number = 250;\n    private bounceOffset: number = 15;\n\n    private betCalculator: BetCalculatorViewDefault;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected configuration: ISlotConfiguration,\n        @inject('DenominationPopupComponentConfiguration')\n        protected componentConfiguration: IDenominationPopupComponentConfigurationExtended,\n    ) {\n        super();\n    }\n\n    public init(): void {\n        this.isOpened = false;\n        // this.createBtnsTextures();\n        this.initialRender();\n\n        Core.LEFT_HAND_MODE.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n        // this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.pipe(takeUntil(this.DESTROY)).subscribe(\n        //     this.changeBtnsTextures.bind(this),\n        // );\n    }\n\n    private initialRender() {\n        this.createGraphicsContainer();\n        this.createMainContainer();\n        this.createSelectedBtn();\n        this.createDenominationPopUp();\n        this.close(false);\n        this.createBalanceText();\n        this.createBetText();\n\n        this.betCalculator = Core.gameDependencyContainer.resolve('BetCalculator');\n\n        if (this.betCalculator?.oneDenomView) {\n            this.oneDenomView = true;\n        }\n    }\n\n    // private createBtnsTextures(): void {\n    //     this.betBtnTextures.set('Normal', Core.assets.getAsset('svgDenominationPopUpNormal').texture);\n    //     this.betBtnTextures.set('Focus', Core.assets.getAsset('svgDenominationPopUpFocus').texture);\n    //     this.betBtnTextures.set('Selected', Core.assets.getAsset('svgDenominationPopUpSelected').texture);\n    //     this.betBtnTextures.set('Disabled', Core.assets.getAsset('svgDenominationPopUpNormal').texture);\n    //     this.betBtnTextures.set('Hover', Core.assets.getAsset('svgDenominationPopUpHover').texture);\n    //     this.betBtnTextures.set('Pressed', Core.assets.getAsset('svgDenominationPopUpPressed').texture);\n\n    //     if (Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS)) {\n    //         this.betBtnTextures.set('NormalSpecial', Core.assets.getAsset('svgDenominationPopUpNormal').texture);\n    //         this.betBtnTextures.set('FocusSpecial', Core.assets.getAsset('svgDenominationPopUpFocusSpecial').texture);\n    //         this.betBtnTextures.set(\n    //             'SelectedSpecial',\n    //             Core.assets.getAsset('svgDenominationPopUpSelectedSpecial').texture,\n    //         );\n    //         this.betBtnTextures.set('DisabledSpecial', Core.assets.getAsset('svgDenominationPopUpNormal').texture);\n    //         this.betBtnTextures.set('HoverSpecial', Core.assets.getAsset('svgDenominationPopUpHoverSpecial').texture);\n    //         this.betBtnTextures.set(\n    //             'PressedSpecial',\n    //             Core.assets.getAsset('svgDenominationPopUpPressedSpecial').texture,\n    //         );\n    //     }\n    // }\n\n    // private changeBtnsTextures() {\n    //     const textureType: string = this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value\n    //         ? 'Special'\n    //         : '';\n    //     for (const betButtonRow of this.betButtons) {\n    //         for (const betButton of betButtonRow) {\n    //             betButton.updateTextures(\n    //                 this.betBtnTextures.get('Normal' + textureType) as Texture,\n    //                 this.betBtnTextures.get('Focus' + textureType) as Texture,\n    //                 this.betBtnTextures.get('Selected' + textureType) as Texture,\n    //                 this.betBtnTextures.get('Disabled' + textureType) as Texture,\n    //                 this.betBtnTextures.get('Hover' + textureType) as Texture,\n    //                 this.betBtnTextures.get('Pressed' + textureType) as Texture,\n    //             );\n    //         }\n    //     }\n    // }\n\n    public destroy(): void {\n        this.killAllAnimations();\n\n        this.destroyObjects();\n        this.destroyObject(this.animationTween);\n        this.removeChildren();\n        super.destroy();\n    }\n\n    private destroyObjects() {\n        this.destroyObject(this.mainContainer);\n        this.destroyObject(this.graphicsContainer);\n        this.destroyObject(this.selectedBtn);\n        this.destroyObject(this.popUpBackground);\n        this.destroyObject(this.popUpShadow);\n        this.destroyObject(this.popUpTitleText);\n        this.destroyObject(this.balanceContainer);\n        this.destroyObject(this.balanceText);\n        this.destroyObject(this.balanceTextValue);\n        this.destroyObject(this.balanceTextCurrency);\n        this.destroyObject(this.betContainer);\n        this.destroyObject(this.betText);\n        this.destroyObject(this.betTextValue);\n        this.destroyObject(this.betTextCurrency);\n        this.destroyObject(this.balanceMoneyFormatter);\n        this.destroyObject(this.betMoneyFormatter);\n        this.destroyObject(this.arrow);\n    }\n\n    public get isOpened(): boolean {\n        return this._isOpened;\n    }\n\n    public set isOpened(value: boolean) {\n        this._isOpened = value;\n    }\n\n    public open(animation: boolean): void {\n        this.setOrientation();\n        this.updateBetValue();\n        this.mainContainer.addChildAt(this.betCalculator, this.mainContainer.getChildIndex(this.graphicsContainer) - 1);\n        this.betCalculator.pivot.set(0, 0);\n\n        this.isOpened = true;\n        this.killAllAnimations();\n        this.betCalculator.changeBtnsTextures.bind(this);\n        this.betCalculator.resetCalculatorPopUp();\n\n        this.popUpTitleText.text = Core.translator.translate(\n            this.rootStore.subjects.EXTENDED_DENOMINATION_POP_UP_TITLE.value,\n        );\n\n        this.mainContainer.alpha = 0;\n        this.mainContainer.y = this.mainContainerY + this.startingPoint;\n        this.mainContainer.visible = true;\n\n        const arrowY =\n            Core.LEFT_HAND_MODE.value && Core.ORIENTATION.value.isLandscape\n                ? this.componentConfiguration.arrowPosition.leftHandY\n                : this.componentConfiguration.arrowPosition.y;\n        this.arrow.alpha = 0;\n        this.arrow.y = arrowY + this.startingPoint;\n        this.arrow.visible = true;\n\n        this.selectedBtn.visible = true;\n        this.selectedBtn.alpha = 1;\n\n        if (animation) {\n            this.animationTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/denomination-popup/src/egt/modes/extended/views/DenominationPopupViewExtended.ts:201:35\",null]), gsap.timeline());\n\n            const animateAlpha = (alpha: number, duration: number) => ({\n                alpha,\n                duration,\n            });\n            const animateBounce = (y: number, duration: number, ease: string) => ({\n                y,\n                duration,\n                ease,\n            });\n\n            const onComplete = () => {\n                this.isInteractive = false;\n                // this.graphicsContainer.alpha = 1;\n                // this.graphicsContainer.visible = true;\n            };\n\n            this.animationTween\n                .to(this.mainContainer, animateAlpha(1, 0.3), 0)\n                .to(this.arrow, animateAlpha(1, 0.3), '<')\n                .to(this.mainContainer, animateBounce(this.mainContainerY - this.bounceOffset, 0.25, 'power1.out'), 0)\n                .to(this.arrow, animateBounce(arrowY - this.bounceOffset, 0.25, 'power1.out'), '<')\n                .to(this.mainContainer, animateBounce(this.mainContainerY, 0.2, 'power1.in'), 0.25)\n                .to(\n                    this.arrow,\n                    {\n                        ...animateBounce(arrowY, 0.2, 'power1.in'),\n                        onComplete,\n                    },\n                    '<',\n                );\n        } else {\n            this.mainContainer.alpha = 1;\n            this.arrow.alpha = 1;\n            this.isInteractive = false;\n            // this.graphicsContainer.alpha = 1;\n            // this.graphicsContainer.visible = true;\n        }\n    }\n\n    public close(animation: boolean): void {\n        if (this.betCalculator) {\n            this.mainContainer.removeChild(this.betCalculator);\n        }\n\n        this.isOpened = false;\n        this.killAllAnimations();\n        this.isInteractive = true;\n        // this.graphicsContainer.alpha = 0;\n        // this.graphicsContainer.visible = false;\n        this.mainContainer.alpha = 1;\n        this.mainContainer.visible = true;\n        this.arrow.alpha = 1;\n        this.arrow.visible = true;\n        this.selectedBtn.alpha = 0;\n        this.selectedBtn.visible = false;\n        const arrowY =\n            Core.LEFT_HAND_MODE.value && Core.ORIENTATION.value.isLandscape\n                ? this.componentConfiguration.arrowPosition.leftHandY\n                : this.componentConfiguration.arrowPosition.y;\n\n        if (animation) {\n            this.animationTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/denomination-popup/src/egt/modes/extended/views/DenominationPopupViewExtended.ts:264:35\",null]), gsap.timeline());\n\n            const animateBounce = (alpha: number, y: number, duration: number) => ({\n                alpha,\n                y,\n                duration,\n            });\n\n            const onComplete = () => {\n                this.noVisibility();\n            };\n\n            this.animationTween\n                .to(this.mainContainer, animateBounce(0, this.mainContainerY + this.startingPoint, 0.3))\n                .to(this.arrow, { ...animateBounce(0, arrowY + this.startingPoint, 0.3), onComplete }, '<');\n        } else {\n            this.noVisibility();\n        }\n    }\n\n    public forceClose(): void {\n        this.isOpened = false;\n        this.killAllAnimations();\n        this.noVisibility();\n        this.isInteractive = true;\n        // this.graphicsContainer.alpha = 0;\n        // this.graphicsContainer.visible = false;\n        this.selectedBtn.alpha = 0;\n        this.selectedBtn.visible = false;\n    }\n\n    public onDenominationsChanged() {\n        const wasOpen = this.isOpened;\n        this.removeChildren();\n\n        this.initialRender();\n\n        if (wasOpen) {\n            this.open(false);\n        } else {\n            this.close(false);\n        }\n        this.setOrientation();\n    }\n\n    public get isInteractive(): boolean {\n        return this.graphicsContainer.interactive;\n    }\n\n    public set isInteractive(isContainerInteractive: boolean) {\n        this.graphicsContainer.interactive = isContainerInteractive;\n    }\n\n    public noVisibility() {\n        this.mainContainer.alpha = 0;\n        this.mainContainer.visible = false;\n        this.arrow.alpha = 0;\n        this.arrow.visible = false;\n    }\n\n    // public updateSelectedRoll(_betButton: BetSettingButton): void {\n    //     this.setOrientation();\n    // }\n\n    public updateBetValue(): void {\n        this.betMoneyFormatter.amountMoney = this.getTotalBet();\n        this.betTextValue.text = this.betMoneyFormatter.stringMoney;\n        this.positionBetBalance();\n        this.fitBetBalanceInBounds();\n    }\n\n    public updateBalance(): void {\n        this.balanceMoneyFormatter.amountMoney = this.rootStore.uiStore.BALANCE.value;\n        this.balanceTextValue.text = this.balanceMoneyFormatter.stringMoney;\n        this.positionBetBalance();\n        this.fitBetBalanceInBounds();\n    }\n\n    public fitBetBalanceInBounds(): void {\n        const maxWidth = this.betContainer.x - this.balanceContainer.x;\n        const balanceWidth =\n            this.balanceText.width +\n            this.balanceTextValue.width +\n            this.balanceTextCurrency.width +\n            2 * this.wordSpacing;\n        const betWidth =\n            this.betText.width + this.betTextValue.width + this.betTextCurrency.width + 2 * this.wordSpacing;\n        const actualWidth = balanceWidth + this.wordSpacing * 2 + betWidth;\n        this.betContainer.scale.set(1);\n        this.balanceContainer.scale.set(1);\n        if (actualWidth > maxWidth) {\n            const scaleFactor = maxWidth / actualWidth - 0.05;\n            this.betContainer.scale.set(scaleFactor);\n            this.balanceContainer.scale.set(scaleFactor);\n            this.positionBetBalance();\n        }\n    }\n\n    public positionBetBalance(): void {\n        this.balanceTextCurrency.x = this.balanceTextValue.x + this.balanceTextValue.width + this.wordSpacing;\n        this.betTextCurrency.x = this.betTextValue.x + this.betTextValue.width + this.wordSpacing;\n        this.betContainer.pivot.set(\n            this.betText.width + this.betTextValue.width + this.betTextCurrency.width + 2 * this.wordSpacing,\n            0,\n        );\n    }\n\n    private createBalanceText(): void {\n        this.balanceMoneyFormatter = new Money(this.rootStore.uiStore.BALANCE.value);\n        this.balanceContainer = new Sprite();\n        this.mainContainer.addChild(this.balanceContainer);\n\n        this.balanceText = new Text(\n            Core.translator.translate('BALANCE') + ':',\n            this.componentConfiguration.balanceText.textStyle,\n        );\n        this.balanceText.resolution = 2;\n        this.balanceContainer.addChild(this.balanceText);\n        this.balanceText.pivot.set(0, this.balanceText.height);\n\n        this.balanceTextValue = new Text(\n            this.balanceMoneyFormatter.stringMoney,\n            this.componentConfiguration.balanceText.valueStyle,\n        );\n        this.balanceTextValue.pivot.set(0, this.balanceTextValue.height);\n        this.balanceTextValue.resolution = 2;\n        this.balanceContainer.addChild(this.balanceTextValue);\n        this.balanceTextValue.x = this.balanceText.x + this.balanceText.width + this.wordSpacing;\n\n        this.balanceTextCurrency = new Text(\n            this.rootStore.settings.currency,\n            this.componentConfiguration.balanceText.currencyStyle,\n        );\n        this.balanceTextCurrency.pivot.set(0, this.balanceTextCurrency.height);\n        this.balanceTextCurrency.resolution = 2;\n        this.balanceContainer.addChild(this.balanceTextCurrency);\n        this.balanceTextCurrency.x = this.balanceTextValue.x + this.balanceTextValue.width + this.wordSpacing;\n    }\n\n    private createBetText(): void {\n        this.betMoneyFormatter = new Money(this.getTotalBet());\n        this.betContainer = new Sprite();\n        this.mainContainer.addChild(this.betContainer);\n\n        this.betText = new Text(Core.translator.translate('BET') + ':', this.componentConfiguration.betText.textStyle);\n        this.betText.pivot.set(0, this.betText.height);\n        this.betText.resolution = 2;\n        this.betContainer.addChild(this.betText);\n\n        this.betTextValue = new Text(\n            this.betMoneyFormatter.stringMoney,\n            this.componentConfiguration.betText.valueStyle,\n        );\n        this.betTextValue.pivot.set(0, this.betTextValue.height);\n        this.betTextValue.resolution = 2;\n        this.betContainer.addChild(this.betTextValue);\n\n        this.betTextCurrency = new Text(\n            this.rootStore.settings.currency,\n            this.componentConfiguration.betText.currencyStyle,\n        );\n        this.betTextCurrency.pivot.set(0, this.betTextCurrency.height);\n        this.betTextCurrency.resolution = 2;\n        this.betContainer.addChild(this.betTextCurrency);\n\n        this.betTextValue.x = this.betText.x + this.betText.width + this.wordSpacing;\n        this.betTextCurrency.x = this.betTextValue.x + this.betTextValue.width + this.wordSpacing;\n\n        this.betContainer.pivot.set(\n            this.betText.width + this.betTextValue.width + this.betTextCurrency.width + 2 * this.wordSpacing,\n            0,\n        );\n    }\n\n    private createDenominationPopUp(): void {\n        this.createPopupGraphics();\n        this.createPopUpTexts();\n        this.createArrow();\n\n        //         for (let i: number = 0; i < this.rootStore.uiStore.denominations.length; i++) {\n        //             const rollBackground = new NineSlicePlane(\n        //                 Core.assets.getTextureFromSpriteSheet('denominationResources', 'popupFill.png'),\n        //                 25,\n        //                 25,\n        //                 25,\n        //                 25,\n        //             );\n        //             this.mainContainer.addChild(rollBackground);\n        //             this.rollsBackgrounds.push(rollBackground);\n\n        //             const rollsBackgroundsSelected = new NineSlicePlane(\n        //                 Core.assets.getTextureFromSpriteSheet('denominationResources', 'popupFillSelected.png'),\n        //                 25,\n        //                 25,\n        //                 25,\n        //                 25,\n        //             );\n        //             this.mainContainer.addChild(rollsBackgroundsSelected);\n        //             this.rollsBackgroundsSelected.push(rollsBackgroundsSelected);\n\n        //             let selectedRoll: boolean = false;\n\n        //             if (Core.SELECTED_DENOMINATION.value === this.rootStore.uiStore.denominations[i]) {\n        //                 selectedRoll = true;\n        //                 rollBackground.visible = false;\n        //                 rollsBackgroundsSelected.visible = true;\n        //             } else {\n        //                 rollBackground.visible = true;\n        //                 rollsBackgroundsSelected.visible = false;\n        //             }\n\n        //             if (this.componentConfiguration.additionalText.hasAdditionalText) {\n        //                 this.createAdditionalText(i, selectedRoll);\n        //             }\n        //             this.betButtons.push([]);\n        //             for (let t: number = 0; t < this.rootStore.uiStore.bets.length; t++) {\n        //                 let selectedButton: boolean = false;\n        //                 if (this.rootStore.uiStore.SELECTED_BET.value === this.rootStore.uiStore.bets[t] && selectedRoll) {\n        //                     selectedButton = true;\n        //                 }\n        //                 this.createBetButtons(i, t, selectedRoll, selectedButton);\n        //             }\n        //         }\n        //         this.mainContainer.addChild(this.graphicsContainer);\n        //     }\n\n        //     private createBetButtons(\n        //         denominationIndex: number,\n        //         betIndex: number,\n        //         selectedRoll: boolean,\n        //         selectedButton: boolean,\n        //     ): void {\n        //         const textureType: string = this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value\n        //             ? 'Special'\n        //             : '';\n\n        //         const btnTextures: BetSettingsButtonTextures = new BetSettingsButtonTextures(\n        //             this.betBtnTextures.get('Normal' + textureType) as Texture,\n        //             this.betBtnTextures.get('Focus' + textureType) as Texture,\n        //             this.betBtnTextures.get('Selected' + textureType) as Texture,\n        //             this.betBtnTextures.get('Disabled' + textureType) as Texture,\n        //             this.betBtnTextures.get('Hover' + textureType) as Texture,\n        //             this.betBtnTextures.get('Pressed' + textureType) as Texture,\n        //         );\n\n        //         const factor = this.componentConfiguration.additionalText.lines\n        //             ? this.rootStore.settings.numberOfLinesPerDenomination![denominationIndex][1]\n        //             : this.rootStore.settings.factor;\n\n        //         const maxBetLimits =\n        //             this.rootStore.settings.settings.settings?.clientSettings?.maxBetLimits &&\n        //             Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS)\n        //                 ? this.rootStore.settings.settings.settings.clientSettings.maxBetLimits[\n        //                       this.rootStore.settings.currency\n        //                   ]\n        //                 : undefined;\n\n        //         const button = new BetSettingButton(\n        //             this.rootStore.uiStore.denominations[denominationIndex],\n        //             this.rootStore.uiStore.bets[betIndex],\n        //             factor,\n        //             btnTextures,\n        //             this.componentConfiguration.popUpButtonsText.valueOffset.valueOf(),\n        //             this.componentConfiguration.popUpButtonsText.currencyOffset.valueOf(),\n        //             Object.assign({}, this.componentConfiguration.popUpButtonsText.normalTextStyle),\n        //             Object.assign({}, this.componentConfiguration.popUpButtonsText.currencyNormalTextStyle),\n        //             Object.assign({}, this.componentConfiguration.popUpButtonsText.currencyHilightedTextStyle),\n        //             Object.assign({}, this.componentConfiguration.popUpButtonsText.hilightedTextStyle),\n        //             this.componentConfiguration.popUpButtonsText.width.valueOf(),\n        //             this.componentConfiguration.popUpButtonsText.height.valueOf(),\n        //             this.createJpStamp(betIndex),\n        //             this.componentConfiguration.jackpotStampConfig?.offset,\n        //             this.rootStore.settings.maxBet,\n        //             maxBetLimits,\n        //         );\n\n        //         if (selectedRoll) {\n        //             button.setHilighted();\n\n        this.mainContainer.addChild(this.graphicsContainer);\n    }\n\n    private createPopupGraphics(): void {\n        this.popUpShadow = new NineSlicePlane(\n            Core.assets.getTextureFromSpriteSheet('denominationResources', 'shadow.png'),\n            60,\n            60,\n            60,\n            60,\n        );\n        this.mainContainer.addChild(this.popUpShadow);\n\n        this.popUpBackground = new NineSlicePlane(\n            Core.assets.getTextureFromSpriteSheet('denominationResources', 'popup.png'),\n            60,\n            60,\n            60,\n            60,\n        );\n        this.popUpBackground.interactive = true;\n        this.mainContainer.addChild(this.popUpBackground);\n    }\n\n    private createPopUpTexts(): void {\n        this.popUpTitleText = new Text('BET LEVELS', this.componentConfiguration.popUpTitle.textStyle);\n        this.popUpTitleText.resolution = 2;\n        this.popUpTitleText.anchor.set(0.5);\n        this.mainContainer.addChild(this.popUpTitleText);\n    }\n\n    private createArrow(): void {\n        this.arrow = new Sprite(Core.assets.getTextureFromSpriteSheet('denominationResources', 'arrow.png'));\n        this.addChild(this.arrow);\n    }\n\n    private killAllAnimations(): void {\n        if (this.animationTween) {\n            this.animationTween.kill();\n            this.animationTween = null;\n        }\n    }\n\n    private setOrientation(): void {\n        this.killAllAnimations();\n        if (this.isOpened) {\n            this.mainContainer.alpha = 1;\n            this.arrow.alpha = 1;\n            this.isInteractive = false;\n        } else {\n            this.noVisibility();\n            this.isInteractive = true;\n        }\n        let rows = this.rootStore.uiStore.denominations.length;\n        if (this.oneDenomView) {\n            rows = this.betCalculator.betButtons.length;\n        }\n        this.mainContainerY = Array.isArray(this.componentConfiguration.mainContainerPosition.y)\n            ? this.componentConfiguration.mainContainerPosition.y[rows - 1]\n            : this.componentConfiguration.mainContainerPosition.y;\n\n        this.mainContainer.x = this.componentConfiguration.mainContainerPosition.x;\n        this.mainContainer.y = this.mainContainerY;\n\n        this.popUpBackground.x = this.componentConfiguration.popUpGraphicsContainer.x;\n        this.popUpBackground.y = this.componentConfiguration.popUpGraphicsContainer.y;\n        this.popUpBackground.width = this.graphicsContainer.width =\n            this.componentConfiguration.popUpGraphicsContainer.width;\n        this.popUpBackground.height = this.graphicsContainer.height =\n            this.componentConfiguration.popUpGraphicsContainer.height + this.betCalculator.height;\n        this.popUpBackground.pivot.set(0, this.popUpBackground.height);\n        this.graphicsContainer.y = this.popUpBackground.y - this.popUpBackground.height;\n        this.graphicsContainer.x = this.popUpBackground.x;\n\n        this.popUpShadow.x = this.popUpBackground.x - 40;\n        this.popUpShadow.y = this.popUpBackground.y + 40;\n        this.popUpShadow.width = this.popUpBackground.width + 80;\n        this.popUpShadow.height = this.popUpBackground.height + 40;\n        this.popUpShadow.pivot.set(0, this.popUpShadow.height);\n\n        this.popUpTitleText.x =\n            this.componentConfiguration.popUpGraphicsContainer.x +\n            this.componentConfiguration.popUpGraphicsContainer.width / 2;\n        this.popUpTitleText.y =\n            this.popUpBackground.y - this.popUpBackground.height + this.componentConfiguration.popUpTitle.yOffset;\n\n        this.arrow.x = this.componentConfiguration.arrowPosition.x;\n        this.arrow.y = this.componentConfiguration.arrowPosition.y;\n        this.arrow.angle = this.componentConfiguration.arrowPosition.angle;\n\n        this.balanceContainer.x = this.componentConfiguration.balanceText.x;\n        this.balanceContainer.y = this.componentConfiguration.balanceText.y;\n        this.betContainer.x = this.componentConfiguration.betText.x;\n        this.betContainer.y = this.componentConfiguration.betText.y;\n\n        this.selectedBtn.x = this.componentConfiguration.selectedButton.x;\n        this.selectedBtn.y = this.componentConfiguration.selectedButton.y;\n        this.selectedBtn.scale.set(this.componentConfiguration.selectedButton.scale);\n\n        this.setLeftHand();\n    }\n\n    private setLeftHand(): void {\n        if (Core.LEFT_HAND_MODE.value && Core.ORIENTATION.value.isLandscape) {\n            this.mainContainer.x = this.componentConfiguration.mainContainerPosition.leftHandX;\n\n            this.arrow.x = this.componentConfiguration.arrowPosition.leftHandX;\n            this.arrow.y = this.componentConfiguration.arrowPosition.leftHandY;\n            this.arrow.angle = this.componentConfiguration.arrowPosition.leftHandAngle;\n\n            this.selectedBtn.x = this.componentConfiguration.selectedButton.leftHandX;\n        }\n    }\n\n    private getTotalBet(): number {\n        const factor = this.rootStore.settings.factor\n            ? this.rootStore.settings.factor\n            : this.rootStore.uiStore.LINES.value;\n        return Core.SELECTED_DENOMINATION.value * this.rootStore.uiStore.SELECTED_BET.value * factor;\n    }\n\n    private createSelectedBtn(): void {\n        this.selectedBtn = new Button(\n            [Core.assets.getAsset('svgDenominationSelected').texture],\n            undefined,\n            ButtonShapes.Circle,\n        );\n        this.selectedBtn.pivot.set(this.selectedBtn.width / 2, this.selectedBtn.height / 2);\n        this.selectedBtn.interactive = true;\n        this.addChild(this.selectedBtn);\n    }\n\n    private createGraphicsContainer(): void {\n        this.graphicsContainer = new Sprite();\n        this.isInteractive = true;\n        // this.graphicsContainer.visible = false;\n        // this.graphicsContainer.alpha = 0;\n        // this.addChild(this.graphicsContainer);\n    }\n\n    private createMainContainer(): void {\n        this.mainContainer = new Container();\n        this.mainContainer.visible = false;\n        this.mainContainer.alpha = 0;\n        this.addChild(this.mainContainer);\n    }\n\n    private destroyObject(obj: any) {\n        obj?.destroy?.();\n        // @ts-ignore\n        obj = null;\n    }\n}\n","import {\n    AssetPriority,\n    AssetsCollection,\n    BaseComponentConfiguration,\n    DefaultAssets,\n    DefaultValue,\n    DynamicPositionObject,\n} from '@egt/core';\nimport { TextStyle } from 'pixi.js';\nimport {\n    IBalanceAndBetTextMaxBet,\n    IBetBasedLayoutConfig,\n    IBetControlButtons,\n    IBetMultiplierPanel,\n    IBetPanel,\n    ICurvePositionObjectMaxBet,\n    IDenomArrowPositionsMaxBet,\n    IDenominationBackgroundPopUpPositionsMaxBet,\n    IDenominationPopUpShadowMaxBet,\n    IDenominationPopUpTitleTextMaxBet,\n    IDenominationPopupComponentConfigurationMaxBet,\n    IDenominationSelectedBtnPositionsMaxBet,\n    IMainContainerPositionMaxBet,\n    IMaxBetButtonPosition,\n    ITextContainer,\n    ITotalBet,\n} from '../interfaces/InterfacesMaxBet';\n\nexport default class DenominationPopupComponentConfigurationMaxBet extends BaseComponentConfiguration {}\nexport function DenominationPopupConfigFactoryMaxBet(): any {\n    class DenominationPopupComponentConfigurationMaxBetInternalClass\n        extends DenominationPopupComponentConfigurationMaxBet\n        implements IDenominationPopupComponentConfigurationMaxBet\n    {\n        public useNonLinearBetTitles = false;\n\n        public buttonsToHide = ['betButtons', 'denominationButton'];\n\n        public mainViewComponentsToHide = ['balanceContainer', 'winContainer'];\n\n        @DefaultAssets([\n            {\n                id: 'denominationResources',\n                url: '../assets/components/slot/denomination-popup/max-bet/denominationResources.json',\n                priority: AssetPriority.HIGHEST,\n                type: 'texture',\n            },\n            {\n                id: 'svgDenominationSelected',\n                url: '../assets/components/slot/denomination-popup/max-bet/ui-svg/denominationSelected.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 135, height: 76 },\n                },\n            },\n            {\n                id: 'maxBetButtonNormal',\n                url: '../assets/components/slot/denomination-popup/max-bet/ui-svg/maxBetButtonNormal.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 246, height: 118 },\n                },\n            },\n            {\n                id: 'maxBetButtonActive',\n                url: '../assets/components/slot/denomination-popup/max-bet/ui-svg/maxBetButtonActive.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 246, height: 118 },\n                },\n            },\n            {\n                id: 'maxBetLabel',\n                url: '../assets/components/slot/denomination-popup/max-bet/ui-svg/maxBetLabel.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 198, height: 55 },\n                },\n            },\n            // {\n            //     id: 'svgDenominationPopUpNormal',\n            //     url: '../assets/components/slot/denomination-popup/max-bet/ui-svg/denominationPopUpNormal.svg',\n            //     priority: AssetPriority.HIGHEST,\n            //     type: 'svg',\n            //     config: {\n            //         mobile: { width: 134, height: 78 },\n            //         desktop: { width: 105, height: 75 },\n            //     },\n            // },\n            // {\n            //     id: 'svgDenominationPopUpPressed',\n            //     url: '../assets/components/slot/denomination-popup/max-bet/ui-svg/denominationPopUpPressed.svg',\n            //     priority: AssetPriority.HIGHEST,\n            //     type: 'svg',\n            //     config: {\n            //         mobile: { width: 134, height: 78 },\n            //         desktop: { width: 105, height: 75 },\n            //     },\n            // },\n            // {\n            //     id: 'svgDenominationPopUpFocus',\n            //     url: '../assets/components/slot/denomination-popup/max-bet/ui-svg/denominationPopUpFocus.svg',\n            //     priority: AssetPriority.HIGHEST,\n            //     type: 'svg',\n            //     config: {\n            //         mobile: { width: 134, height: 78 },\n            //         desktop: { width: 105, height: 75 },\n            //     },\n            // },\n            // {\n            //     id: 'svgDenominationPopUpSelected',\n            //     url: '../assets/components/slot/denomination-popup/max-bet/ui-svg/denominationPopUpSelected.svg',\n            //     priority: AssetPriority.HIGHEST,\n            //     type: 'svg',\n            //     config: {\n            //         mobile: { width: 134, height: 78 },\n            //         desktop: { width: 105, height: 75 },\n            //     },\n            // },\n            // {\n            //     id: 'svgDenominationPopUpHover',\n            //     url: '../assets/components/slot/denomination-popup/max-bet/ui-svg/denominationPopUpHover.svg',\n            //     priority: AssetPriority.HIGHEST,\n            //     type: 'svg',\n            //     config: {\n            //         mobile: { width: 134, height: 78 },\n            //         desktop: { width: 105, height: 75 },\n            //     },\n            // },\n        ])\n        public assets: AssetsCollection;\n\n        @DefaultValue<IMainContainerPositionMaxBet>({\n            defaults: {\n                x: 0,\n                y: 2,\n                leftHandX: 0,\n            },\n            portrait: {\n                x: 0,\n                y: 8,\n            },\n        })\n        public mainContainerPosition: DynamicPositionObject<IMainContainerPositionMaxBet> &\n            IMainContainerPositionMaxBet;\n\n        @DefaultValue<IDenominationPopUpTitleTextMaxBet>({\n            defaults: {\n                yOffset: 30,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                    fontSize: 36,\n                    fill: '#FFFFFF',\n                    align: 'center',\n                }),\n            },\n        })\n        public popUpTitle: DynamicPositionObject<IDenominationPopUpTitleTextMaxBet> & IDenominationPopUpTitleTextMaxBet;\n\n        @DefaultValue<IDenominationBackgroundPopUpPositionsMaxBet>({\n            defaults: {\n                width: 1058,\n                height: 285,\n                popupRollHeight: 94, // roll height + space between rolls\n                x: 8,\n                y: 2,\n            },\n            portrait: {\n                x: 8,\n                y: 980,\n                width: 749,\n                height: 314,\n            },\n        })\n        public popUpGraphicsContainer: DynamicPositionObject<IDenominationBackgroundPopUpPositionsMaxBet> &\n            IDenominationBackgroundPopUpPositionsMaxBet;\n\n        @DefaultValue<IBetBasedLayoutConfig>({\n            defaults: {\n                betsBase: 5,\n                dynamicLayoutThreshold: 25,\n                maxPossibleBetRowsCount: 5,\n                betsRowHeight: 94,\n                moveElementsBasedOnBets: [\n                    'balanceTextContainer',\n                    'totalBetTextContainer',\n                    'maxBetIncreaseBtn',\n                    'maxBetDecreaseBtn',\n                    'maxBetButton',\n                ],\n            },\n            portrait: {\n                maxPossibleBetRowsCount: 7,\n                moveElementsBasedOnBets: ['betMultiplierContainer', 'betContainer', 'totalBetTitle'],\n            },\n        })\n        public betBasedLayoutConfig: DynamicPositionObject<IBetBasedLayoutConfig> & IBetBasedLayoutConfig;\n\n        @DefaultValue<IDenomArrowPositionsMaxBet>({\n            defaults: {\n                x: 1188,\n                y: 526,\n                angle: 270,\n                leftHandX: 176,\n                leftHandY: 475,\n                leftHandAngle: 90,\n            },\n            portrait: {\n                x: 553,\n                y: 935,\n                angle: 0,\n            },\n            desktop: {\n                y: 544,\n            },\n        })\n        public arrowPosition: DynamicPositionObject<IDenomArrowPositionsMaxBet> & IDenomArrowPositionsMaxBet;\n\n        @DefaultValue<IBalanceAndBetTextMaxBet>({\n            defaults: {\n                x: 468,\n                y: 743,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFD200',\n                    fontSize: 33,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                valueStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 48,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                currencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 24,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n            },\n            portrait: {\n                x: 30,\n                y: 919,\n            },\n        })\n        public balanceText: DynamicPositionObject<IBalanceAndBetTextMaxBet> & IBalanceAndBetTextMaxBet;\n\n        @DefaultValue<IBalanceAndBetTextMaxBet>({\n            defaults: {\n                x: 1173,\n                y: 743,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFD200',\n                    fontSize: 33,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                valueStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 48,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                currencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 24,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n            },\n            portrait: {\n                x: 735,\n                y: 919,\n            },\n        })\n        public betText: DynamicPositionObject<IBalanceAndBetTextMaxBet> & IBalanceAndBetTextMaxBet;\n\n        @DefaultValue<IDenominationSelectedBtnPositionsMaxBet>({\n            defaults: {\n                x: 1269,\n                y: 127,\n                leftHandX: -10,\n                scale: 1,\n            },\n            portrait: {\n                x: 557,\n                y: 1226,\n            },\n        })\n        public selectedButton: DynamicPositionObject<IDenominationSelectedBtnPositionsMaxBet> &\n            IDenominationSelectedBtnPositionsMaxBet;\n\n        @DefaultValue<IMaxBetButtonPosition>({\n            defaults: {\n                x: 414,\n                y: 634,\n                textStyleNormal: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'center',\n                    fill: '#C6C5C5',\n                    lineHeight: 30,\n                    fontSize: 38,\n                    lineJoin: 'round',\n                }),\n                textStyleActive: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'center',\n                    fill: '#FFFFFF',\n                    lineHeight: 30,\n                    fontSize: 38,\n                    lineJoin: 'round',\n                }),\n            },\n            portrait: {\n                x: 260,\n                y: 948,\n            },\n        })\n        public maxBetButtonPosition: DynamicPositionObject<IMaxBetButtonPosition> & IMaxBetButtonPosition;\n\n        @DefaultValue<IBetMultiplierPanel>({\n            defaults: {\n                x: 250,\n                y: 28,\n                maxWidth: 466,\n                titleX: 0,\n                titleY: 0,\n                titleTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'center',\n                    fill: '#FFD200',\n                    fontSize: 33,\n                    lineJoin: 'round',\n                    trim: true,\n                }),\n                labelBackgroundX: 0,\n                labelBackgroundY: 65,\n                labelX: 0,\n                labelY: 0,\n                labelTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'center',\n                    fill: '#FFFFFF',\n                    fontSize: 42,\n                    lineJoin: 'round',\n                }),\n            },\n            portrait: {\n                x: 375,\n                y: 28,\n                maxWidth: 520,\n            },\n        })\n        public betMultiplierPanel: DynamicPositionObject<IBetMultiplierPanel> & IBetMultiplierPanel;\n\n        @DefaultValue<IBetPanel>({\n            defaults: {\n                x: 825,\n                y: 28,\n                maxWidth: 350,\n                titleX: 0,\n                titleY: 0,\n                titleTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'center',\n                    fill: '#FFD200',\n                    fontSize: 33,\n                    lineJoin: 'round',\n                    trim: true,\n                }),\n                decreaseBtnX: -144,\n                decreaseBtnY: 65,\n                decreaseBtnScale: 0.7857142857142857,\n                increaseBtnX: 146,\n                increaseBtnY: 65,\n                increaseBtnScale: 0.7857142857142857,\n                labelBackgroundX: 0,\n                labelBackgroundY: 65,\n                labelValueContainerX: 0,\n                labelValueContainerY: 0,\n                labelTextValueStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'center',\n                    fill: '#FFFFFF',\n                    fontSize: 42,\n                    lineJoin: 'round',\n                    trim: true,\n                    stroke: '#FFFFFF',\n                    strokeThickness: 0.27,\n                }),\n                labelTextCurrencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                    align: 'center',\n                    fill: '#FFFFFF',\n                    fontSize: 24,\n                    lineJoin: 'round',\n                    trim: true,\n                }),\n            },\n            portrait: {\n                x: 375,\n                y: 151,\n                maxWidth: 350,\n            },\n        })\n        public betPanel: DynamicPositionObject<IBetPanel> & IBetPanel;\n\n        @DefaultValue<ITotalBet>({\n            defaults: {\n                x: 537,\n                y: 137,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'center',\n                    fill: '#FFD200',\n                    fontSize: 33,\n                    lineJoin: 'round',\n                    trim: true,\n                }),\n            },\n            portrait: {\n                x: 382,\n                y: 274,\n            },\n        })\n        public totalBet: DynamicPositionObject<ITotalBet> & ITotalBet;\n\n        @DefaultValue<ITextContainer>({\n            defaults: {\n                x: 138,\n                y: 650,\n                maxWidth: 230,\n                currencyTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                    align: 'center',\n                    fill: '#C6C5C5',\n                    fontSize: 22,\n                    lineJoin: 'round',\n                    trim: true,\n                }),\n                valueTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'center',\n                    fill: '#FFFFFF',\n                    fontSize: 48,\n                    lineJoin: 'round',\n                    trim: true,\n                    stroke: '#FFFFFF',\n                    strokeThickness: 0.07,\n                }),\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'center',\n                    fill: '#FFD200',\n                    fontSize: 33,\n                    lineJoin: 'round',\n                    trim: true,\n                }),\n            },\n            portrait: {\n                x: 110,\n                y: 999,\n                maxWidth: 192,\n            },\n        })\n        public balanceContainerStyle: DynamicPositionObject<ITextContainer> & ITextContainer;\n\n        @DefaultValue<ITextContainer>({\n            defaults: {\n                x: 928,\n                y: 650,\n                maxWidth: 260,\n                currencyTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                    align: 'center',\n                    fill: '#C6C5C5',\n                    fontSize: 22,\n                    lineJoin: 'round',\n                    trim: true,\n                }),\n                valueTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'center',\n                    fill: '#FFFFFF',\n                    fontSize: 48,\n                    lineJoin: 'round',\n                    trim: true,\n                    stroke: '#FFFFFFF',\n                    strokeThickness: 0.07,\n                }),\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'center',\n                    fill: '#FFD200',\n                    fontSize: 33,\n                    lineJoin: 'round',\n                    trim: true,\n                }),\n            },\n            portrait: {\n                x: 654,\n                y: 999,\n                maxWidth: 200,\n            },\n        })\n        public totalBetContainerStyle: DynamicPositionObject<ITextContainer> & ITextContainer;\n\n        @DefaultValue<ICurvePositionObjectMaxBet>({\n            defaults: {\n                x: 146,\n                y: 977,\n            },\n        })\n        public curvePosition: DynamicPositionObject<ICurvePositionObjectMaxBet> & ICurvePositionObjectMaxBet;\n\n        @DefaultValue<IBetControlButtons>({\n            defaults: {\n                x: 687,\n                y: 693,\n                btnTextures: [\n                    'svgBetPlusBtnActive',\n                    'svgBetPlusBtnActive',\n                    'svgBetPlusBtnActive',\n                    'svgBetPlusBtnInactive',\n                ],\n            },\n        })\n        public betIncreaseBtn: DynamicPositionObject<IBetControlButtons> & IBetControlButtons;\n\n        @DefaultValue<IBetControlButtons>({\n            defaults: {\n                x: 387,\n                y: 693,\n                btnTextures: [\n                    'svgBetMinusBtnActive',\n                    'svgBetMinusBtnActive',\n                    'svgBetMinusBtnActive',\n                    'svgBetMinusBtnInactive',\n                ],\n            },\n        })\n        public betDecreaseBtn: DynamicPositionObject<IBetControlButtons> & IBetControlButtons;\n\n        @DefaultValue<IDenominationPopUpShadowMaxBet>({\n            defaults: {\n                width: 1200,\n                height: 1200,\n                x: -20,\n                y: -200,\n            },\n            portrait: {\n                x: 0,\n                y: 930,\n                width: 765,\n                height: 242,\n            },\n        })\n        public popUpShadow: DynamicPositionObject<IDenominationPopUpShadowMaxBet> & IDenominationPopUpShadowMaxBet;\n    }\n    return DenominationPopupComponentConfigurationMaxBetInternalClass;\n}\n","import { BuyBonusModes } from '@egt/buy-bonus';\nimport Core, { BaseController, ErrorTypes } from '@egt/core';\nimport { RootStore, SlotComponents, ZOrders } from '@egt/slot';\nimport { fromEvent } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { IDenominationPopupComponentConfigurationMaxBet } from '../interfaces/InterfacesMaxBet';\nimport DenominationPopupViewMaxBet from '../views/DenominationPopupViewMaxBet';\nimport { UIViewDefault } from '@egt/ui-view';\nimport DenominationPopupShadowViewMaxBet from '../views/DenominationPopupShadowViewMaxBet';\n@injectable()\nexport default class DenominationPopupControllerMaxBet extends BaseController {\n    private errorType: number | null = null;\n    constructor(\n        @inject('UIView') protected uiView: UIViewDefault,\n        @inject('DenominationPopupView') protected denominationPopup: DenominationPopupViewMaxBet,\n        @inject('DenominationPopupShadowView') protected denominationPopUpShadowView: DenominationPopupShadowViewMaxBet,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('DenominationPopupComponentConfiguration')\n        protected componentConfiguration: IDenominationPopupComponentConfigurationMaxBet,\n    ) {\n        super(denominationPopup);\n    }\n\n    public destroy(): void {\n        super.destroy();\n    }\n\n    public init(): void {\n        this.attachEventListeners();\n    }\n\n    public attachEventListeners(): void {\n        this.addSelectedButtonEventListener();\n\n        this.rootStore.subjects.DENOMINATIONS_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onDenominationsChanged.bind(this),\n        );\n\n        // this.rootStore.uiStore.BALANCE.pipe(takeUntil(this.DESTROY)).subscribe(this.onBalanceChanged.bind(this));\n\n        this.rootStore.subjects.TOGGLE_DENOMINATION_POPUP.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.toggleExtendedDenominationPopup.bind(this),\n        );\n        this.rootStore.subjects.CLOSE_ALL_POPUPS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.forceClosePopup.bind(this),\n        );\n        this.rootStore.subjects.CLOSE_DENOMINATION_POPUP.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.closePopup(null, 'chosenDenominationSound');\n        });\n\n        this.rootStore.subjects.MODAL_PRESSED.pipe(takeUntil(this.DESTROY)).subscribe(this.closePopup.bind(this));\n\n        this.rootStore.subjects.KEY_UP.pipe(takeUntil(this.DESTROY)).subscribe(this.onKeyReleased.bind(this));\n\n        this.rootStore.uiStore.STATE.pipe(takeUntil(this.DESTROY)).subscribe(this.onStateChanged.bind(this));\n\n        this.rootStore.uiStore.SELECTED_BET.pipe(takeUntil(this.DESTROY)).subscribe(this.updateBetValue.bind(this));\n        // Core.SELECTED_DENOMINATION.pipe(takeUntil(this.DESTROY)).subscribe(this.updateBetValue.bind(this));\n        this.rootStore.subjects.FACTOR_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(this.updateBetValue.bind(this));\n        Core.SHOW_ERROR.pipe(takeUntil(this.DESTROY)).subscribe(this.onErrorChanged.bind(this));\n        Core.HIDE_ERROR.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.errorType = null;\n        });\n\n        Core.UI_BLOCKER.pipe(takeUntil(this.DESTROY)).subscribe((isUiBlocked) => {\n            if (Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS)) {\n                if (this.errorType !== ErrorTypes.CONFIRMATION) {\n                    this.changeBuyBonusParameters(isUiBlocked);\n                }\n            }\n\n            this.denominationPopup.mainContainer.interactiveChildren = !isUiBlocked;\n        });\n\n        this.rootStore.uiStore.BALANCE.pipe(takeUntil(this.DESTROY)).subscribe(this.onBalanceChanged.bind(this));\n    }\n\n    protected onErrorChanged(errorData: any): void {\n        this.errorType = Number(errorData.type);\n\n        this.changeBuyBonusParameters();\n    }\n\n    protected changeBuyBonusParameters(isUiBlocked: boolean = false): void {\n        if (this.errorType === ErrorTypes.CONFIRMATION) {\n            this.rootStore.subjects.DISABLED_BUY_BONUS.next({ disabled: false, doNotChangeVisual: true });\n        }\n\n        this.rootStore.subjects.DISABLED_BUY_BONUS.next({ disabled: isUiBlocked, doNotChangeVisual: true });\n    }\n\n    protected toggleCustomButtons(visible: boolean): void {\n        this.componentConfiguration.buttonsToHide.forEach((btnName) => {\n            if (btnName === 'betButtons') {\n                this.rootStore.uiStore.SHOW_HIDE_BET_BUTTONS.next(visible);\n            } else {\n                this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                    name: btnName,\n                    actions: 'visible',\n                    values: visible,\n                });\n            }\n        });\n\n        this.componentConfiguration.mainViewComponentsToHide.forEach((mainViewComponent) => {\n            this.rootStore.subjects.SHOW_HIDE_MAIN_VIEW_COMPONENTS.next({\n                name: mainViewComponent,\n                actions: 'visible',\n                values: visible,\n            });\n        });\n    }\n\n    protected onKeyReleased(e: KeyboardEvent): void {\n        if (\n            e &&\n            this.rootStore.uiStore.SHOW_SETTINGS.value &&\n            ['ArrowDown', 'KeyC', 'KeyV', 'KeyB', 'KeyN', 'KeyM'].indexOf(e.code) > -1\n        ) {\n            return;\n        }\n        if (e === null || Core.UI_BLOCKER.value) {\n            return;\n        }\n\n        const blockKeys = ['KeyC', 'KeyV', 'KeyB', 'KeyN', 'KeyM', 'BracketLeft', 'BracketRight'];\n        const blockKeyCodes = [67, 86, 66, 78, 77, 219, 221];\n\n        if (\n            (e.code !== undefined && blockKeys.includes(e.code)) ||\n            (e.keyCode !== undefined && blockKeyCodes.includes(e.keyCode))\n        ) {\n            this.forceClosePopup();\n        }\n        if (e.code === 'KeyT' && this.denominationPopup.isOpened) {\n            this.denominationPopup.onMaxBet();\n        }\n    }\n\n    private onDenominationsChanged(): void {\n        this.denominationPopup.onDenominationsChanged();\n        this.denominationPopup.onBalanceChanged();\n        this.addSelectedButtonEventListener();\n    }\n\n    private addSelectedButtonEventListener() {\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/denomination-popup/src/egt/modes/max-bet/controllers/DenominationPopupControllerMaxBet.ts:148:9\",(this.denominationPopup.selectedBtn),\"pointerup\"]), fromEvent(this.denominationPopup.selectedBtn, 'pointerup'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.closePopup.bind(this));\n    }\n\n    // private onBalanceChanged(): void {\n    //     this.extendedDenominationPopup.updateBalance();\n    // }\n\n    // private onDenominationChanged(_dispatchedFromSettings: boolean = false, data: any): void {\n    //     if (data.playDenomChangeSound) {\n    //         Core.sounds.play('changeDenominationSound');\n    //     }\n    //     Core.SELECTED_DENOMINATION.next(this.rootStore.uiStore.denominations[data.denomination - 1]);\n    // }\n\n    // private onBetChanged(): void {\n    //     const denomIndex = this.rootStore.uiStore.denominations.indexOf(Core.SELECTED_DENOMINATION.value);\n    //     const betIndex = this.rootStore.uiStore.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value);\n    //     const button: BetSettingButton = this.extendedDenominationPopup.betButtons[denomIndex][betIndex];\n    //     this.extendedDenominationPopup.updateSelectedRoll(denomIndex, button);\n    //     button.setSelected();\n    //     this.extendedDenominationPopup.updateBetValue();\n    // }\n\n    // private onBetOptionButtonPressed(betButton: any): void {\n    //     for (let i: number = 0; i < this.extendedDenominationPopup.betButtons.length; i++) {\n    //         for (const betBtn of this.extendedDenominationPopup.betButtons[i]) {\n    //             if (betButton.currentTarget === betBtn) {\n    //                 this.extendedDenominationPopup.animateDownScaleBtn(betBtn);\n    //             }\n    //         }\n    //     }\n    // }\n\n    // private onBetOptionButtonReleased(betButton: any): void {\n    //     for (let i: number = 0; i < this.extendedDenominationPopup.betButtons.length; i++) {\n    //         for (const betBtn of this.extendedDenominationPopup.betButtons[i]) {\n    //             if (betButton.currentTarget === betBtn) {\n    //                 this.extendedDenominationPopup.animateUpScaleBtn(betBtn, i);\n    //             }\n    //         }\n    //     }\n    // }\n\n    // private onBetOptionButtonClicked(betButton: BetSettingButton, dispatchedFromPopup: boolean): void {\n    //     if (this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_RESPONSE) {\n    //         return;\n    //     }\n    //     Core.UI_BLOCKER.next(true);\n    //     for (let i: number = 0; i < this.extendedDenominationPopup.betButtons.length; i++) {\n    //         for (const betBtn of this.extendedDenominationPopup.betButtons[i]) {\n    //             if (betButton === betBtn) {\n    //                 if (!Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS)) {\n    //                     this.rootStore.subjects.DISABLED_BUY_BONUS.next(\n    //                         this.checkForMaxBet(betBtn.betLevel, betBtn.denominationLevel),\n    //                     );\n    //                 }\n\n    //                 Timers.setTimeout(() => {\n    //                     this.extendedDenominationPopup.updateSelectedRoll(i, betBtn);\n    //                     betBtn.setPressed();\n    //                 }, 10);\n\n    //                 Timers.setTimeout(() => {\n    //                     if (this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_RESPONSE) {\n    //                         return;\n    //                     }\n    //                     betBtn.setSelected();\n    //                     this.updateBet(betButton, dispatchedFromPopup);\n    //                     Core.UI_BLOCKER.next(false);\n    //                 }, 100);\n    //             }\n    //         }\n    //     }\n    //     if (!this.extendedDenominationPopup.isInteractive) {\n    //         this.extendedDenominationPopup.isInteractive = true;\n    //     }\n    // }\n\n    // private checkForMaxBet(bet: number, denomination: number): boolean {\n    //     let buyBonusValue: number =\n    //         denomination *\n    //         bet *\n    //         (this.rootStore.settings.factors[this.rootStore.settings.factors.length - 1] /\n    //             this.rootStore.uiStore.units);\n\n    //     if (this.rootStore.settings.clientSettings?.maxBetLimits || this.rootStore.settings.maxBet) {\n    //         const maxBetForBonus: number = Math.min(\n    //             this.rootStore.settings.clientSettings?.maxBetLimits\n    //                 ? this.rootStore.settings.clientSettings?.maxBetLimits[Core.PLAYER_BALANCE.value.currency]\n    //                 : Infinity,\n    //             this.rootStore.settings.maxBet ?? Infinity,\n    //         );\n    //         if (maxBetForBonus && buyBonusValue > maxBetForBonus) {\n    //             buyBonusValue = maxBetForBonus;\n    //             return true;\n    //         }\n    //     }\n    //     return false;\n    // }\n\n    private toggleExtendedDenominationPopup(): void {\n        if (this.denominationPopup.isOpened) {\n            this.closePopup();\n        } else {\n            this.openPopup();\n        }\n    }\n\n    private closePopup(_data?: any, hideSound: string = 'hideDenominationsSound'): void {\n        // this.onBetChanged();\n        if (this.denominationPopup.isOpened) {\n            this.uiView.spinButton.enabled = true;\n            if (this.uiView.ropeText) {\n                this.uiView.ropeText.visible = true;\n            }\n            this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_BTN_VISIBLE.next(true);\n            this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_OUTSIDE_BETS_VISIBLE.next(true);\n            this.rootStore.subjects.ACTIVE_COMPONENT.next(\n                this.rootStore.subjects.ACTIVE_COMPONENT.value.filter((x) => x !== SlotComponents.DENOMINATION_POPUP),\n            );\n            this.rootStore.subjects.BUY_BONUS_AND_DOUBLE_CHANCE_VISIBLE.next(ZOrders.MESSAGES_LEVEL + 3);\n            Core.sounds.play(hideSound);\n            this.toggleCustomButtons(true);\n            this.denominationPopup.close(true);\n            this.denominationPopUpShadowView.visible = false;\n            this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(false);\n            this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(false);\n        }\n    }\n\n    private forceClosePopup(): void {\n        // this.onBetChanged();\n        if (this.denominationPopup.isOpened) {\n            this.uiView.spinButton.enabled = true;\n            if (this.uiView.ropeText) {\n                this.uiView.ropeText.visible = false;\n            }\n            this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_BTN_VISIBLE.next(true);\n            this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_OUTSIDE_BETS_VISIBLE.next(true);\n            this.rootStore.subjects.ACTIVE_COMPONENT.next(\n                this.rootStore.subjects.ACTIVE_COMPONENT.value.filter((x) => x !== SlotComponents.DENOMINATION_POPUP),\n            );\n            this.rootStore.subjects.BUY_BONUS_AND_DOUBLE_CHANCE_VISIBLE.next(ZOrders.MESSAGES_LEVEL + 3);\n            this.toggleCustomButtons(true);\n            this.denominationPopup.forceClose();\n            this.denominationPopUpShadowView.visible = false;\n            this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(false);\n            this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(false);\n        }\n    }\n\n    private openPopup(animation: boolean = true): void {\n        // this.onBetChanged();\n        if (!this.denominationPopup.isOpened) {\n            const activeComponents = this.rootStore.subjects.ACTIVE_COMPONENT.value.concat([\n                SlotComponents.DENOMINATION_POPUP,\n            ]);\n            this.rootStore.subjects.ACTIVE_COMPONENT.next(activeComponents);\n            // this.uiView.spinButton.enabled = false;\n            if (this.uiView.ropeText) {\n                this.uiView.ropeText.visible = false;\n            }\n            Core.sounds.play('showDenominationsSound');\n            this.rootStore.subjects.CLOSE_ALL_POPUPS.next();\n            this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(true);\n            this.denominationPopup.open(animation);\n            this.denominationPopUpShadowView.visible = true;\n            this.toggleCustomButtons(false);\n            this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(false);\n            this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_BTN_VISIBLE.next(false);\n            this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_OUTSIDE_BETS_VISIBLE.next(false);\n            this.rootStore.subjects.BUY_BONUS_AND_DOUBLE_CHANCE_VISIBLE.next(0);\n        }\n    }\n\n    protected onStateChanged(): void {\n        if (this.denominationPopup.isOpened) {\n            this.toggleCustomButtons(false);\n        }\n    }\n\n    private updateBetValue(): void {\n        this.denominationPopup.setBetValue();\n    }\n\n    private onBalanceChanged(): void {\n        this.denominationPopup.onBalanceChanged();\n    }\n}\n","import Core from '@egt/core';\nimport { ViewContainer } from '@egt/ui-lib';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\n\nimport { IDenominationPopupComponentConfigurationMaxBet } from '../interfaces/InterfacesMaxBet';\nimport { Sprite } from 'pixi.js';\nimport { RootStore } from '@egt/slot';\n\n@injectable()\nexport default class DenominationPopupShadowViewMaxBet extends ViewContainer {\n    private shadow: Sprite;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('DenominationPopupComponentConfiguration')\n        protected componentConfiguration: IDenominationPopupComponentConfigurationMaxBet,\n    ) {\n        super();\n    }\n\n    public init(): void {\n        this.visible = false;\n        this.shadow = new Sprite(Core.assets.getTextureFromSpriteSheet('denominationResources', 'shadow.png'));\n        this.shadow.name = 'shadow';\n        this.addChild(this.shadow);\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n    }\n\n    private setOrientation(): void {\n        let offsetY = 0;\n\n        if (Core.ORIENTATION.value.isLandscape) {\n            const betRows = this.calculateNumberOfRowsInLandscape();\n\n            const config = this.componentConfiguration.betBasedLayoutConfig;\n            offsetY = (config.maxPossibleBetRowsCount - betRows) * config.betsRowHeight;\n        }\n\n        this.shadow.x = this.componentConfiguration.popUpShadow.x;\n        this.shadow.y = this.componentConfiguration.popUpShadow.y - offsetY;\n        this.shadow.width = this.componentConfiguration.popUpShadow.width;\n        this.shadow.height = this.componentConfiguration.popUpShadow.height;\n    }\n\n    private calculateNumberOfRowsInLandscape(): number {\n        const { betsBase, dynamicLayoutThreshold } = this.componentConfiguration.betBasedLayoutConfig;\n        const betsLength = this.rootStore.uiStore.bets.length;\n        let rows = this.rootStore.uiStore.denominations.length;\n\n        if (this.rootStore.uiStore.denominations.length === 1) {\n            rows = Math.ceil(betsLength / betsBase);\n\n            if (betsLength > dynamicLayoutThreshold) {\n                rows = betsBase;\n            }\n        }\n\n        return rows;\n    }\n\n    public destroy(): void {\n        super.destroy();\n    }\n}\n","import { BetCalculatorViewTurtle } from '@egt/bet-calculator';\nimport { BuyBonusModes } from '@egt/buy-bonus';\nimport Core, { MoneyFormatter, Timers } from '@egt/core';\nimport { ISlotConfiguration, RootStore, SlotComponents } from '@egt/slot';\nimport { Button, ButtonShapes, ViewContainer } from '@egt/ui-lib';\nimport { gsap } from 'gsap';\nimport { Container, Graphics, NineSlicePlane, Sprite, Text } from 'pixi.js';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { fromEvent } from 'rxjs';\nimport { IDenominationPopupComponentConfigurationMaxBet } from '../interfaces/InterfacesMaxBet';\n\n@injectable()\nexport default class DenominationPopupViewMaxBet extends ViewContainer {\n    // public readonly UPDATE_BET: BehaviorSubject<BetSettingButton | null> = new BehaviorSubject(null);\n\n    public oneDenomView: boolean = false;\n\n    public mainContainer: Container;\n    // public graphicsContainer: Sprite;\n\n    public selectedBtn: Button;\n\n    private maxBetContainer: Sprite;\n    private maxBetButton: Sprite;\n    private maxBetButtonGraphics: Graphics;\n    private maxBetButtonText: Text;\n    private maxBetDecreaseBtn: Button;\n    private maxBetIncreaseBtn: Button;\n\n    private betMultiplierContainer: Sprite;\n    private betMultiplierTitle: Text;\n    private betMultiplierLabelBackground: Sprite;\n    private betMultiplierLabel: Text;\n\n    private betContainer: Sprite;\n    private betTitle: Text;\n    private betLabelBackground: Sprite;\n    private betLabelValueContainer: Sprite;\n    private betLabelValue: Text;\n    private betLabelCurrency: Text;\n    private betDecreaseBtn: Button;\n    private betIncreaseBtn: Button;\n\n    private balanceTextContainer: Sprite;\n    private balanceCurrencyText: Text;\n    private balanceValueText: Text;\n    private balanceText: Text;\n\n    private totalBetTextContainer: Sprite;\n    private totalBetCurrencyText: Text;\n    private totalBetValueText: Text;\n    private totalBetText: Text;\n\n    private totalBetTitle: Text;\n\n    private betOptionsContainer: Sprite;\n\n    protected pressingAnimation: gsap.core.Timeline | null;\n\n    // private betBtnTextures: Map<string, Texture> = new Map();\n\n    // private rollsBackgrounds: NineSlicePlane[] = [];\n    // private rollsBackgroundsSelected: NineSlicePlane[] = [];\n\n    private popUpBackground: NineSlicePlane;\n    // private popUpShadow: NineSlicePlane;\n    // private popUpTitleText: Text;\n    // private balanceContainer: Sprite;\n    // private balanceText: Text;\n    // private balanceTextValue: Text;\n    // private balanceTextCurrency: Text;\n    // private betContainer: Sprite;\n    // private betText: Text;\n    // private betTextValue: Text;\n    // private betTextCurrency: Text;\n    // private balanceMoneyFormatter: Money;\n    // private betMoneyFormatter: Money;\n    // private wordSpacing: number = 6;\n    // private arrow: Sprite;\n    private animationTween: any;\n    private _isOpened: boolean = false;\n    private curve: Sprite;\n\n    private animationStartingPointOffset: number = 250;\n    private bounceOffset: number = 15;\n\n    private betCalculator: BetCalculatorViewTurtle;\n\n    private boundsTextOffset: number = 15;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected configuration: ISlotConfiguration,\n        @inject('DenominationPopupComponentConfiguration')\n        protected componentConfiguration: IDenominationPopupComponentConfigurationMaxBet,\n    ) {\n        super();\n    }\n\n    public init(): void {\n        this.isOpened = false;\n        // this.createBtnsTextures();\n        this.initialRender();\n\n        Core.LEFT_HAND_MODE.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n\n        this.rootStore.subjects.FACTOR_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(this.updateBetTitles.bind(this));\n\n        this.rootStore.uiStore.CURRENT_BET_LEVEL.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.updateMultiplierLabel();\n            this.setBetValue();\n        });\n        // this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.pipe(takeUntil(this.DESTROY)).subscribe(\n        //     this.changeBtnsTextures.bind(this),\n        // );\n        // for testing with one denom\n    }\n\n    private initialRender() {\n        // this.createGraphicsContainer();\n        this.createMainContainer();\n        this.createSelectedBtn();\n        this.createPopupGraphics();\n        this.close(false);\n        this.createTotalBalanceText();\n        this.createBetText();\n        this.createCurve();\n        this.createMaxBetPanel();\n\n        this.betOptionsContainer = new Sprite();\n        this.betOptionsContainer.name = 'betOptionsContainer';\n        this.mainContainer.addChild(this.betOptionsContainer);\n\n        this.crateBetMultiplierPanel();\n        this.createBetPanel();\n\n        this.totalBetTitle = new Text(\n            Core.translator.translate('TOTAL BET'),\n            this.componentConfiguration.totalBet.textStyle,\n        );\n        this.totalBetTitle.name = 'totalBetTitle';\n        this.totalBetTitle.anchor.set(0.5, 0);\n        this.betOptionsContainer.addChild(this.totalBetTitle);\n\n        this.betCalculator = Core.gameDependencyContainer.resolve('BetCalculator');\n\n        if (this.rootStore.uiStore.denominations.length === 1) {\n            this.oneDenomView = true;\n        }\n    }\n\n    // private createBtnsTextures(): void {\n    //     this.betBtnTextures.set('Normal', Core.assets.getAsset('svgDenominationPopUpNormal').texture);\n    //     this.betBtnTextures.set('Focus', Core.assets.getAsset('svgDenominationPopUpFocus').texture);\n    //     this.betBtnTextures.set('Selected', Core.assets.getAsset('svgDenominationPopUpSelected').texture);\n    //     this.betBtnTextures.set('Disabled', Core.assets.getAsset('svgDenominationPopUpNormal').texture);\n    //     this.betBtnTextures.set('Hover', Core.assets.getAsset('svgDenominationPopUpHover').texture);\n    //     this.betBtnTextures.set('Pressed', Core.assets.getAsset('svgDenominationPopUpPressed').texture);\n\n    //     if (Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS)) {\n    //         this.betBtnTextures.set('NormalSpecial', Core.assets.getAsset('svgDenominationPopUpNormal').texture);\n    //         this.betBtnTextures.set('FocusSpecial', Core.assets.getAsset('svgDenominationPopUpFocusSpecial').texture);\n    //         this.betBtnTextures.set(\n    //             'SelectedSpecial',\n    //             Core.assets.getAsset('svgDenominationPopUpSelectedSpecial').texture,\n    //         );\n    //         this.betBtnTextures.set('DisabledSpecial', Core.assets.getAsset('svgDenominationPopUpNormal').texture);\n    //         this.betBtnTextures.set('HoverSpecial', Core.assets.getAsset('svgDenominationPopUpHoverSpecial').texture);\n    //         this.betBtnTextures.set(\n    //             'PressedSpecial',\n    //             Core.assets.getAsset('svgDenominationPopUpPressedSpecial').texture,\n    //         );\n    //     }\n    // }\n\n    // private changeBtnsTextures() {\n    //     const textureType: string = this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value\n    //         ? 'Special'\n    //         : '';\n    //     for (const betButtonRow of this.betButtons) {\n    //         for (const betButton of betButtonRow) {\n    //             betButton.updateTextures(\n    //                 this.betBtnTextures.get('Normal' + textureType) as Texture,\n    //                 this.betBtnTextures.get('Focus' + textureType) as Texture,\n    //                 this.betBtnTextures.get('Selected' + textureType) as Texture,\n    //                 this.betBtnTextures.get('Disabled' + textureType) as Texture,\n    //                 this.betBtnTextures.get('Hover' + textureType) as Texture,\n    //                 this.betBtnTextures.get('Pressed' + textureType) as Texture,\n    //             );\n    //         }\n    //     }\n    // }\n\n    public destroy(): void {\n        this.killAllAnimations();\n\n        this.destroyObjects();\n        this.destroyObject(this.animationTween);\n        this.removeChildren();\n        super.destroy();\n    }\n\n    private destroyObjects() {\n        this.destroyObject(this.mainContainer);\n        // this.destroyObject(this.graphicsContainer);\n        this.destroyObject(this.selectedBtn);\n        this.destroyObject(this.popUpBackground);\n        // this.destroyObject(this.popUpShadow);\n        // this.destroyObject(this.popUpTitleText);\n        // this.destroyObject(this.balanceContainer);\n        // this.destroyObject(this.balanceText);\n        // this.destroyObject(this.balanceTextValue);\n        // this.destroyObject(this.balanceTextCurrency);\n        // this.destroyObject(this.betContainer);\n        // this.destroyObject(this.betText);\n        // this.destroyObject(this.betTextValue);\n        // this.destroyObject(this.betTextCurrency);\n        // this.destroyObject(this.balanceMoneyFormatter);\n        // this.destroyObject(this.betMoneyFormatter);\n        // this.destroyObject(this.arrow);\n    }\n\n    private createBetText(): void {\n        this.totalBetTextContainer = new Sprite();\n        this.totalBetTextContainer.anchor.set(0.5);\n        this.mainContainer.addChild(this.totalBetTextContainer);\n\n        this.totalBetCurrencyText = new Text(\n            this.rootStore.uiStore.currency,\n            this.componentConfiguration.totalBetContainerStyle.currencyTextStyle,\n        );\n        this.totalBetCurrencyText.anchor.set(0.5, 0);\n        this.totalBetTextContainer.addChild(this.totalBetCurrencyText);\n\n        this.totalBetValueText = new Text('', this.componentConfiguration.totalBetContainerStyle.valueTextStyle);\n        this.totalBetValueText.anchor.set(0.5, 0);\n        this.totalBetValueText.y = 23;\n        this.totalBetTextContainer.addChild(this.totalBetValueText);\n\n        this.totalBetText = new Text(\n            Core.translator.translate('TOTAL BET'),\n            this.componentConfiguration.totalBetContainerStyle.textStyle,\n        );\n        this.totalBetText.anchor.set(0.5, 0);\n        this.totalBetText.y = 63;\n        this.totalBetTextContainer.addChild(this.totalBetText);\n        this.fitBalanceTextTotalBetTextInBounds();\n    }\n\n    private createTotalBalanceText(): void {\n        this.balanceTextContainer = new Sprite();\n        this.balanceTextContainer.anchor.set(0.5, 1);\n        this.mainContainer.addChild(this.balanceTextContainer);\n\n        this.balanceCurrencyText = new Text(\n            this.rootStore.uiStore.currency,\n            this.componentConfiguration.balanceContainerStyle.currencyTextStyle,\n        );\n        this.balanceCurrencyText.anchor.set(0.5, 0);\n        this.balanceTextContainer.addChild(this.balanceCurrencyText);\n\n        this.balanceValueText = new Text('', this.componentConfiguration.balanceContainerStyle.valueTextStyle);\n        this.balanceValueText.anchor.set(0.5, 0);\n        this.balanceValueText.y = 23;\n        this.balanceTextContainer.addChild(this.balanceValueText);\n\n        this.balanceText = new Text(\n            Core.translator.translate('BALANCE'),\n            this.componentConfiguration.balanceContainerStyle.textStyle,\n        );\n        this.balanceText.anchor.set(0.5, 0);\n        this.balanceText.y = 63;\n        this.balanceTextContainer.addChild(this.balanceText);\n        this.fitBalanceTextTotalBetTextInBounds();\n    }\n\n    private fitBalanceTextTotalBetTextInBounds(): void {\n        if (!this.balanceText || !this.totalBetText) return;\n        this.balanceText.scale.set(1);\n        this.totalBetText.scale.set(1);\n\n        const maxBalanceTextWidth = this.componentConfiguration.balanceContainerStyle.maxWidth;\n        const maxTotalBetTextWidth = this.componentConfiguration.totalBetContainerStyle.maxWidth;\n\n        const scaleBalanceText = maxBalanceTextWidth / this.balanceText.width;\n        const scaleTotalBetText = maxTotalBetTextWidth / this.totalBetText.width;\n\n        const scale = Math.min(1, scaleBalanceText, scaleTotalBetText);\n\n        if (this.balanceText.scale.x !== scale) {\n            this.balanceText.scale.set(scale);\n        }\n        this.totalBetText.scale.set(scale);\n    }\n\n    public get isOpened(): boolean {\n        return this._isOpened;\n    }\n\n    public set isOpened(value: boolean) {\n        this._isOpened = value;\n    }\n\n    public open(animation: boolean): void {\n        this.setLastBetButtonsState();\n        this.steFirsBetButtonsState();\n        this.setOrientation();\n        // this.updateBetValue();\n        this.mainContainer.addChild(this.betCalculator);\n        this.betCalculator.pivot.set(0, 0);\n\n        this.isOpened = true;\n        this.killAllAnimations();\n        this.betCalculator.changeBtnsTextures.bind(this);\n        this.betCalculator.resetCalculatorPopUp();\n        this.updateMultiplierLabel();\n\n        // this.popUpTitleText.text = Core.translator.translate(\n        //     this.rootStore.subjects.EXTENDED_DENOMINATION_POP_UP_TITLE.value,\n        // );\n\n        this.mainContainer.alpha = 0;\n        this.mainContainer.y = this.componentConfiguration.mainContainerPosition.y + this.animationStartingPointOffset;\n        this.mainContainer.visible = true;\n\n        // const arrowY =\n        //     Core.LEFT_HAND_MODE.value && Core.ORIENTATION.value.isLandscape\n        //         ? this.componentConfiguration.arrowPosition.leftHandY\n        //         : this.componentConfiguration.arrowPosition.y;\n        // this.arrow.alpha = 0;\n        // this.arrow.y = arrowY + this.startingPoint;\n        // this.arrow.visible = true;\n\n        this.selectedBtn.visible = true;\n        this.selectedBtn.alpha = 1;\n\n        if (animation) {\n            this.animationTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/denomination-popup/src/egt/modes/max-bet/views/DenominationPopupViewMaxBet.ts:340:35\",null]), gsap.timeline());\n\n            const animateAlpha = (alpha: number, duration: number) => ({\n                alpha,\n                duration,\n            });\n            const animateBounce = (y: number, duration: number, ease: string) => ({\n                y,\n                duration,\n                ease,\n            });\n\n            const onComplete = () => {\n                // this.isInteractive = false;\n                // this.graphicsContainer.alpha = 1;\n                // this.graphicsContainer.visible = true;\n            };\n\n            this.animationTween\n                .to(this.mainContainer, animateAlpha(1, 0.3), 0)\n                // .to(this.arrow, animateAlpha(1, 0.3), '<')\n                .to(\n                    this.mainContainer,\n                    animateBounce(\n                        this.componentConfiguration.mainContainerPosition.y - this.bounceOffset,\n                        0.25,\n                        'power1.out',\n                    ),\n                    0,\n                )\n                // .to(this.arrow, animateBounce(arrowY - this.bounceOffset, 0.25, 'power1.out'), '<')\n                .to(\n                    this.mainContainer,\n                    {\n                        ...animateBounce(this.componentConfiguration.mainContainerPosition.y, 0.2, 'power1.in'),\n                        onComplete,\n                    },\n                    0.25,\n                );\n            // .to(\n            //     this.arrow,\n            //     {\n            //         ...animateBounce(arrowY, 0.2, 'power1.in'),\n            //         onComplete,\n            //     },\n            //     '<',\n            // );\n        } else {\n            this.mainContainer.alpha = 1;\n            // this.arrow.alpha = 1;\n            // this.isInteractive = false;\n            // this.graphicsContainer.alpha = 1;\n            // this.graphicsContainer.visible = true;\n        }\n    }\n\n    public close(animation: boolean): void {\n        if (this.betCalculator) {\n            this.mainContainer.removeChild(this.betCalculator);\n        }\n\n        this.isOpened = false;\n        this.killAllAnimations();\n        // this.isInteractive = true;\n        // this.graphicsContainer.alpha = 0;\n        // this.graphicsContainer.visible = false;\n        this.mainContainer.alpha = 1;\n        this.mainContainer.visible = true;\n        // this.arrow.alpha = 1;\n        // this.arrow.visible = true;\n        this.selectedBtn.alpha = 0;\n        this.selectedBtn.visible = false;\n        // const arrowY =\n        //     Core.LEFT_HAND_MODE.value && Core.ORIENTATION.value.isLandscape\n        //         ? this.componentConfiguration.arrowPosition.leftHandY\n        //         : this.componentConfiguration.arrowPosition.y;\n\n        if (animation) {\n            this.animationTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/denomination-popup/src/egt/modes/max-bet/views/DenominationPopupViewMaxBet.ts:418:35\",null]), gsap.timeline());\n\n            const animateBounce = (alpha: number, y: number, duration: number) => ({\n                alpha,\n                y,\n                duration,\n            });\n\n            const onComplete = () => {\n                this.noVisibility();\n            };\n\n            this.animationTween.to(this.mainContainer, {\n                ...animateBounce(\n                    0,\n                    this.componentConfiguration.mainContainerPosition.y + this.animationStartingPointOffset,\n                    0.3,\n                ),\n                onComplete,\n            });\n            // .to(this.arrow, { ...animateBounce(0, arrowY + this.startingPoint, 0.3), onComplete }, '<');\n        } else {\n            this.noVisibility();\n        }\n    }\n\n    public forceClose(): void {\n        this.isOpened = false;\n        this.killAllAnimations();\n        this.noVisibility();\n        // this.isInteractive = true;\n        // this.graphicsContainer.alpha = 0;\n        // this.graphicsContainer.visible = false;\n        this.selectedBtn.alpha = 0;\n        this.selectedBtn.visible = false;\n    }\n\n    public onDenominationsChanged() {\n        const wasOpen = this.isOpened;\n        this.removeChildren();\n\n        this.initialRender();\n\n        if (wasOpen) {\n            this.open(false);\n        } else {\n            this.close(false);\n        }\n        this.setOrientation();\n    }\n\n    // public get isInteractive(): boolean {\n    //     return this.graphicsContainer.interactive;\n    // }\n\n    // public set isInteractive(isContainerInteractive: boolean) {\n    //     this.graphicsContainer.interactive = isContainerInteractive;\n    // }\n\n    public noVisibility() {\n        this.mainContainer.alpha = 0;\n        this.mainContainer.visible = false;\n        // this.arrow.alpha = 0;\n        // this.arrow.visible = false;\n    }\n\n    // public updateSelectedRoll(_betButton: BetSettingButton): void {\n    //     this.setOrientation();\n    // }\n\n    // public updateBetValue(): void {\n    // this.betMoneyFormatter.amountMoney = this.getTotalBet();\n    // this.betTextValue.text = this.betMoneyFormatter.stringMoney;\n    // this.positionBetBalance();\n    // this.fitBetBalanceInBounds();\n    // }\n\n    // public updateBalance(): void {\n    // this.balanceMoneyFormatter.amountMoney = this.rootStore.uiStore.BALANCE.value;\n    // this.balanceTextValue.text = this.balanceMoneyFormatter.stringMoney;\n    // this.positionBetBalance();\n    // this.fitBetBalanceInBounds();\n    // }\n\n    // public fitBetBalanceInBounds(): void {\n    // const maxWidth = this.betContainer.x - this.balanceContainer.x;\n    // const balanceWidth =\n    //     this.balanceText.width +\n    //     this.balanceTextValue.width +\n    //     this.balanceTextCurrency.width +\n    //     2 * this.wordSpacing;\n    // const betWidth =\n    //     this.betText.width + this.betTextValue.width + this.betTextCurrency.width + 2 * this.wordSpacing;\n    // const actualWidth = balanceWidth + this.wordSpacing * 2 + betWidth;\n    // this.betContainer.scale.set(1);\n    // this.balanceContainer.scale.set(1);\n    // if (actualWidth > maxWidth) {\n    //     const scaleFactor = maxWidth / actualWidth - 0.05;\n    //     this.betContainer.scale.set(scaleFactor);\n    //     this.balanceContainer.scale.set(scaleFactor);\n    //     this.positionBetBalance();\n    // }\n    // }\n\n    // public positionBetBalance(): void {\n    //     this.balanceTextCurrency.x = this.balanceTextValue.x + this.balanceTextValue.width + this.wordSpacing;\n    //     this.betTextCurrency.x = this.betTextValue.x + this.betTextValue.width + this.wordSpacing;\n    //     this.betContainer.pivot.set(\n    //         this.betText.width + this.betTextValue.width + this.betTextCurrency.width + 2 * this.wordSpacing,\n    //         0,\n    //     );\n    // }\n\n    // private createBalanceText(): void {\n    //     this.balanceMoneyFormatter = new Money(this.rootStore.uiStore.BALANCE.value);\n    //     this.balanceContainer = new Sprite();\n    //     this.mainContainer.addChild(this.balanceContainer);\n\n    //     this.balanceText = new Text(\n    //         Core.translator.translate('BALANCE') + ':',\n    //         this.componentConfiguration.balanceText.textStyle,\n    //     );\n    //     this.balanceText.resolution = 2;\n    //     this.balanceContainer.addChild(this.balanceText);\n    //     this.balanceText.pivot.set(0, this.balanceText.height);\n\n    //     this.balanceTextValue = new Text(\n    //         this.balanceMoneyFormatter.stringMoney,\n    //         this.componentConfiguration.balanceText.valueStyle,\n    //     );\n    //     this.balanceTextValue.pivot.set(0, this.balanceTextValue.height);\n    //     this.balanceTextValue.resolution = 2;\n    //     this.balanceContainer.addChild(this.balanceTextValue);\n    //     this.balanceTextValue.x = this.balanceText.x + this.balanceText.width + this.wordSpacing;\n\n    //     this.balanceTextCurrency = new Text(\n    //         this.rootStore.settings.currency,\n    //         this.componentConfiguration.balanceText.currencyStyle,\n    //     );\n    //     this.balanceTextCurrency.pivot.set(0, this.balanceTextCurrency.height);\n    //     this.balanceTextCurrency.resolution = 2;\n    //     this.balanceContainer.addChild(this.balanceTextCurrency);\n    //     this.balanceTextCurrency.x = this.balanceTextValue.x + this.balanceTextValue.width + this.wordSpacing;\n    // }\n\n    private createCurve(): void {\n        this.curve = new Sprite(Core.assets.getTextureFromSpriteSheet('denominationResources', 'curve.png'));\n        this.curve.interactive = true;\n        this.curve.name = 'curve';\n        this.mainContainer.addChild(this.curve);\n    }\n\n    // private createBetText(): void {\n    //     this.betMoneyFormatter = new Money(this.getTotalBet());\n    //     this.betContainer = new Sprite();\n    //     this.mainContainer.addChild(this.betContainer);\n\n    //     this.betText = new Text(Core.translator.translate('BET') + ':', this.componentConfiguration.betText.textStyle);\n    //     this.betText.pivot.set(0, this.betText.height);\n    //     this.betText.resolution = 2;\n    //     this.betContainer.addChild(this.betText);\n\n    //     this.betTextValue = new Text(\n    //         this.betMoneyFormatter.stringMoney,\n    //         this.componentConfiguration.betText.valueStyle,\n    //     );\n    //     this.betTextValue.pivot.set(0, this.betTextValue.height);\n    //     this.betTextValue.resolution = 2;\n    //     this.betContainer.addChild(this.betTextValue);\n\n    //     this.betTextCurrency = new Text(\n    //         this.rootStore.settings.currency,\n    //         this.componentConfiguration.betText.currencyStyle,\n    //     );\n    //     this.betTextCurrency.pivot.set(0, this.betTextCurrency.height);\n    //     this.betTextCurrency.resolution = 2;\n    //     this.betContainer.addChild(this.betTextCurrency);\n\n    //     this.betTextValue.x = this.betText.x + this.betText.width + this.wordSpacing;\n    //     this.betTextCurrency.x = this.betTextValue.x + this.betTextValue.width + this.wordSpacing;\n\n    //     this.betContainer.pivot.set(\n    //         this.betText.width + this.betTextValue.width + this.betTextCurrency.width + 2 * this.wordSpacing,\n    //         0,\n    //     );\n    // }\n\n    // private createDenominationPopUp(): void {\n    // this.createPopupGraphics();\n    // this.createPopUpTexts();\n    // this.createArrow();\n\n    //         for (let i: number = 0; i < this.rootStore.uiStore.denominations.length; i++) {\n    //             const rollBackground = new NineSlicePlane(\n    //                 Core.assets.getTextureFromSpriteSheet('denominationResources', 'popupFill.png'),\n    //                 25,\n    //                 25,\n    //                 25,\n    //                 25,\n    //             );\n    //             this.mainContainer.addChild(rollBackground);\n    //             this.rollsBackgrounds.push(rollBackground);\n\n    //             const rollsBackgroundsSelected = new NineSlicePlane(\n    //                 Core.assets.getTextureFromSpriteSheet('denominationResources', 'popupFillSelected.png'),\n    //                 25,\n    //                 25,\n    //                 25,\n    //                 25,\n    //             );\n    //             this.mainContainer.addChild(rollsBackgroundsSelected);\n    //             this.rollsBackgroundsSelected.push(rollsBackgroundsSelected);\n\n    //             let selectedRoll: boolean = false;\n\n    //             if (Core.SELECTED_DENOMINATION.value === this.rootStore.uiStore.denominations[i]) {\n    //                 selectedRoll = true;\n    //                 rollBackground.visible = false;\n    //                 rollsBackgroundsSelected.visible = true;\n    //             } else {\n    //                 rollBackground.visible = true;\n    //                 rollsBackgroundsSelected.visible = false;\n    //             }\n\n    //             if (this.componentConfiguration.additionalText.hasAdditionalText) {\n    //                 this.createAdditionalText(i, selectedRoll);\n    //             }\n    //             this.betButtons.push([]);\n    //             for (let t: number = 0; t < this.rootStore.uiStore.bets.length; t++) {\n    //                 let selectedButton: boolean = false;\n    //                 if (this.rootStore.uiStore.SELECTED_BET.value === this.rootStore.uiStore.bets[t] && selectedRoll) {\n    //                     selectedButton = true;\n    //                 }\n    //                 this.createBetButtons(i, t, selectedRoll, selectedButton);\n    //             }\n    //         }\n    //         this.mainContainer.addChild(this.graphicsContainer);\n    //     }\n\n    //     private createBetButtons(\n    //         denominationIndex: number,\n    //         betIndex: number,\n    //         selectedRoll: boolean,\n    //         selectedButton: boolean,\n    //     ): void {\n    //         const textureType: string = this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value\n    //             ? 'Special'\n    //             : '';\n\n    //         const btnTextures: BetSettingsButtonTextures = new BetSettingsButtonTextures(\n    //             this.betBtnTextures.get('Normal' + textureType) as Texture,\n    //             this.betBtnTextures.get('Focus' + textureType) as Texture,\n    //             this.betBtnTextures.get('Selected' + textureType) as Texture,\n    //             this.betBtnTextures.get('Disabled' + textureType) as Texture,\n    //             this.betBtnTextures.get('Hover' + textureType) as Texture,\n    //             this.betBtnTextures.get('Pressed' + textureType) as Texture,\n    //         );\n\n    //         const factor = this.componentConfiguration.additionalText.lines\n    //             ? this.rootStore.settings.numberOfLinesPerDenomination![denominationIndex][1]\n    //             : this.rootStore.settings.factor;\n\n    //         const maxBetLimits =\n    //             this.rootStore.settings.settings.settings?.clientSettings?.maxBetLimits &&\n    //             Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS)\n    //                 ? this.rootStore.settings.settings.settings.clientSettings.maxBetLimits[\n    //                       this.rootStore.settings.currency\n    //                   ]\n    //                 : undefined;\n\n    //         const button = new BetSettingButton(\n    //             this.rootStore.uiStore.denominations[denominationIndex],\n    //             this.rootStore.uiStore.bets[betIndex],\n    //             factor,\n    //             btnTextures,\n    //             this.componentConfiguration.popUpButtonsText.valueOffset.valueOf(),\n    //             this.componentConfiguration.popUpButtonsText.currencyOffset.valueOf(),\n    //             Object.assign({}, this.componentConfiguration.popUpButtonsText.normalTextStyle),\n    //             Object.assign({}, this.componentConfiguration.popUpButtonsText.currencyNormalTextStyle),\n    //             Object.assign({}, this.componentConfiguration.popUpButtonsText.currencyHilightedTextStyle),\n    //             Object.assign({}, this.componentConfiguration.popUpButtonsText.hilightedTextStyle),\n    //             this.componentConfiguration.popUpButtonsText.width.valueOf(),\n    //             this.componentConfiguration.popUpButtonsText.height.valueOf(),\n    //             this.createJpStamp(betIndex),\n    //             this.componentConfiguration.jackpotStampConfig?.offset,\n    //             this.rootStore.settings.maxBet,\n    //             maxBetLimits,\n    //         );\n\n    //         if (selectedRoll) {\n    //             button.setHilighted();\n\n    // this.mainContainer.addChild(this.graphicsContainer);\n    // }\n\n    private createPopupGraphics(): void {\n        // this.popUpShadow = new NineSlicePlane(\n        //     Core.assets.getTextureFromSpriteSheet('denominationResources', 'shadow.png'),\n        //     60,\n        //     60,\n        //     60,\n        //     60,\n        // );\n        // this.mainContainer.addChild(this.popUpShadow);\n\n        this.popUpBackground = new NineSlicePlane(\n            Core.assets.getTextureFromSpriteSheet('denominationResources', 'popup.png'),\n            60,\n            60,\n            60,\n            60,\n        );\n        this.popUpBackground.interactive = true;\n        this.mainContainer.addChild(this.popUpBackground);\n    }\n\n    // private createPopUpTexts(): void {\n    //     this.popUpTitleText = new Text('BET LEVELS', this.componentConfiguration.popUpTitle.textStyle);\n    //     this.popUpTitleText.resolution = 2;\n    //     this.popUpTitleText.anchor.set(0.5);\n    //     this.mainContainer.addChild(this.popUpTitleText);\n    // }\n\n    // private createArrow(): void {\n    //     this.arrow = new Sprite(Core.assets.getTextureFromSpriteSheet('denominationResources', 'arrow.png'));\n    //     this.addChild(this.arrow);\n    // }\n\n    private killAllAnimations(): void {\n        if (this.animationTween) {\n            this.animationTween.kill();\n            this.animationTween = null;\n        }\n    }\n\n    private setOrientation(): void {\n        this.killAllAnimations();\n        if (this.isOpened) {\n            this.mainContainer.alpha = 1;\n        } else {\n            this.noVisibility();\n        }\n\n        const betRows = this.calculateNumberOfRows();\n\n        this.mainContainer.x = this.componentConfiguration.mainContainerPosition.x;\n        this.mainContainer.y = this.componentConfiguration.mainContainerPosition.y;\n\n        this.popUpBackground.x = this.componentConfiguration.popUpGraphicsContainer.x;\n        this.popUpBackground.y = this.componentConfiguration.popUpGraphicsContainer.y;\n        this.popUpBackground.width = this.componentConfiguration.popUpGraphicsContainer.width;\n        this.popUpBackground.height =\n            this.componentConfiguration.popUpGraphicsContainer.height +\n            betRows * this.componentConfiguration.betBasedLayoutConfig.betsRowHeight;\n        this.popUpBackground.pivot.set(0, Core.ORIENTATION.value.isPortrait ? this.popUpBackground.height : 0);\n\n        this.balanceTextContainer.x = this.componentConfiguration.balanceContainerStyle.x;\n        this.balanceTextContainer.y = this.componentConfiguration.balanceContainerStyle.y;\n\n        this.totalBetTextContainer.x = this.componentConfiguration.totalBetContainerStyle.x;\n        this.totalBetTextContainer.y = this.componentConfiguration.totalBetContainerStyle.y;\n\n        this.curve.visible = Core.ORIENTATION.value.isPortrait;\n        this.curve.x = this.componentConfiguration.curvePosition.x;\n        this.curve.y = this.componentConfiguration.curvePosition.y;\n\n        this.maxBetIncreaseBtn.visible = Core.ORIENTATION.value.isLandscape;\n        this.maxBetIncreaseBtn.x = this.componentConfiguration.betIncreaseBtn.x;\n        this.maxBetIncreaseBtn.y = this.componentConfiguration.betIncreaseBtn.y;\n\n        this.maxBetDecreaseBtn.visible = Core.ORIENTATION.value.isLandscape;\n        this.maxBetDecreaseBtn.x = this.componentConfiguration.betDecreaseBtn.x;\n        this.maxBetDecreaseBtn.y = this.componentConfiguration.betDecreaseBtn.y;\n\n        this.selectedBtn.x = this.componentConfiguration.selectedButton.x;\n        this.selectedBtn.y = this.componentConfiguration.selectedButton.y;\n        this.selectedBtn.scale.set(this.componentConfiguration.selectedButton.scale);\n\n        this.maxBetButton.x = this.componentConfiguration.maxBetButtonPosition.x + this.maxBetButton.width / 2;\n        this.maxBetButton.y = this.componentConfiguration.maxBetButtonPosition.y + this.maxBetButton.height / 2;\n\n        this.betMultiplierContainer.x = this.componentConfiguration.betMultiplierPanel.x;\n        this.betMultiplierContainer.y = this.componentConfiguration.betMultiplierPanel.y;\n        this.betContainer.x = this.componentConfiguration.betPanel.x;\n        this.betContainer.y = this.componentConfiguration.betPanel.y;\n\n        this.totalBetTitle.x = this.componentConfiguration.totalBet.x;\n        this.totalBetTitle.y = this.componentConfiguration.totalBet.y;\n\n        this.setLeftHand();\n        this.syncBalanceAndTotalBetTextScales();\n        this.fitBetMultiplierTitleBetTitleInBounds();\n        this.fitBalanceTextTotalBetTextInBounds();\n        this.applyBetLabelValueScale();\n        this.applyOffsetYBasedOnNumberOfBets(\n            this.componentConfiguration.betBasedLayoutConfig.moveElementsBasedOnBets,\n            betRows,\n        );\n    }\n\n    private applyOffsetYBasedOnNumberOfBets(elementsToMove: string[], betRows: number): void {\n        const config = this.componentConfiguration.betBasedLayoutConfig;\n        const direction = Core.ORIENTATION.value.isPortrait ? 1 : -1;\n        const offsetY = direction * (config.maxPossibleBetRowsCount - betRows) * config.betsRowHeight;\n\n        for (const element of elementsToMove) {\n            this[element].y += offsetY;\n        }\n    }\n\n    private calculateNumberOfRows(): number {\n        const { betsBase, dynamicLayoutThreshold } = this.componentConfiguration.betBasedLayoutConfig;\n        const bets = this.rootStore.uiStore.bets.length;\n        const denominations = this.rootStore.uiStore.denominations.length;\n        const numberOfAllBets = bets * denominations;\n        let rows = this.rootStore.uiStore.denominations.length;\n\n        if (this.oneDenomView) {\n            rows = Math.ceil(numberOfAllBets / betsBase);\n        }\n\n        if (!Core.ORIENTATION.value.isPortrait && numberOfAllBets > dynamicLayoutThreshold) {\n            rows = betsBase;\n        }\n\n        return rows;\n    }\n\n    private setLeftHand(): void {\n        if (Core.LEFT_HAND_MODE.value && Core.ORIENTATION.value.isLandscape) {\n            this.mainContainer.x = this.componentConfiguration.mainContainerPosition.leftHandX;\n\n            // this.arrow.x = this.componentConfiguration.arrowPosition.leftHandX;\n            // this.arrow.y = this.componentConfiguration.arrowPosition.leftHandY;\n            // this.arrow.angle = this.componentConfiguration.arrowPosition.leftHandAngle;\n\n            this.selectedBtn.x = this.componentConfiguration.selectedButton.leftHandX;\n        }\n    }\n\n    // private getTotalBet(): number {\n    //     const factor = this.rootStore.settings.factor\n    //         ? this.rootStore.settings.factor\n    //         : this.rootStore.uiStore.LINES.value;\n    //     return Core.SELECTED_DENOMINATION.value * this.rootStore.uiStore.SELECTED_BET.value * factor;\n    // }\n\n    private createSelectedBtn(): void {\n        this.selectedBtn = new Button(\n            [Core.assets.getAsset('svgDenominationSelected').texture],\n            undefined,\n            ButtonShapes.Rectangle,\n        );\n        this.selectedBtn.pivot.set(this.selectedBtn.width / 2, this.selectedBtn.height / 2);\n        this.selectedBtn.interactive = true;\n        this.addChild(this.selectedBtn);\n    }\n\n    private createMaxBetPanel(): void {\n        this.maxBetContainer = new Sprite();\n        this.maxBetContainer.anchor.set(0.5);\n        this.maxBetContainer.name = 'maxBetContainer';\n        this.mainContainer.addChild(this.maxBetContainer);\n\n        this.maxBetDecreaseBtn = new Button(\n            Core.assets.getAssets(this.componentConfiguration.betDecreaseBtn.btnTextures),\n            undefined,\n            ButtonShapes.Circle,\n        );\n        this.maxBetDecreaseBtn.name = 'maxBetDecreaseBtn';\n        this.maxBetDecreaseBtn.pivot.set(this.maxBetDecreaseBtn.width / 2, this.maxBetDecreaseBtn.height / 2);\n        this.maxBetContainer.addChild(this.maxBetDecreaseBtn);\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/denomination-popup/src/egt/modes/max-bet/views/DenominationPopupViewMaxBet.ts:891:9\",(this.maxBetDecreaseBtn),\"pointertap\"]), fromEvent(this.maxBetDecreaseBtn, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.decreaseBet.bind(this));\n\n        this.maxBetIncreaseBtn = new Button(\n            Core.assets.getAssets(this.componentConfiguration.betIncreaseBtn.btnTextures),\n            undefined,\n            ButtonShapes.Circle,\n        );\n        this.maxBetIncreaseBtn.name = 'maxBetIncreaseBtn';\n        this.maxBetIncreaseBtn.pivot.set(this.maxBetIncreaseBtn.width / 2, this.maxBetIncreaseBtn.height / 2);\n        this.maxBetContainer.addChild(this.maxBetIncreaseBtn);\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/denomination-popup/src/egt/modes/max-bet/views/DenominationPopupViewMaxBet.ts:904:9\",(this.maxBetIncreaseBtn),\"pointertap\"]), fromEvent(this.maxBetIncreaseBtn, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.increaseBet.bind(this));\n\n        this.maxBetButton = new Sprite();\n        this.maxBetButton.name = 'maxBetButton';\n        this.maxBetButton.anchor.set(0.5);\n        this.maxBetContainer.addChild(this.maxBetButton);\n\n        this.setMaxBetButtonGraphics(true);\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/denomination-popup/src/egt/modes/max-bet/views/DenominationPopupViewMaxBet.ts:915:9\",(this.maxBetButtonGraphics),\"pointertap\"]), fromEvent(this.maxBetButtonGraphics, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onMaxBet.bind(this));\n\n        this.maxBetButtonText = new Text(\n            Core.translator.translate('MAX BET'),\n            this.componentConfiguration.maxBetButtonPosition.textStyleNormal,\n        );\n        this.maxBetButtonText.anchor.set(0.5);\n        this.maxBetButtonText.resolution = 2;\n        this.maxBetButton.addChild(this.maxBetButtonText);\n        this.fitMaxBetTextInBounds();\n    }\n\n    public onMaxBet(): void {\n        const targetBet = this.getMaxAllowedBet();\n        const maxDenomination = this.rootStore.uiStore.denominations[this.rootStore.uiStore.denominations.length - 1];\n        Core.UI_BLOCKER.next(true);\n\n        if (\n            targetBet === this.rootStore.uiStore.SELECTED_BET.value &&\n            Core.SELECTED_DENOMINATION.value === maxDenomination\n        ) {\n            return;\n        }\n\n        this.rootStore.uiStore.SELECTED_BET.next(targetBet);\n        Core.SELECTED_DENOMINATION.next(maxDenomination);\n        this.rootStore.uiStore.CURRENT_BET_LEVEL.next({\n            betLevel: this.rootStore.uiStore.SELECTED_BET.value,\n            denomLevel: Core.SELECTED_DENOMINATION.value,\n        });\n\n        this.rootStore.subjects.CHANGE_SELECTED_BET_BTN_EXTERNALLY.next({\n            betVal: this.rootStore.uiStore.SELECTED_BET.value,\n            changedFromPopUp: true,\n        });\n\n        Timers.setTimeout(() => {\n            Core.UI_BLOCKER.next(false);\n            this.rootStore.subjects.CLOSE_DENOMINATION_POPUP.next();\n        }, 300);\n\n        Core.sounds.play('changeBetSound');\n    }\n\n    private isNextBetOverMaxLimit(): boolean {\n        const bets = this.rootStore.uiStore.bets;\n        const currentBet = this.rootStore.uiStore.SELECTED_BET.value;\n\n        const currentIndex = bets.indexOf(currentBet);\n        if (currentIndex < 0) return false;\n\n        const nextIndex = currentIndex + 1;\n        if (nextIndex >= bets.length) return false;\n\n        const nextBet = bets[nextIndex];\n        const denom = Core.SELECTED_DENOMINATION.value;\n        const factor = this.rootStore.settings.factor;\n        const nextTotalBet = (nextBet * denom * factor) / 100;\n        const betLimit = this.getBetLimit();\n\n        if (betLimit === null) return false;\n\n        return nextTotalBet > betLimit;\n    }\n\n    private getBetLimit(): number | null {\n        const jurisdictionalLimit: number | null = this.rootStore.settings.maxBet ?? null;\n\n        const buyBonusLimit: number | null =\n            this.rootStore.settings.settings.settings?.clientSettings?.maxBetLimits &&\n            Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS)\n                ? (this.rootStore.settings.settings.settings.clientSettings.maxBetLimits[\n                      this.rootStore.settings.currency\n                  ] ?? null)\n                : null;\n\n        const buyBonusActivated = this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value === true;\n        const effectiveBuyBonusLimit = buyBonusActivated ? buyBonusLimit : null;\n\n        if (jurisdictionalLimit != null && effectiveBuyBonusLimit != null) {\n            return Math.min(jurisdictionalLimit, effectiveBuyBonusLimit);\n        }\n        if (jurisdictionalLimit != null) return jurisdictionalLimit;\n        if (effectiveBuyBonusLimit != null) return effectiveBuyBonusLimit;\n\n        return null;\n    }\n\n    private getMaxAllowedBet(): number {\n        const bets = this.rootStore.settings.bets;\n        const denom = Core.SELECTED_DENOMINATION.value;\n        const factor = this.rootStore.settings.factor;\n\n        const betLimit = this.getBetLimit();\n\n        if (betLimit === null) {\n            return bets[bets.length - 1];\n        }\n\n        let maxAllowed = bets[0];\n\n        for (let i = 0; i < bets.length; i++) {\n            const total = (bets[i] * denom * factor) / 100;\n            if (total <= betLimit) {\n                maxAllowed = bets[i];\n            } else {\n                break;\n            }\n        }\n        return maxAllowed;\n    }\n\n    private steFirsBetButtonsState(): void {\n        const firstDenom: boolean =\n            this.rootStore.settings.denominations.indexOf(Core.SELECTED_DENOMINATION.value) === 0;\n        const firstBet: boolean = this.rootStore.settings.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value) === 0;\n        const isFirstBet: boolean = firstDenom && firstBet;\n\n        this.betDecreaseBtn.enabled = !isFirstBet;\n        this.maxBetDecreaseBtn.enabled = !isFirstBet;\n    }\n\n    private setLastBetButtonsState(): void {\n        const lastDenom: boolean =\n            this.rootStore.settings.denominations.indexOf(Core.SELECTED_DENOMINATION.value) ===\n            this.rootStore.settings.denominations.length - 1;\n\n        const lastBet: boolean =\n            this.rootStore.settings.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value) ===\n            this.rootStore.settings.bets.length - 1;\n\n        const isLastBet: boolean = lastDenom && lastBet;\n        const reachedMaxBet: boolean = isLastBet || this.isNextBetOverMaxLimit();\n\n        this.maxBetButton.texture = Core.assets.getAsset(\n            reachedMaxBet ? 'maxBetButtonActive' : 'maxBetButtonNormal',\n        ).texture;\n\n        this.setMaxBetButtonGraphics(!reachedMaxBet);\n\n        this.maxBetButtonText.style = reachedMaxBet\n            ? this.componentConfiguration.maxBetButtonPosition.textStyleActive\n            : this.componentConfiguration.maxBetButtonPosition.textStyleNormal;\n\n        this.fitMaxBetTextInBounds();\n\n        this.betIncreaseBtn.enabled = !reachedMaxBet;\n        this.maxBetIncreaseBtn.enabled = !reachedMaxBet;\n    }\n\n    private updateBetTitles(): void {\n        if (\n            Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS) &&\n            this.rootStore.settings.factor !== this.rootStore.settings.getFactorByUniqueGameMode('NORMAL_MODE')\n        ) {\n            this.betMultiplierTitle.text = Core.translator.translate('BET MULTIPLIER');\n            this.betTitle.text = Core.translator.translate('BET');\n        } else {\n            this.betMultiplierTitle.text = Core.translator.translate('LINES');\n            this.betTitle.text = Core.translator.translate('BET PER LINE');\n        }\n    }\n\n    private crateBetMultiplierPanel(): void {\n        this.betMultiplierContainer = new Sprite();\n        this.betMultiplierContainer.name = 'betMultiplierContainer';\n        this.betOptionsContainer.addChild(this.betMultiplierContainer);\n\n        this.betMultiplierLabelBackground = new Sprite(Core.assets.getAsset('maxBetLabel').texture);\n        this.betMultiplierLabelBackground.anchor.set(0.5);\n        this.betMultiplierLabelBackground.x = this.componentConfiguration.betMultiplierPanel.labelBackgroundX;\n        this.betMultiplierLabelBackground.y = this.componentConfiguration.betMultiplierPanel.labelBackgroundY;\n        this.betMultiplierContainer.addChild(this.betMultiplierLabelBackground);\n\n        this.betMultiplierTitle = new Text(\n            Core.translator.translate(this.componentConfiguration.useNonLinearBetTitles ? 'BET MULTIPLIER' : 'LINES'),\n            this.componentConfiguration.betMultiplierPanel.titleTextStyle,\n        );\n        this.betMultiplierTitle.anchor.set(0.5, 0);\n        this.betMultiplierTitle.name = 'betMultiplierTitle';\n        this.betMultiplierTitle.x = this.componentConfiguration.betMultiplierPanel.titleX;\n        this.betMultiplierTitle.y = this.componentConfiguration.betMultiplierPanel.titleY;\n        this.betMultiplierContainer.addChild(this.betMultiplierTitle);\n        this.fitBetMultiplierTitleBetTitleInBounds();\n\n        this.betMultiplierLabel = new Text(\n            this.rootStore.settings.factor + 'x',\n            this.componentConfiguration.betMultiplierPanel.labelTextStyle,\n        );\n        this.betMultiplierLabel.x = this.componentConfiguration.betMultiplierPanel.labelX;\n        this.betMultiplierLabel.y = this.componentConfiguration.betMultiplierPanel.labelY;\n        this.betMultiplierLabel.anchor.set(0.5);\n        this.betMultiplierLabel.name = 'betMultiplierLabel';\n        this.betMultiplierLabelBackground.addChild(this.betMultiplierLabel);\n        this.updateMultiplierLabel();\n    }\n\n    private fitBetMultiplierTitleBetTitleInBounds(): void {\n        if (!this.betMultiplierTitle || !this.betTitle) return;\n\n        this.betMultiplierTitle.scale.set(1);\n        this.betTitle.scale.set(1);\n\n        const betMultiplierTitleMaxWidth = this.componentConfiguration.betMultiplierPanel.maxWidth;\n        const betTitleMaxWidth = this.componentConfiguration.betPanel.maxWidth;\n\n        const scale = Math.min(\n            1,\n            betMultiplierTitleMaxWidth / this.betMultiplierTitle.width,\n            betTitleMaxWidth / this.betTitle.width,\n        );\n\n        if (this.betMultiplierTitle.scale.x !== scale || this.betTitle.scale.x !== scale) {\n            this.betMultiplierTitle.scale.set(scale);\n            this.betTitle.scale.set(scale);\n        }\n    }\n\n    private updateMultiplierLabel(): void {\n        this.betMultiplierLabel.text = this.rootStore.settings.factor + 'x';\n    }\n\n    private createBetPanel(): void {\n        this.betContainer = new Sprite();\n        this.betContainer.name = 'betContainer';\n        this.betOptionsContainer.addChild(this.betContainer);\n\n        this.betDecreaseBtn = new Button(\n            Core.assets.getAssets(this.componentConfiguration.betDecreaseBtn.btnTextures),\n            undefined,\n            ButtonShapes.Circle,\n        );\n        this.betDecreaseBtn.name = 'betDecreaseBtn';\n        this.betDecreaseBtn.x = this.componentConfiguration.betPanel.decreaseBtnX;\n        this.betDecreaseBtn.y = this.componentConfiguration.betPanel.decreaseBtnY;\n        this.betDecreaseBtn.pivot.set(this.betDecreaseBtn.width / 2, this.betDecreaseBtn.height / 2);\n        this.betDecreaseBtn.scale.set(this.componentConfiguration.betPanel.decreaseBtnScale);\n        this.betContainer.addChild(this.betDecreaseBtn);\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/denomination-popup/src/egt/modes/max-bet/views/DenominationPopupViewMaxBet.ts:1156:9\",(this.betDecreaseBtn),\"pointertap\"]), fromEvent(this.betDecreaseBtn, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.decreaseBet.bind(this));\n\n        this.betIncreaseBtn = new Button(\n            Core.assets.getAssets(this.componentConfiguration.betIncreaseBtn.btnTextures),\n            undefined,\n            ButtonShapes.Circle,\n        );\n        this.betIncreaseBtn.name = 'betIncreaseBtn';\n        this.betIncreaseBtn.x = this.componentConfiguration.betPanel.increaseBtnX;\n        this.betIncreaseBtn.y = this.componentConfiguration.betPanel.increaseBtnY;\n        this.betIncreaseBtn.pivot.set(this.betIncreaseBtn.width / 2, this.betIncreaseBtn.height / 2);\n        this.betIncreaseBtn.scale.set(this.componentConfiguration.betPanel.increaseBtnScale);\n        this.betContainer.addChild(this.betIncreaseBtn);\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/denomination-popup/src/egt/modes/max-bet/views/DenominationPopupViewMaxBet.ts:1172:9\",(this.betIncreaseBtn),\"pointertap\"]), fromEvent(this.betIncreaseBtn, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.increaseBet.bind(this));\n\n        this.betLabelBackground = new Sprite(Core.assets.getAsset('maxBetLabel').texture);\n        this.betLabelBackground.anchor.set(0.5);\n        this.betLabelBackground.x = this.componentConfiguration.betPanel.labelBackgroundX;\n        this.betLabelBackground.y = this.componentConfiguration.betPanel.labelBackgroundY;\n        this.betContainer.addChild(this.betLabelBackground);\n\n        this.betTitle = new Text(\n            Core.translator.translate(this.componentConfiguration.useNonLinearBetTitles ? 'BET' : 'BET PER LINE'),\n            this.componentConfiguration.betPanel.titleTextStyle,\n        );\n        this.betTitle.anchor.set(0.5, 0);\n        this.betTitle.name = 'betTitle';\n        this.betTitle.x = this.componentConfiguration.betPanel.titleX;\n        this.betTitle.y = this.componentConfiguration.betPanel.titleY;\n        this.betContainer.addChild(this.betTitle);\n        this.fitBetMultiplierTitleBetTitleInBounds();\n\n        this.betLabelValueContainer = new Sprite();\n        this.betLabelValueContainer.name = 'betLabelValueContainer';\n        this.betLabelValueContainer.anchor.set(0.5);\n        this.betContainer.addChild(this.betLabelValueContainer);\n\n        this.betLabelValue = new Text('', this.componentConfiguration.betPanel.labelTextValueStyle);\n        this.betLabelValue.y = 0;\n        this.betLabelValue.anchor.set(1, 1);\n        this.betLabelValue.name = 'betLabelValue';\n        this.betLabelBackground.addChild(this.betLabelValue);\n\n        this.betLabelCurrency = new Text(\n            this.rootStore.settings.currency,\n            this.componentConfiguration.betPanel.labelTextCurrencyStyle,\n        );\n        this.betLabelCurrency.y = 0;\n        this.betLabelCurrency.anchor.set(0, 1);\n        this.betLabelCurrency.name = 'betLabelCurrency';\n        this.betLabelBackground.addChild(this.betLabelCurrency);\n        this.setBetValue();\n        this.updateMultiplierLabel();\n    }\n\n    private decreaseBet(): void {\n        // this.rootStore.uiStore.SELECTED_BET.next(\n        //     this.rootStore.settings.bets[\n        //     this.rootStore.settings.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value) - 1\n        //     ],\n        // );\n\n        const bets: number[] = this.rootStore.settings.bets;\n        const betIndex = bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value);\n        const denominations: number[] = this.rootStore.uiStore.denominations;\n        const previousDenomIndex = denominations.indexOf(Core.SELECTED_DENOMINATION.value) - 1;\n\n        if (betIndex > 0) {\n            this.rootStore.uiStore.SELECTED_BET.next(bets[betIndex - 1]);\n        } else {\n            this.rootStore.uiStore.SELECTED_BET.next(bets[bets.length - 1]);\n\n            if (betIndex === 0 && !this.oneDenomView && previousDenomIndex >= 0) {\n                Core.SELECTED_DENOMINATION.next(denominations[previousDenomIndex]);\n            }\n        }\n\n        this.rootStore.uiStore.CURRENT_BET_LEVEL.next({\n            betLevel: this.rootStore.uiStore.SELECTED_BET.value,\n            denomLevel: Core.SELECTED_DENOMINATION.value,\n        });\n        this.rootStore.subjects.CHANGE_SELECTED_BET_BTN_EXTERNALLY.next({\n            betVal: this.rootStore.uiStore.SELECTED_BET.value,\n            changedFromPopUp: true,\n        });\n        Core.sounds.play('changeBetSound');\n    }\n    private increaseBet(): void {\n        // this.rootStore.uiStore.SELECTED_BET.next(\n        //     this.rootStore.settings.bets[\n        //         this.rootStore.settings.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value) + 1\n        //     ],\n        // );\n        const bets: number[] = this.rootStore.settings.bets;\n        const betIndex = bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value);\n        const denominations: number[] = this.rootStore.uiStore.denominations;\n        const nextDenomIndex = denominations.indexOf(Core.SELECTED_DENOMINATION.value) + 1;\n\n        if (betIndex < bets.length - 1) {\n            this.rootStore.uiStore.SELECTED_BET.next(bets[betIndex + 1]);\n        } else {\n            this.rootStore.uiStore.SELECTED_BET.next(bets[0]);\n\n            if (betIndex === bets.length - 1 && !this.oneDenomView && nextDenomIndex <= denominations.length - 1) {\n                Core.SELECTED_DENOMINATION.next(denominations[nextDenomIndex]);\n            }\n        }\n\n        this.rootStore.uiStore.CURRENT_BET_LEVEL.next({\n            betLevel: this.rootStore.uiStore.SELECTED_BET.value,\n            denomLevel: Core.SELECTED_DENOMINATION.value,\n        });\n        this.rootStore.subjects.CHANGE_SELECTED_BET_BTN_EXTERNALLY.next({\n            betVal: this.rootStore.uiStore.SELECTED_BET.value,\n            changedFromPopUp: true,\n        });\n        Core.sounds.play('changeBetSound');\n    }\n\n    public setBetValue(): void {\n        // const bet: number = this.rootStore.getBetAmount();\n        // const factor: number = this.rootStore.settings.getFactorByUniqueGameMode(this.rootStore.settings.gameMode);\n        const wordSpace: number = 5;\n        this.betLabelValue.text = new MoneyFormatter(\n            this.rootStore.uiStore.SELECTED_BET.value * Core.SELECTED_DENOMINATION.value,\n        ).stringMoney;\n        this.applyBetLabelValueScale();\n        this.betLabelValue.x = (this.betLabelValue.width + wordSpace - this.betLabelCurrency.width) / 2;\n        this.betLabelCurrency.x = this.betLabelValue.x + wordSpace;\n        this.betLabelValue.y = this.betLabelCurrency.y = this.betLabelValue.height / 2;\n        this.setLastBetButtonsState();\n        this.steFirsBetButtonsState();\n        if (this.totalBetValueText) {\n            const totalBet =\n                this.rootStore.uiStore.SELECTED_BET.value *\n                Core.SELECTED_DENOMINATION.value *\n                this.rootStore.settings.factor;\n            this.totalBetValueText.text = new MoneyFormatter(totalBet).stringMoney;\n            this.syncBalanceAndTotalBetTextScales();\n        }\n    }\n\n    public onBalanceChanged(): void {\n        if (this.balanceValueText) {\n            const balance = this.rootStore.uiStore.BALANCE.value;\n            this.balanceValueText.text = new MoneyFormatter(balance).stringMoney;\n            this.syncBalanceAndTotalBetTextScales();\n        }\n    }\n\n    private syncBalanceAndTotalBetTextScales(): void {\n        if (!this.balanceValueText || !this.totalBetValueText) return;\n        this.balanceValueText.scale.set(1);\n        this.totalBetValueText.scale.set(1);\n\n        const balanceTextMaxWidth = this.componentConfiguration.balanceContainerStyle.maxWidth;\n        const totalBetMaxWidth = this.componentConfiguration.totalBetContainerStyle.maxWidth;\n\n        const balanceValueTextWidth = this.balanceValueText.width;\n        const balanceValueTextScale = Math.min(1, balanceTextMaxWidth / balanceValueTextWidth);\n\n        const totalBetValueTextWidth = this.totalBetValueText.width;\n        const totalBetValueTextScale = Math.min(1, totalBetMaxWidth / totalBetValueTextWidth);\n\n        const finalScale = Math.min(balanceValueTextScale, totalBetValueTextScale);\n\n        this.balanceValueText.scale.set(finalScale);\n        this.totalBetValueText.scale.set(finalScale);\n    }\n\n    private applyBetLabelValueScale(): void {\n        const labelMaxWidth = 120;\n        this.betLabelValue.scale.set(1);\n        this.betLabelCurrency.scale.set(1);\n\n        const scale = Math.min(1, labelMaxWidth / this.betLabelValue.width);\n        this.betLabelValue.scale.set(scale);\n        this.betLabelCurrency.scale.set(scale);\n    }\n\n    // private createGraphicsContainer(): void {\n    // this.graphicsContainer = new Sprite();\n    // this.isInteractive = true;\n    // this.graphicsContainer.visible = false;\n    // this.graphicsContainer.alpha = 0;\n    // this.addChild(this.graphicsContainer);\n    // }\n\n    private createMainContainer(): void {\n        this.mainContainer = new Container();\n        this.mainContainer.visible = false;\n        this.mainContainer.alpha = 0;\n        this.addChild(this.mainContainer);\n    }\n\n    private destroyObject(obj: any) {\n        obj?.destroy?.();\n        // @ts-ignore\n        obj = null;\n    }\n\n    private setMaxBetButtonGraphics(interactive: boolean): void {\n        if (!this.maxBetButtonGraphics) {\n            this.maxBetButtonGraphics = new Graphics();\n            this.maxBetButtonGraphics.beginFill(0x000000, 0.1).drawRect(0, 0, 174, 70).endFill();\n\n            this.maxBetButtonGraphics.alpha = 0;\n        }\n        if (!this.maxBetButton.children.find((child) => child === this.maxBetButtonGraphics)) {\n            this.maxBetButton.addChild(this.maxBetButtonGraphics);\n            this.maxBetButtonGraphics.pivot.set(\n                this.maxBetButtonGraphics.width / 2,\n                this.maxBetButtonGraphics.height / 2,\n            );\n        }\n\n        this.maxBetButtonGraphics.interactive = interactive;\n        this.maxBetButtonGraphics.cursor = 'pointer';\n    }\n\n    private fitMaxBetTextInBounds(): void {\n        if (!this.maxBetButtonText || !this.maxBetButtonGraphics) return;\n\n        this.maxBetButtonText.scale.set(1);\n        this.maxBetButtonText.updateText(true);\n\n        const maxAllowedWidth = this.maxBetButtonGraphics.width - this.boundsTextOffset;\n        const maxAllowedHeight = this.maxBetButtonGraphics.height;\n\n        const scaleX = maxAllowedWidth / this.maxBetButtonText.width;\n        const scaleY = maxAllowedHeight / this.maxBetButtonText.height;\n\n        const finalScale = Math.min(1, scaleX, scaleY);\n        this.maxBetButtonText.scale.set(finalScale);\n    }\n}\n","import Core, { BaseComponent, IBaseComponentView } from '@egt/core';\nimport { ReelsOverlayZOrders } from '@egt/reels-overlay';\nimport { SlotComponents, ZOrders } from '@egt/slot';\nimport { IModeConfig } from 'core/src/egt/core/BaseModeFactory';\nimport { Lifecycle } from 'tsyringe';\nimport FooterBackgroundModesConfigurations, { FooterBackgroundModes } from './FooterBackgroundFactory';\nimport { FooterBackgroundConfigFactoryBlurred } from './modes/blurred/configuration/FooterBackgroundComponentConfigurationBlurred';\nimport { FooterBackgroundConfigFactoryDefault } from './modes/default/configuration/FooterBackgroundComponentConfigurationDefault';\nimport { FooterBackgroundConfigFactorySided } from './modes/sided/configuration/FooterBackgroundComponentConfigurationSided';\n\nexport default class FooterBackgroundComponent extends BaseComponent {\n    public static configurationName = 'FooterBackgroundComponent';\n    public footerBackgroundView: IBaseComponentView;\n    public footerDarknessView: IBaseComponentView;\n    public footerBgAnimView: IBaseComponentView;\n    public componentType = SlotComponents.FOOTER_BACKGROUND;\n    public configuration;\n    public rootView;\n    public reelsOverlayView;\n\n    constructor(modeConfig: IModeConfig) {\n        super();\n        const baseConfigs = {\n            [FooterBackgroundModes.DEFAULT]: FooterBackgroundConfigFactoryDefault,\n            [FooterBackgroundModes.BLURRED]: FooterBackgroundConfigFactoryBlurred,\n            [FooterBackgroundModes.SIDED]: FooterBackgroundConfigFactorySided,\n        };\n\n        this.modeFactory = this.initMode<FooterBackgroundModesConfigurations>(modeConfig, {\n            defaultModeType: FooterBackgroundModes.DEFAULT,\n            baseConfigs,\n            defaultFactory: FooterBackgroundModesConfigurations,\n        });\n    }\n\n    public destroy(): void {\n        this.footerBackgroundView.destroy();\n        // @ts-ignore\n        this.footerBackgroundView = null;\n        this.configuration.destroy();\n        // @ts-ignore\n        this.configuration = null;\n        // @ts-ignore\n        this.rootView = null;\n        // @ts-ignore\n        this.reelsOverlayView = null;\n\n        // @ts-ignore\n        this.config = null;\n\n        super.destroy();\n    }\n\n    public onAfterGameConfigurationCreated(): void {\n        super.onAfterGameConfigurationCreated();\n        this.configuration = this.dependencyContainer.resolve('FooterBackgroundComponentConfiguration');\n    }\n\n    public onRegisterDependencies(container: any): void {\n        super.onRegisterDependencies(container);\n\n        this.dependencyContainer.register('FooterBackgroundComponentConfiguration', this.mode.configuration);\n\n        this.dependencyContainer.register(\n            'FooterBackgroundView',\n            { useClass: this.mode.view },\n            { lifecycle: Lifecycle.Singleton },\n        );\n\n        if (this.mode.secondView) {\n            this.dependencyContainer.register(\n                'FooterDarknessView',\n                { useClass: this.mode.secondView },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n\n        if (this.mode.thirdView) {\n            this.dependencyContainer.register(\n                'FooterBGAnimationView',\n                { useClass: this.mode.thirdView },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n    }\n\n    public onResolveDependencies(container: any): void {\n        super.onResolveDependencies(container);\n        this.rootView = this.dependencyContainer.resolve('RootView');\n        this.footerBackgroundView = this.dependencyContainer.resolve('FooterBackgroundView');\n        if (\n            this.dependencyContainer.isRegistered('ReelsOverlay') &&\n            this.modeFactory.modeType === FooterBackgroundModes.DEFAULT\n        ) {\n            this.reelsOverlayView = this.dependencyContainer.resolve('ReelsOverlay');\n            this.reelsOverlayView.addChild(this.footerBackgroundView);\n            this.footerBackgroundView.zIndex = ReelsOverlayZOrders.PANEL_BACKGROUND + 2;\n        } else {\n            this.rootView.addChild(this.footerBackgroundView);\n            this.footerBackgroundView.zIndex = ZOrders.UI_LEVEL - 1;\n        }\n\n        if (this.mode.secondView) {\n            this.footerDarknessView = this.dependencyContainer.resolve('FooterDarknessView');\n            this.footerDarknessView.zIndex = ZOrders.UI_LEVEL - 1;\n            this.rootView.addChild(this.footerDarknessView);\n        }\n\n        if (this.mode.thirdView && this.configuration.customAssetsBgAnim) {\n            this.footerBgAnimView = this.dependencyContainer.resolve('FooterBGAnimationView');\n            this.footerBgAnimView.zIndex = this.configuration.customAssetsBgAnimZIndex;\n            this.rootView.addChild(this.footerBgAnimView);\n        }\n    }\n\n    public onPrepareResources(_container: any): void {\n        Core.assets.addAssets(this.configuration?.assets?.toArray() || []);\n    }\n\n    public onInit(_view: any): void {\n        if (this.mode.secondView) {\n            this.footerDarknessView.init();\n        }\n    }\n}\n","import { BaseModesConfigurations, IForceSetConfig, IModes } from '@egt/core';\nimport { FooterBackgroundConfigFactoryBlurred } from './modes/blurred/configuration/FooterBackgroundComponentConfigurationBlurred';\nimport FooterBackgroundViewBlurred from './modes/blurred/views/FooterBackgroundViewBlurred';\nimport FooterDarknessViewBlurred from './modes/blurred/views/FooterDarknessViewBlurred';\nimport { FooterBackgroundConfigFactoryDefault } from './modes/default/configuration/FooterBackgroundComponentConfigurationDefault';\nimport FooterBackgroundViewDefault from './modes/default/views/FooterBackgroundViewDefault';\nimport { FooterBackgroundConfigFactorySided } from './modes/sided/configuration/FooterBackgroundComponentConfigurationSided';\nimport FooterBackgroundViewSided from './modes/sided/view/FooterBackgroundViewSided';\nimport FooterBGAnimationViewBlurred from './modes/blurred/views/FooterBGAnimationViewBlurred';\nexport default class FooterBackgroundModesConfigurations extends BaseModesConfigurations<FooterBackgroundModes> {\n    constructor(modeType: FooterBackgroundModes, forceSetConfig?: IForceSetConfig) {\n        super(modeType, forceSetConfig);\n    }\n\n    protected createBaseModesConfig(modeType: FooterBackgroundModes): IModes {\n        switch (modeType) {\n            case FooterBackgroundModes.BLURRED:\n                return {\n                    view: FooterBackgroundViewBlurred,\n                    secondView: FooterDarknessViewBlurred,\n                    thirdView: FooterBGAnimationViewBlurred,\n                    configuration: FooterBackgroundConfigFactoryBlurred(),\n                };\n            case FooterBackgroundModes.SIDED:\n                return {\n                    view: FooterBackgroundViewSided,\n                    configuration: FooterBackgroundConfigFactorySided(),\n                };\n            default:\n                return {\n                    view: FooterBackgroundViewDefault,\n                    configuration: FooterBackgroundConfigFactoryDefault(),\n                };\n        }\n    }\n}\n\nexport enum FooterBackgroundModes {\n    DEFAULT = 'default',\n    BLURRED = 'blurred',\n    SIDED = 'sided',\n}\n","import FooterBackgroundComponent from './FooterBackgroundComponent';\nimport { FooterBackgroundModes } from './FooterBackgroundFactory';\nimport FooterBackgroundComponentConfigurationBlurred, {\n    FooterBackgroundConfigFactoryBlurred,\n} from './modes/blurred/configuration/FooterBackgroundComponentConfigurationBlurred';\nimport {\n    IFooterBackgroundComponentConfigurationBlurred,\n    IFooterDarknessSettingsBlurred,\n    IGradientImgBlurred,\n} from './modes/blurred/interfaces/InterfacesBlurred';\nimport FooterBackgroundViewBlurred from './modes/blurred/views/FooterBackgroundViewBlurred';\nimport FooterBGAnimationViewBlurred from './modes/blurred/views/FooterBGAnimationViewBlurred';\nimport FooterDarknessViewBlurred from './modes/blurred/views/FooterDarknessViewBlurred';\nimport FooterBackgroundComponentConfigurationDefault, {\n    FooterBackgroundConfigFactoryDefault,\n} from './modes/default/configuration/FooterBackgroundComponentConfigurationDefault';\nimport {\n    IFooterBackgroundComponentConfigurationDefault,\n    SpriteTypeDefault,\n    IElementsDefault,\n    IFrameOverBetDefault,\n    IGradientImgDefault,\n    IAlphaDefault,\n    IBottomLinePosition,\n} from './modes/default/interfaces/InterfacesDefault';\nimport FooterBackgroundViewDefault from './modes/default/views/FooterBackgroundViewDefault';\nimport FooterBackgroundComponentConfigurationSided from './modes/sided/configuration/FooterBackgroundComponentConfigurationSided';\nimport { IGradientImgSided } from './modes/sided/interfaces/InterfacesSided';\nimport FooterBackgroundViewSided from './modes/sided/view/FooterBackgroundViewSided';\n\nexport {\n    FooterBackgroundComponentConfigurationBlurred,\n    FooterBackgroundModes,\n    FooterBackgroundViewBlurred,\n    FooterBackgroundComponentConfigurationDefault,\n    FooterBackgroundViewDefault,\n    SpriteTypeDefault,\n    FooterDarknessViewBlurred,\n    FooterBGAnimationViewBlurred,\n    FooterBackgroundConfigFactoryBlurred,\n    FooterBackgroundConfigFactoryDefault,\n    FooterBackgroundComponentConfigurationSided,\n    FooterBackgroundViewSided,\n};\nexport type {\n    IFooterBackgroundComponentConfigurationDefault,\n    IGradientImgDefault,\n    IAlphaDefault,\n    IFrameOverBetDefault,\n    IElementsDefault,\n    IFooterDarknessSettingsBlurred,\n    IGradientImgBlurred,\n    IFooterBackgroundComponentConfigurationBlurred,\n    IBottomLinePosition,\n    IGradientImgSided,\n};\nexport default FooterBackgroundComponent;\n","import {\n    DynamicPositionObject,\n    DefaultValue,\n    BaseComponentConfiguration,\n    DefaultAssets,\n    AssetsCollection,\n    AssetPriority,\n} from '@egt/core';\nimport {\n    IFooterBackgroundComponentConfigurationBlurred,\n    IFooterDarknessSettingsBlurred,\n    IGradientImgBlurred,\n} from '../interfaces/InterfacesBlurred';\nimport { ZOrders } from '@egt/slot';\n\nexport default class FooterBackgroundComponentConfigurationBlurred extends BaseComponentConfiguration {}\n\nexport function FooterBackgroundConfigFactoryBlurred(): any {\n    // tslint:disable-next-line: max-classes-per-file\n    class FooterBackgroundComponentConfigurationBlurredInternalClass\n        extends FooterBackgroundComponentConfigurationBlurred\n        implements IFooterBackgroundComponentConfigurationBlurred\n    {\n        @DefaultAssets([\n            {\n                id: 'footerBackground',\n                url: '../assets/components/slot/footer-background/blurred/footerBackground.json',\n                priority: AssetPriority.HIGHEST,\n                type: 'texture',\n            },\n            // miscellaneous should be rearanged as asset package and assets should be part of different packs for different components but for now well use to load the it from blurred footer\n            {\n                id: 'miscellaneous',\n                url: '../assets/commons/images/miscellaneous/modes/blurred/miscellaneous.json',\n                priority: AssetPriority.HIGHEST,\n                type: 'texture',\n            },\n        ])\n        public assets: AssetsCollection;\n        public customAssetsBgAnim: boolean = false;\n        public customAssetsBgAnimZIndex: number = ZOrders.REELS_LEVEL + 1;\n\n        @DefaultValue<IGradientImgBlurred>({\n            defaults: {\n                x: 0,\n                y: 472,\n                resourceName: 'footerPortrait',\n            },\n            landscape: {\n                resourceName: 'footerLandscape',\n            },\n            desktop: {\n                resourceName: 'footerLandscape',\n            },\n        })\n        public footerSprite: DynamicPositionObject<IGradientImgBlurred> & IGradientImgBlurred;\n\n        @DefaultValue<IFooterDarknessSettingsBlurred>({\n            defaults: {\n                height: 69,\n                color: 0x000000,\n                opacity: 1,\n                showOnDesktop: true,\n            },\n            portrait: { height: 104 },\n        })\n        public footerDarknessSettings: DynamicPositionObject<IFooterDarknessSettingsBlurred> &\n            IFooterDarknessSettingsBlurred;\n    }\n    return FooterBackgroundComponentConfigurationBlurredInternalClass;\n}\n","import Core from '@egt/core';\nimport { IFooterBackgroundComponentConfigurationBlurred } from '@egt/footer-background';\nimport { InitialSettings, ISlotConfiguration, RootStore, ServerState } from '@egt/slot';\nimport { ViewContainer } from '@egt/ui-lib';\nimport { Sprite } from 'pixi.js';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\n@injectable()\nexport default class FooterBGAnimationViewBlurred extends ViewContainer {\n    protected footerBgAnim: Sprite;\n    protected freeSpinsActive: boolean = false;\n\n    constructor(\n        @inject('ISlotConfiguration') protected configuration: ISlotConfiguration,\n        @inject('FooterBackgroundComponentConfiguration')\n        protected componentConfiguration: IFooterBackgroundComponentConfigurationBlurred,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('InitialSettings') protected settings: InitialSettings,\n    ) {\n        super();\n        this.name = 'FooterBGAnimationView';\n        this.initialRender();\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n\n        this.rootStore.subjects.PLAY_FS_FOOTER_BACKGROUND.pipe(takeUntil(this.DESTROY)).subscribe((active) => {\n            this.freeSpinsActive = active;\n            this.updateFooterBlurred();\n        });\n\n        if (this.settings.state === ServerState.FREESPIN) {\n            this.freeSpinsActive = true;\n            this.updateFooterBlurred();\n        }\n    }\n\n    public destroy(): void {\n        if (this.footerBgAnim) {\n            this.removeChild(this.footerBgAnim);\n            this.footerBgAnim.destroy();\n            // @ts-ignore\n            this.footerBgAnim = null;\n        }\n    }\n\n    public initialRender(): void {\n        this.createFooter();\n    }\n\n    protected setOrientation(): void {\n        this.updateFooterBlurred();\n    }\n\n    protected createFooter(): void {\n        if (this.componentConfiguration.customAssetsBgAnim) {\n            this.footerBgAnim = new Sprite();\n            this.footerBgAnim.anchor.set(0.5, 1);\n            this.footerBgAnim.name = 'footerBgAnim';\n            this.addChild(this.footerBgAnim);\n        }\n    }\n\n    protected updateFooterBlurred(): void {\n        if (this.footerBgAnim) {\n            const fS =\n                this.freeSpinsActive &&\n                Core.assets.getTextureFromSpriteSheet(\n                    'footerBackground',\n                    'blurredFooterFS' + Core.ORIENTATION.value.orientation + '.png',\n                )\n                    ? 'FS'\n                    : '';\n            this.footerBgAnim.texture = Core.assets.getTextureFromSpriteSheet(\n                'footerBackground',\n                'blurredFooter' + fS + Core.ORIENTATION.value.orientation + '.png',\n            );\n            this.footerBgAnim.y = Core.ORIENTATION.value.height;\n            this.footerBgAnim.x = Core.ORIENTATION.value.width / 2;\n        }\n    }\n}\n","import Core from '@egt/core';\nimport { ISlotConfiguration } from '@egt/slot';\nimport { ViewContainer } from '@egt/ui-lib';\nimport { Sprite } from 'pixi.js';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { IFooterBackgroundComponentConfigurationBlurred } from '../interfaces/InterfacesBlurred';\n\n@injectable()\nexport default class FooterBackgroundViewBlurred extends ViewContainer {\n    protected footerSprite: Sprite;\n\n    constructor(\n        @inject('ISlotConfiguration') protected configuration: ISlotConfiguration,\n        @inject('FooterBackgroundComponentConfiguration')\n        protected componentConfiguration: IFooterBackgroundComponentConfigurationBlurred,\n    ) {\n        super();\n        this.name = 'FooterBackgroundViewBlurred';\n        this.initialRender();\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n    }\n\n    public destroy(): void {\n        if (this.footerSprite) {\n            this.removeChild(this.footerSprite);\n            this.footerSprite.destroy();\n            // @ts-ignore\n            this.footerSprite = null;\n        }\n    }\n\n    public initialRender(): void {\n        this.createFooter();\n    }\n\n    protected setOrientation(): void {\n        this.updateFooter();\n    }\n\n    protected createFooter(): void {\n        this.footerSprite = new Sprite();\n        this.footerSprite.anchor.set(0.5, 1);\n        this.footerSprite.name = 'footerSprite';\n        this.addChild(this.footerSprite);\n    }\n\n    protected updateFooter(): void {\n        if (!this.footerSprite) {\n            return;\n        }\n        this.footerSprite.texture = Core.assets.getTextureFromSpriteSheet(\n            'footerBackground',\n            'mainMenuBackground' + Core.ORIENTATION.value.orientation + '.png',\n        );\n        this.footerSprite.y = Core.ORIENTATION.value.height;\n        this.footerSprite.x = Core.ORIENTATION.value.width / 2;\n    }\n}\n","import Core from '@egt/core';\nimport { RootStore } from '@egt/slot';\nimport { ViewContainer } from '@egt/ui-lib';\nimport { Graphics, Sprite } from 'pixi.js';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { merge } from 'rxjs';\nimport { IFooterBackgroundComponentConfigurationBlurred } from '../interfaces/InterfacesBlurred';\n\n@injectable()\nexport default class FooterDarknessViewBlurred extends ViewContainer {\n    private graphicContainer: Sprite;\n    private darknessGraphic: Graphics;\n\n    constructor(\n        @inject('FooterBackgroundComponentConfiguration')\n        protected componentConfiguration: IFooterBackgroundComponentConfigurationBlurred,\n        @inject('RootStore') protected rootStore: RootStore,\n    ) {\n        super();\n        this.name = 'FooterDarknessView';\n    }\n\n    public destroy(): void {\n        super.destroy();\n    }\n\n    public init(): void {\n        this.createContainer();\n        this.createGraphic();\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n        this.rootStore.subjects.SETTINGS_POPUP_OPENED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onSettingsOpened.bind(this),\n        );\n        const hideMerge = merge(\n            this.rootStore.subjects.MODAL_PRESSED,\n            this.rootStore.subjects.CLOSE_ALL_POPUPS,\n            this.rootStore.subjects.CLOSE_SETTINGS_POPUP,\n        );\n        hideMerge.pipe(takeUntil(this.DESTROY)).subscribe(this.onSettingsClosed.bind(this, true));\n    }\n\n    private onSettingsOpened(): void {\n        this.darknessGraphic.alpha =\n            Core.isDesktopMode && !this.componentConfiguration.footerDarknessSettings.showOnDesktop ? 0 : 1;\n    }\n\n    private onSettingsClosed(): void {\n        this.darknessGraphic.alpha = 0;\n    }\n\n    private createContainer(): void {\n        this.graphicContainer = new Sprite();\n        this.addChild(this.graphicContainer);\n    }\n\n    private createGraphic(): void {\n        this.darknessGraphic = new Graphics();\n        this.darknessGraphic.beginFill(\n            this.componentConfiguration.footerDarknessSettings.color,\n            this.componentConfiguration.footerDarknessSettings.opacity,\n        );\n        this.darknessGraphic.drawRect(\n            0,\n            0,\n            Core.display.stage.width,\n            this.componentConfiguration.footerDarknessSettings.height,\n        );\n        this.darknessGraphic.y = Core.display.stage.height - this.componentConfiguration.footerDarknessSettings.height;\n        this.graphicContainer.addChild(this.darknessGraphic);\n        this.darknessGraphic.alpha = 0;\n    }\n\n    private setOrientation(): void {\n        this.darknessGraphic.width = Core.display.stage.width;\n        this.darknessGraphic.height =\n            Core.display.stage.height - this.componentConfiguration.footerDarknessSettings.height;\n        this.darknessGraphic.y = Core.display.stage.height - this.componentConfiguration.footerDarknessSettings.height;\n    }\n}\n","import {\n    AddPriority,\n    AssetPriority,\n    AssetsCollection,\n    BaseComponentConfiguration,\n    DefaultAssets,\n    DefaultValue,\n    DynamicPositionObject,\n} from '@egt/core';\nimport { SlotComponents } from '@egt/slot';\nimport {\n    IAlphaDefault,\n    IElementsDefault,\n    IFrameOverBetDefault,\n    IGradientImgDefault,\n    IFooterBackgroundComponentConfigurationDefault,\n    SpriteTypeDefault,\n    IBottomLinePosition,\n} from '../interfaces/InterfacesDefault';\n\nexport default class FooterBackgroundComponentConfigurationDefault extends BaseComponentConfiguration {}\n\nexport function FooterBackgroundConfigFactoryDefault(): any {\n    class FooterBackgroundConfigurationInternal\n        extends FooterBackgroundComponentConfigurationDefault\n        implements IFooterBackgroundComponentConfigurationDefault\n    {\n        @DefaultAssets([\n            // miscellaneous should be rearanged as asset package and assets should be part of different packs for different components but for now well use to load the it from blurred footer\n            {\n                id: 'miscellaneous',\n                url: '../assets/commons/images/miscellaneous/modes/default/miscellaneous.json',\n                priority: AssetPriority.HIGHEST,\n                hasDesktopVersion: true,\n                type: 'texture',\n            },\n        ])\n        public assets: AssetsCollection;\n\n        @DefaultValue<IElementsDefault>({\n            defaults: {\n                leftGradient: true,\n                rightGradient: true,\n                mainGrapic: true,\n                soundGradient: false,\n                farameOverBetGradient: false,\n            },\n            landscape: { soundGradient: true },\n            portrait: { leftGradient: false, rightGradient: false },\n            desktop: { leftGradient: false, rightGradient: false },\n        })\n        public availableElements: DynamicPositionObject<IElementsDefault> & IElementsDefault;\n\n        @DefaultValue<IAlphaDefault>({\n            defaults: { x: 0, y: 0, width: 0, height: 0, alpha: 1, fill: 0x000000 },\n            landscape: { x: 0, y: 661, width: 1360, height: 104, alpha: 0.9 },\n            portrait: { x: 0, y: 1230, width: 765, height: 120, alpha: 0.8 },\n            desktop: { x: 0, y: 678 - 36, width: 1360, height: 87, alpha: 0.6 },\n        })\n        public mainGraphic: DynamicPositionObject<IAlphaDefault> & IAlphaDefault;\n\n        @DefaultValue<IGradientImgDefault>({\n            defaults: {\n                x: 0,\n                y: 472,\n                width: 149.5,\n                spriteSheetName: 'miscellaneous',\n                texture: 'mainMenuGradient.png',\n                scaleX: 1,\n                scaleY: 1,\n                type: SpriteTypeDefault.GRADIENT,\n            },\n        })\n        public leftGradient: DynamicPositionObject<IGradientImgDefault> & IGradientImgDefault;\n\n        @AddPriority<IGradientImgDefault>([\n            {\n                priorityType: { feature: SlotComponents.BACKGROUND_SOUND },\n                priority: 2,\n                value: {\n                    landscape: { x: 1247 },\n                },\n                condition: (current) => current.type === SpriteTypeDefault.CIRCLE,\n            },\n        ])\n        @DefaultValue<IGradientImgDefault>({\n            defaults: {\n                x: 1210.5,\n                y: 472,\n                width: 149.5,\n                spriteSheetName: 'miscellaneous',\n                texture: 'mainMenuGradient.png',\n                scaleX: 1,\n                scaleY: 1,\n                type: SpriteTypeDefault.GRADIENT,\n            },\n        })\n        public rightGradient: DynamicPositionObject<IGradientImgDefault> & IGradientImgDefault;\n\n        @DefaultValue<IGradientImgDefault>({\n            defaults: {\n                x: 1172,\n                y: 472,\n                width: 149.5,\n                spriteSheetName: 'miscellaneous',\n                texture: 'mainMenuGradient.png',\n                scaleX: 1,\n                scaleY: 1,\n                type: SpriteTypeDefault.GRADIENT,\n            },\n        })\n        public soundGradient: DynamicPositionObject<IGradientImgDefault> & IGradientImgDefault;\n\n        @DefaultValue<IFrameOverBetDefault>({\n            defaults: {\n                x: 0,\n                y: 689,\n                spriteSheetName: 'mainResources',\n                texture: 'gradientFramePortrait.png',\n            },\n        })\n        public farameOverBetGradient: DynamicPositionObject<IFrameOverBetDefault> & IFrameOverBetDefault;\n\n        @DefaultValue<IBottomLinePosition>({\n            defaults: {\n                x: 0,\n                y: 0,\n                visible: true,\n                height: 0,\n                display: true,\n                alpha: 1,\n            },\n            landscape: { x: 0, y: 737, height: 46, display: false },\n            portrait: { x: 0, y: 1314, height: 46 },\n            desktop: { x: 0, y: 729, height: 36 },\n            features: {\n                // [Features.MYSTERY_JACKPOT]: {\n                //     landscape: { display: false },\n                //     portrait: { display: false },\n                // },\n            },\n        })\n        public bottomLinePosition: DynamicPositionObject<IBottomLinePosition> & IBottomLinePosition;\n    }\n    return FooterBackgroundConfigurationInternal;\n}\n","import { DynamicPositionObject } from '@egt/core';\n\nexport interface IFooterBackgroundComponentConfigurationDefault {\n    availableElements: DynamicPositionObject<IElementsDefault> & IElementsDefault;\n    mainGraphic: DynamicPositionObject<IAlphaDefault> & IAlphaDefault;\n    leftGradient: DynamicPositionObject<IGradientImgDefault> & IGradientImgDefault;\n    rightGradient: DynamicPositionObject<IGradientImgDefault> & IGradientImgDefault;\n    soundGradient: DynamicPositionObject<IGradientImgDefault> & IGradientImgDefault;\n    farameOverBetGradient: DynamicPositionObject<IFrameOverBetDefault> & IFrameOverBetDefault;\n    bottomLinePosition: DynamicPositionObject<IBottomLinePosition> & IBottomLinePosition;\n}\n\nexport enum SpriteTypeDefault {\n    GRADIENT = 'gradient',\n    CIRCLE = 'circle',\n}\nexport interface IGradientImgDefault {\n    x: number;\n    y: number;\n    width: number;\n    texture: string;\n    spriteSheetName: string;\n    scaleX: number;\n    scaleY: number;\n    type: SpriteTypeDefault;\n}\nexport interface IAlphaDefault {\n    alpha: number;\n    x: number;\n    y: number;\n    width: number;\n    height: number;\n    fill: number;\n}\n\nexport interface IFrameOverBetDefault {\n    x: number;\n    y: number;\n    texture: string;\n    spriteSheetName: string;\n}\n\nexport interface IElementsDefault {\n    leftGradient: boolean;\n    rightGradient: boolean;\n    mainGrapic: boolean;\n    soundGradient: boolean;\n    farameOverBetGradient: boolean;\n}\n\nexport interface IBottomLinePosition {\n    x: number;\n    y: number;\n    height: number;\n    visible: boolean;\n    display: boolean;\n    alpha: number;\n}\n","import Core, { IOrientation } from '@egt/core';\nimport { ISlotConfiguration, SlotComponents } from '@egt/slot';\nimport { ViewContainer } from '@egt/ui-lib';\nimport { Graphics, Sprite } from 'pixi.js';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { IFooterBackgroundComponentConfigurationDefault, SpriteTypeDefault } from '../interfaces/InterfacesDefault';\n@injectable()\nexport default class FooterBackgroundViewDefault extends ViewContainer {\n    protected leftGradient: Sprite;\n    protected rightGradient: Sprite;\n    protected mainGraphic: Graphics;\n\n    protected farameOverBetGradient: Sprite;\n    protected soundGradient: Sprite;\n    protected bottomLine: Graphics;\n\n    constructor(\n        @inject('ISlotConfiguration') protected configuration: ISlotConfiguration,\n        @inject('FooterBackgroundComponentConfiguration')\n        protected componentConfiguration: IFooterBackgroundComponentConfigurationDefault,\n    ) {\n        super();\n        this.name = 'FooterBackgroundViewDefault';\n        this.sortableChildren = true;\n        this.initialRender();\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n    }\n\n    public initialRender(): void {\n        // Fill panel\n        this.createMainGraphic();\n        this.createLeftGradient();\n        this.createRightGradient();\n        this.createSoundGradient();\n        this.createFrameOverBetGradient();\n        this.createBottomLine();\n\n        // if(Core.assets.getTextureFromSpriteSheet(\"mainResources\", \"gradientFramePortrait.png\")){\n    }\n    protected createFrameOverBetGradient(): void {\n        if (this.componentConfiguration.availableElements.farameOverBetGradient) {\n            this.farameOverBetGradient = new Sprite(\n                Core.assets.getTextureFromSpriteSheet(\n                    this.componentConfiguration.farameOverBetGradient.spriteSheetName,\n                    this.componentConfiguration.farameOverBetGradient.texture,\n                ),\n            );\n            this.farameOverBetGradient.name = 'gradientFramePortrait';\n            this.farameOverBetGradient.y = this.componentConfiguration.farameOverBetGradient.y;\n            this.addChild(this.farameOverBetGradient);\n            this.farameOverBetGradient.zIndex = 5;\n        } else {\n            this.destroyElement(this.farameOverBetGradient);\n            // @ts-ignore\n            this.farameOverBetGradient = null;\n        }\n    }\n\n    protected setOrientation(_orientation: IOrientation): void {\n        this.updateMainGraphic();\n        this.updateLeftGradient();\n        this.updateRightGradient();\n        this.updateSoundGradient();\n        this.updateFrameOverBetGradient();\n        this.bottomLine.visible =\n            Core.ORIENTATION.value.isPortrait ||\n            (Core.isDesktopMode && this.componentConfiguration.bottomLinePosition.display);\n        this.bottomLine.x = this.componentConfiguration.bottomLinePosition.x;\n        this.bottomLine.y = this.componentConfiguration.bottomLinePosition.y;\n        // this.bottomLine.visible = this.componentConfiguration.bottomLinePosition.visible;\n        this.bottomLine.width = Core.display.stage.width;\n        this.bottomLine.height = this.componentConfiguration.bottomLinePosition.height;\n    }\n    protected updateFrameOverBetGradient(): void {\n        const shouldDisplay = this.componentConfiguration.availableElements.farameOverBetGradient;\n\n        if (shouldDisplay && !this.farameOverBetGradient) {\n            this.createFrameOverBetGradient();\n        } else if (!shouldDisplay && this.farameOverBetGradient) {\n            this.destroyElement(this.farameOverBetGradient);\n            // @ts-ignore\n            this.farameOverBetGradient = null;\n        }\n\n        if (this.farameOverBetGradient) {\n            this.farameOverBetGradient.x = this.componentConfiguration.farameOverBetGradient.x;\n            this.farameOverBetGradient.y = this.componentConfiguration.farameOverBetGradient.y;\n            this.farameOverBetGradient.texture = Core.assets.getTextureFromSpriteSheet(\n                this.componentConfiguration.farameOverBetGradient.spriteSheetName,\n                this.componentConfiguration.farameOverBetGradient.texture,\n            );\n        }\n    }\n\n    protected createMainGraphic(): void {\n        if (this.componentConfiguration.availableElements.mainGrapic) {\n            this.mainGraphic = new Graphics();\n            this.mainGraphic.beginFill(this.componentConfiguration.mainGraphic.fill);\n            this.mainGraphic.drawRect(0, 0, 1, 1);\n            this.mainGraphic.endFill();\n            this.mainGraphic.interactive = false;\n            this.mainGraphic.name = 'mainGraphic';\n            this.addChild(this.mainGraphic);\n            this.mainGraphic.zIndex = 2;\n        } else {\n            this.destroyElement(this.mainGraphic);\n            // @ts-ignore\n            this.mainGraphic = null;\n        }\n    }\n\n    protected createLeftGradient(): void {\n        if (this.componentConfiguration.availableElements.leftGradient) {\n            this.leftGradient = new Sprite(\n                Core.assets.getTextureFromSpriteSheet(\n                    this.componentConfiguration.leftGradient.spriteSheetName,\n                    this.componentConfiguration.leftGradient.texture,\n                ),\n            );\n            this.leftGradient.name = 'leftGradient';\n            this.addChild(this.leftGradient);\n            this.leftGradient.zIndex = 3;\n        } else {\n            this.destroyElement(this.leftGradient);\n            // @ts-ignore\n            this.leftGradient = null;\n        }\n    }\n\n    protected createSoundGradient(): void {\n        if (\n            this.componentConfiguration.availableElements.soundGradient &&\n            this.componentConfiguration.rightGradient.type === SpriteTypeDefault.CIRCLE &&\n            Core.hasComponent(SlotComponents.BACKGROUND_SOUND)\n        ) {\n            this.soundGradient = new Sprite(\n                Core.assets.getTextureFromSpriteSheet(\n                    this.componentConfiguration.soundGradient.spriteSheetName,\n                    this.componentConfiguration.soundGradient.texture,\n                ),\n            );\n            this.soundGradient.name = 'soundGradient';\n            this.addChild(this.soundGradient);\n            this.soundGradient.zIndex = 3;\n        } else {\n            this.destroyElement(this.soundGradient);\n            // @ts-ignore\n            this.soundGradient = null;\n        }\n    }\n    protected createRightGradient(): void {\n        if (this.componentConfiguration.availableElements.rightGradient) {\n            this.rightGradient = new Sprite(\n                Core.assets.getTextureFromSpriteSheet(\n                    this.componentConfiguration.rightGradient.spriteSheetName,\n                    this.componentConfiguration.rightGradient.texture,\n                ),\n            );\n            this.rightGradient.name = 'rightGradient';\n            this.addChild(this.rightGradient);\n            this.rightGradient.zIndex = 4;\n        } else {\n            this.destroyElement(this.rightGradient);\n            // @ts-ignore\n            this.rightGradient = null;\n        }\n    }\n\n    protected updateMainGraphic(): void {\n        const shouldDisplay = this.componentConfiguration.availableElements.mainGrapic;\n\n        if (shouldDisplay && !this.mainGraphic) {\n            this.createMainGraphic();\n        } else if (!shouldDisplay && this.mainGraphic) {\n            this.destroyElement(this.mainGraphic);\n            // @ts-ignore\n            this.mainGraphic = null;\n        }\n\n        if (this.mainGraphic) {\n            this.mainGraphic.x = this.componentConfiguration.mainGraphic.x;\n            this.mainGraphic.y = this.componentConfiguration.mainGraphic.y;\n            this.mainGraphic.width = this.componentConfiguration.mainGraphic.width;\n            this.mainGraphic.height = this.componentConfiguration.mainGraphic.height;\n            this.mainGraphic.alpha = this.componentConfiguration.mainGraphic.alpha;\n        }\n    }\n\n    protected updateLeftGradient(): void {\n        const shouldDisplay = this.componentConfiguration.availableElements.leftGradient;\n\n        if (shouldDisplay && !this.leftGradient) {\n            this.createLeftGradient();\n        } else if (!shouldDisplay && this.leftGradient) {\n            this.destroyElement(this.leftGradient);\n            // @ts-ignore\n            this.leftGradient = null;\n        }\n\n        if (this.leftGradient) {\n            this.leftGradient.texture = Core.assets.getTextureFromSpriteSheet(\n                this.componentConfiguration.leftGradient.spriteSheetName,\n                this.componentConfiguration.leftGradient.texture,\n            );\n            this.leftGradient.x = this.componentConfiguration.leftGradient.x;\n            this.leftGradient.y = this.componentConfiguration.leftGradient.y;\n            this.leftGradient.scale.set(\n                this.componentConfiguration.leftGradient.scaleX,\n                this.componentConfiguration.leftGradient.scaleY,\n            );\n            this.leftGradient.width = this.componentConfiguration.leftGradient.width;\n        }\n    }\n\n    protected updateSoundGradient(): void {\n        const shouldDisplay = this.componentConfiguration.availableElements.soundGradient;\n\n        if (shouldDisplay && !this.soundGradient) {\n            this.createSoundGradient();\n        } else if (!shouldDisplay && this.soundGradient) {\n            this.destroyElement(this.soundGradient);\n            // @ts-ignore\n            this.soundGradient = null;\n        }\n\n        if (this.soundGradient) {\n            this.soundGradient.x = this.componentConfiguration.soundGradient.x;\n            this.soundGradient.y = this.componentConfiguration.soundGradient.y;\n            this.soundGradient.scale.set(\n                this.componentConfiguration.soundGradient.scaleX,\n                this.componentConfiguration.soundGradient.scaleY,\n            );\n            this.soundGradient.width = this.componentConfiguration.soundGradient.width;\n            this.soundGradient.texture = Core.assets.getTextureFromSpriteSheet(\n                this.componentConfiguration.soundGradient.spriteSheetName,\n                this.componentConfiguration.soundGradient.texture,\n            );\n        }\n    }\n\n    protected updateRightGradient(): void {\n        const shouldDisplay = this.componentConfiguration.availableElements.rightGradient;\n\n        if (shouldDisplay && !this.rightGradient) {\n            this.createRightGradient();\n        } else if (!shouldDisplay && this.rightGradient) {\n            this.destroyElement(this.rightGradient);\n            // @ts-ignore\n            this.rightGradient = null;\n        }\n\n        if (this.rightGradient) {\n            this.rightGradient.x = this.componentConfiguration.rightGradient.x;\n            this.rightGradient.y = this.componentConfiguration.rightGradient.y;\n            this.rightGradient.scale.set(\n                this.componentConfiguration.rightGradient.scaleX,\n                this.componentConfiguration.rightGradient.scaleY,\n            );\n            this.rightGradient.width = this.componentConfiguration.rightGradient.width;\n            this.rightGradient.texture = Core.assets.getTextureFromSpriteSheet(\n                this.componentConfiguration.rightGradient.spriteSheetName,\n                this.componentConfiguration.rightGradient.texture,\n            );\n        }\n    }\n\n    public destroy(): void {\n        this.removeChildren();\n        if (this.bottomLine) {\n            this.bottomLine.destroy();\n            // @ts-ignore\n            this.bottomLine = null;\n        }\n        super.destroy({ children: true, texture: true, baseTexture: true });\n    }\n\n    private createBottomLine(): void {\n        if (this.bottomLine) {\n            this.removeChild(this.bottomLine);\n            // @ts-ignore\n            this.bottomLine = null;\n        }\n        // if (this.componentConfiguration.bottomLinePosition.display) {\n        this.bottomLine = new Graphics()\n            .beginFill(0x000000, 1)\n            .drawRect(\n                this.componentConfiguration.bottomLinePosition.x,\n                0,\n                Core.display.stage.width,\n                this.componentConfiguration.bottomLinePosition.height,\n            )\n            .endFill();\n        this.bottomLine.name = 'bottomLine';\n        // this.elements.set(this.bottomLine.name, this.bottomLine);\n        this.addChildAt(this.bottomLine, 0);\n        // }\n    }\n\n    protected destroyElement(element: any): void {\n        if (!element) {\n            return;\n        }\n\n        if (this.children.includes(element)) {\n            this.removeChild(element);\n        }\n        element.destroy();\n    }\n}\n","import {\n    AssetPriority,\n    AssetsCollection,\n    BaseComponentConfiguration,\n    DefaultAssets,\n    DefaultValue,\n    DynamicPositionObject,\n} from '@egt/core';\n\nimport {\n    IGradientImgSided,\n    IFooterBackgroundComponentConfigurationSided,\n    IBottomLinePosition,\n} from '../interfaces/InterfacesSided';\n\nexport default class FooterBackgroundComponentConfigurationSided extends BaseComponentConfiguration {}\n\nexport function FooterBackgroundConfigFactorySided(): any {\n    class FooterBackgroundConfigurationInternal\n        extends FooterBackgroundComponentConfigurationSided\n        implements IFooterBackgroundComponentConfigurationSided\n    {\n        @DefaultAssets([\n            // miscellaneous should be rearanged as asset package and assets should be part of different packs for different components but for now well use to load the it from blurred footer\n            {\n                id: 'miscellaneous',\n                url: '../assets/commons/images/miscellaneous/modes/sided/miscellaneous.json',\n                priority: AssetPriority.HIGHEST,\n                type: 'texture',\n            },\n        ])\n        public assets: AssetsCollection;\n\n        @DefaultValue<IGradientImgSided>({\n            defaults: {\n                x: 0,\n                y: 696,\n                width: 300,\n                spriteSheetName: 'miscellaneous',\n                texture: 'mainMenuBackgroundLandscape.png',\n                scaleX: 1,\n                scaleY: 1,\n            },\n            portrait: { y: 1255, width: 290, texture: 'mainMenuBackgroundPortrait.png' },\n        })\n        public leftGradient: DynamicPositionObject<IGradientImgSided> & IGradientImgSided;\n\n        @DefaultValue<IGradientImgSided>({\n            defaults: {\n                x: 1360,\n                y: 696,\n                width: 300,\n                spriteSheetName: 'miscellaneous',\n                texture: 'mainMenuBackgroundLandscape.png',\n                scaleX: -1,\n                scaleY: 1,\n            },\n            portrait: { x: 765, y: 1255, width: 290, texture: 'mainMenuBackgroundPortrait.png' },\n        })\n        public rightGradient: DynamicPositionObject<IGradientImgSided> & IGradientImgSided;\n\n        @DefaultValue<IBottomLinePosition>({\n            defaults: {\n                x: 0,\n                y: 1329,\n                visible: true,\n                height: 46,\n                display: true,\n                alpha: 1,\n            },\n            landscape: { y: 0, display: false },\n            desktop: { y: 729, height: 36, display: false },\n            features: {},\n        })\n        public bottomLinePosition: DynamicPositionObject<IBottomLinePosition> & IBottomLinePosition;\n    }\n    return FooterBackgroundConfigurationInternal;\n}\n","import Core, { IOrientation } from '@egt/core';\nimport { ISlotConfiguration } from '@egt/slot';\nimport { ViewContainer } from '@egt/ui-lib';\nimport { Graphics, Sprite } from 'pixi.js';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { IFooterBackgroundComponentConfigurationSided } from '../interfaces/InterfacesSided';\n@injectable()\nexport default class FooterBackgroundViewSided extends ViewContainer {\n    protected leftGradient: Sprite;\n    protected rightGradient: Sprite;\n    // protected mainGraphic: Graphics;\n    // protected frameOverBetGradient: Sprite;\n    // protected soundGradient: Sprite;\n    protected bottomLine: Graphics;\n\n    constructor(\n        @inject('ISlotConfiguration') protected configuration: ISlotConfiguration,\n        @inject('FooterBackgroundComponentConfiguration')\n        protected componentConfiguration: IFooterBackgroundComponentConfigurationSided,\n    ) {\n        super();\n        this.name = 'FooterBackgroundViewSided';\n        this.sortableChildren = true;\n        this.initialRender();\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n    }\n\n    public initialRender(): void {\n        // Fill panel\n        // this.createMainGraphic();\n        this.createLeftGradient();\n        this.createRightGradient();\n        // this.createSoundGradient();\n        // this.createFrameOverBetGradient();\n        this.createBottomLine();\n\n        // if(Core.assets.getTextureFromSpriteSheet(\"mainResources\", \"gradientFramePortrait.png\")){\n    }\n    // protected createFrameOverBetGradient(): void {\n    //     if (this.componentConfiguration.availableElements.frameOverBetGradient) {\n    //         this.frameOverBetGradient = new Sprite(\n    //             Core.assets.getTextureFromSpriteSheet(\n    //                 this.componentConfiguration.frameOverBetGradient.spriteSheetName,\n    //                 this.componentConfiguration.frameOverBetGradient.texture,\n    //             ),\n    //         );\n    //         this.frameOverBetGradient.name = 'gradientFramePortrait';\n    //         this.frameOverBetGradient.y = this.componentConfiguration.frameOverBetGradient.y;\n    //         this.addChild(this.frameOverBetGradient);\n    //         this.frameOverBetGradient.zIndex = 5;\n    //     } else {\n    //         this.destroyElement(this.frameOverBetGradient);\n    //         // @ts-ignore\n    //         this.frameOverBetGradient = null;\n    //     }\n    // }\n\n    protected setOrientation(_orientation: IOrientation): void {\n        this.updateLeftGradient();\n        this.updateRightGradient();\n        // this.updateSoundGradient();\n        this.bottomLine.visible =\n            Core.ORIENTATION.value.isPortrait ||\n            (Core.isDesktopMode && this.componentConfiguration.bottomLinePosition.display);\n        this.bottomLine.x = this.componentConfiguration.bottomLinePosition.x;\n        this.bottomLine.y = this.componentConfiguration.bottomLinePosition.y;\n\n        this.bottomLine.width = Core.display.stage.width;\n        this.bottomLine.height = this.componentConfiguration.bottomLinePosition.height;\n    }\n    // protected updateFrameOverBetGradient(): void {\n    //     const shouldDisplay = this.componentConfiguration.availableElements.frameOverBetGradient;\n\n    //     if (shouldDisplay && !this.frameOverBetGradient) {\n    //         this.createFrameOverBetGradient();\n    //     } else if (!shouldDisplay && this.frameOverBetGradient) {\n    //         this.destroyElement(this.frameOverBetGradient);\n    //         // @ts-ignore\n    //         this.frameOverBetGradient = null;\n    //     }\n\n    //     if (this.frameOverBetGradient) {\n    //         this.frameOverBetGradient.x = this.componentConfiguration.frameOverBetGradient.x;\n    //         this.frameOverBetGradient.y = this.componentConfiguration.frameOverBetGradient.y;\n    //         this.frameOverBetGradient.texture = Core.assets.getTextureFromSpriteSheet(\n    //             this.componentConfiguration.frameOverBetGradient.spriteSheetName,\n    //             this.componentConfiguration.frameOverBetGradient.texture,\n    //         );\n    //     }\n    // }\n\n    // protected createMainGraphic(): void {\n    //     if (this.componentConfiguration.availableElements.mainGraphic) {\n    //         this.mainGraphic = new Graphics();\n    //         this.mainGraphic.beginFill(this.componentConfiguration.mainGraphic.fill);\n    //         this.mainGraphic.drawRect(0, 0, 1, 1);\n    //         this.mainGraphic.endFill();\n    //         this.mainGraphic.interactive = false;\n    //         this.mainGraphic.name = 'mainGraphic';\n    //         this.addChild(this.mainGraphic);\n    //         this.mainGraphic.zIndex = 2;\n    //     } else {\n    //         this.destroyElement(this.mainGraphic);\n    //         // @ts-ignore\n    //         this.mainGraphic = null;\n    //     }\n    // }\n\n    protected createLeftGradient(): void {\n        this.leftGradient = new Sprite(\n            Core.assets.getTextureFromSpriteSheet(\n                this.componentConfiguration.leftGradient.spriteSheetName,\n                this.componentConfiguration.leftGradient.texture,\n            ),\n        );\n        this.leftGradient.name = 'leftGradient';\n        this.addChild(this.leftGradient);\n        this.leftGradient.zIndex = 3;\n    }\n\n    // protected createSoundGradient(): void {\n    //     if (\n    //         this.componentConfiguration.availableElements.soundGradient &&\n    //         this.componentConfiguration.rightGradient.type === SpriteTypeSided.CIRCLE &&\n    //         Core.hasComponent(SlotComponents.BACKGROUND_SOUND)\n    //     ) {\n    //         this.soundGradient = new Sprite(\n    //             Core.assets.getTextureFromSpriteSheet(\n    //                 this.componentConfiguration.soundGradient.spriteSheetName,\n    //                 this.componentConfiguration.soundGradient.texture,\n    //             ),\n    //         );\n    //         this.soundGradient.name = 'soundGradient';\n    //         this.addChild(this.soundGradient);\n    //         this.soundGradient.zIndex = 3;\n    //     } else {\n    //         this.destroyElement(this.soundGradient);\n    //         // @ts-ignore\n    //         this.soundGradient = null;\n    //     }\n    // }\n    protected createRightGradient(): void {\n        this.rightGradient = new Sprite(\n            Core.assets.getTextureFromSpriteSheet(\n                this.componentConfiguration.rightGradient.spriteSheetName,\n                this.componentConfiguration.rightGradient.texture,\n            ),\n        );\n        this.rightGradient.name = 'rightGradient';\n        this.addChild(this.rightGradient);\n        this.rightGradient.zIndex = 4;\n    }\n\n    // protected updateMainGraphic(): void {\n    //     const shouldDisplay = this.componentConfiguration.availableElements.mainGraphic;\n\n    //     if (shouldDisplay && !this.mainGraphic) {\n    //         this.createMainGraphic();\n    //     } else if (!shouldDisplay && this.mainGraphic) {\n    //         this.destroyElement(this.mainGraphic);\n    //         // @ts-ignore\n    //         this.mainGraphic = null;\n    //     }\n\n    //     if (this.mainGraphic) {\n    //         this.mainGraphic.x = this.componentConfiguration.mainGraphic.x;\n    //         this.mainGraphic.y = this.componentConfiguration.mainGraphic.y;\n    //         this.mainGraphic.width = this.componentConfiguration.mainGraphic.width;\n    //         this.mainGraphic.height = this.componentConfiguration.mainGraphic.height;\n    //         this.mainGraphic.alpha = this.componentConfiguration.mainGraphic.alpha;\n    //     }\n    // }\n\n    protected updateLeftGradient(): void {\n        if (!this.leftGradient) {\n            this.createLeftGradient();\n        }\n        this.leftGradient.texture = Core.assets.getTextureFromSpriteSheet(\n            this.componentConfiguration.leftGradient.spriteSheetName,\n            this.componentConfiguration.leftGradient.texture,\n        );\n        this.leftGradient.x = this.componentConfiguration.leftGradient.x;\n        this.leftGradient.y = this.componentConfiguration.leftGradient.y;\n        this.leftGradient.scale.set(\n            this.componentConfiguration.leftGradient.scaleX,\n            this.componentConfiguration.leftGradient.scaleY,\n        );\n        this.leftGradient.width = this.componentConfiguration.leftGradient.width;\n    }\n\n    // protected updateSoundGradient(): void {\n    //     const shouldDisplay = this.componentConfiguration.availableElements.soundGradient;\n\n    //     if (shouldDisplay && !this.soundGradient) {\n    //         this.createSoundGradient();\n    //     } else if (!shouldDisplay && this.soundGradient) {\n    //         this.destroyElement(this.soundGradient);\n    //         // @ts-ignore\n    //         this.soundGradient = null;\n    //     }\n\n    //     if (this.soundGradient) {\n    //         this.soundGradient.x = this.componentConfiguration.soundGradient.x;\n    //         this.soundGradient.y = this.componentConfiguration.soundGradient.y;\n    //         this.soundGradient.scale.set(\n    //             this.componentConfiguration.soundGradient.scaleX,\n    //             this.componentConfiguration.soundGradient.scaleY,\n    //         );\n    //         this.soundGradient.width = this.componentConfiguration.soundGradient.width;\n    //         this.soundGradient.texture = Core.assets.getTextureFromSpriteSheet(\n    //             this.componentConfiguration.soundGradient.spriteSheetName,\n    //             this.componentConfiguration.soundGradient.texture,\n    //         );\n    //     }\n    // }\n\n    protected updateRightGradient(): void {\n        if (!this.rightGradient) {\n            this.createRightGradient();\n        }\n        this.rightGradient.x = this.componentConfiguration.rightGradient.x;\n        this.rightGradient.y = this.componentConfiguration.rightGradient.y;\n        this.rightGradient.scale.set(\n            this.componentConfiguration.rightGradient.scaleX,\n            this.componentConfiguration.rightGradient.scaleY,\n        );\n        this.rightGradient.width = this.componentConfiguration.rightGradient.width;\n        this.rightGradient.texture = Core.assets.getTextureFromSpriteSheet(\n            this.componentConfiguration.rightGradient.spriteSheetName,\n            this.componentConfiguration.rightGradient.texture,\n        );\n    }\n\n    public destroy(): void {\n        this.removeChildren();\n        if (this.bottomLine) {\n            this.bottomLine.destroy();\n            // @ts-ignore\n            this.bottomLine = null;\n        }\n        if (this.leftGradient) {\n            this.destroyElement(this.leftGradient);\n            // @ts-ignore\n            this.leftGradient = null;\n        }\n        if (this.rightGradient) {\n            this.destroyElement(this.rightGradient);\n            // @ts-ignore\n            this.rightGradient = null;\n        }\n        super.destroy({ children: true, texture: true, baseTexture: true });\n    }\n\n    private createBottomLine(): void {\n        if (this.bottomLine) {\n            this.removeChild(this.bottomLine);\n            // @ts-ignore\n            this.bottomLine = null;\n        }\n        this.bottomLine = new Graphics()\n            .beginFill(0x000000, 1)\n            .drawRect(\n                this.componentConfiguration.bottomLinePosition.x,\n                0,\n                Core.display.stage.width,\n                this.componentConfiguration.bottomLinePosition.height,\n            )\n            .endFill();\n        this.bottomLine.name = 'bottomLine';\n        this.addChildAt(this.bottomLine, 0);\n    }\n\n    protected destroyElement(element: any): void {\n        if (!element) {\n            return;\n        }\n\n        if (this.children.includes(element)) {\n            this.removeChild(element);\n        }\n        element.destroy();\n    }\n}\n","import Core, { BaseComponent, IBaseComponentController, IBaseComponentView, IModeConfig } from '@egt/core';\nimport { SlotComponents } from '@egt/slot';\nimport { Lifecycle } from 'tsyringe';\nimport HomeButtonModesConfigurations, { HomeButtonModes } from './HomeButtonFactory';\nimport { HomeButtonComponentConfigurationFactoryDefault } from './modes/default/configuration/HomeButtonComponentConfigurationDefault';\nimport { HomeButtonComponentConfigurationFactorySided } from './modes/sided/configuration/HomeButtonComponentConfigurationSided';\nimport { HomeButtonComponentConfigurationFactoryBlurred } from './modes/blurred/configuration/HomeButtonComponentConfigurationBlurred';\n\nexport default class HomeButtonComponent extends BaseComponent {\n    public static configurationName = 'HomeButtonComponent';\n    public homeButtonView: IBaseComponentView;\n    public homeButtonController: IBaseComponentController;\n    public componentType = SlotComponents.HOME_BUTTON;\n    public configuration: any;\n    public rootView;\n\n    constructor(modeConfig: IModeConfig) {\n        super();\n        const baseConfigs = {\n            [HomeButtonModes.DEFAULT]: HomeButtonComponentConfigurationFactoryDefault,\n            [HomeButtonModes.BLURRED]: HomeButtonComponentConfigurationFactoryBlurred,\n            [HomeButtonModes.SIDED]: HomeButtonComponentConfigurationFactorySided,\n        };\n\n        this.modeFactory = this.initMode<HomeButtonModesConfigurations>(modeConfig, {\n            defaultModeType: HomeButtonModes.DEFAULT,\n            baseConfigs,\n            defaultFactory: HomeButtonModesConfigurations,\n        });\n    }\n\n    public destroy(): void {\n        this.homeButtonController.destroy();\n        // @ts-ignore\n        this.homeButtonController = null;\n        // @ts-ignore\n        this.homeButtonView = null;\n        this.configuration.destroy();\n        // @ts-ignore\n        this.configuration = null;\n        // @ts-ignore\n        this.dependencyContainer = null;\n        // @ts-ignore\n        this.rootView = null;\n        // @ts-ignore\n        this.config = null;\n        super.destroy();\n    }\n\n    public onRegisterDependencies(container: any): void {\n        super.onRegisterDependencies(container);\n        this.dependencyContainer.register(\n            'HomeButtonController',\n            { useClass: this.mode.controller },\n            { lifecycle: Lifecycle.Singleton },\n        );\n        this.dependencyContainer.register(\n            'HomeButtonView',\n            { useClass: this.mode.view },\n            { lifecycle: Lifecycle.Singleton },\n        );\n\n        this.dependencyContainer.register('HomeButtonComponentConfiguration', this.mode.configuration);\n    }\n\n    public onPrepareResources(): void {\n        this.configuration = this.dependencyContainer.resolve('HomeButtonComponentConfiguration');\n        Core.assets.addAssets(this.configuration?.assets?.toArray() || []);\n    }\n\n    public onResolveDependencies(container: any): void {\n        super.onResolveDependencies(container);\n\n        this.homeButtonController = this.dependencyContainer.resolve('HomeButtonController');\n        this.rootView = this.dependencyContainer.resolve('RootView');\n        this.homeButtonView = this.dependencyContainer.resolve('HomeButtonView');\n        this.rootView.addChild(this.homeButtonView);\n    }\n\n    public onInit(_view: any): void {\n        this.homeButtonView.init();\n        this.homeButtonController.init();\n    }\n}\n","import { BaseModesConfigurations, IForceSetConfig, IModes } from '@egt/core';\nimport { HomeButtonComponentConfigurationFactoryBlurred } from './modes/blurred/configuration/HomeButtonComponentConfigurationBlurred';\nimport { HomeButtonComponentConfigurationFactoryDefault } from './modes/default/configuration/HomeButtonComponentConfigurationDefault';\nimport HomeButtonControllerDefault from './modes/default/controllers/HomeButtonControllerDefault';\nimport HomeButtonViewDefault from './modes/default/views/HomeButtonViewDefault';\nimport { HomeButtonComponentConfigurationFactorySided } from './modes/sided/configuration/HomeButtonComponentConfigurationSided';\n\nexport default class HomeButtonModesConfigurations extends BaseModesConfigurations<HomeButtonModes> {\n    constructor(modeType: HomeButtonModes, forceSetConfig?: IForceSetConfig) {\n        super(modeType, forceSetConfig);\n    }\n\n    protected createBaseModesConfig(modeType: HomeButtonModes): IModes {\n        switch (modeType) {\n            case HomeButtonModes.BLURRED:\n                return {\n                    view: HomeButtonViewDefault,\n                    controller: HomeButtonControllerDefault,\n                    configuration: HomeButtonComponentConfigurationFactoryBlurred(),\n                };\n            case HomeButtonModes.SIDED:\n                return {\n                    view: HomeButtonViewDefault,\n                    controller: HomeButtonControllerDefault,\n                    configuration: HomeButtonComponentConfigurationFactorySided(),\n                };\n            default:\n                return {\n                    view: HomeButtonViewDefault,\n                    controller: HomeButtonControllerDefault,\n                    configuration: HomeButtonComponentConfigurationFactoryDefault(),\n                };\n        }\n    }\n}\n\nexport enum HomeButtonModes {\n    DEFAULT = 'default',\n    BLURRED = 'blurred',\n    SIDED = 'sided',\n}\n","import HomeButtonComponent from './HomeButtonComponent';\nimport { HomeButtonModes } from './HomeButtonFactory';\nimport { IButtonProps, IRoundGraphic, IText } from './interfaces/HomeButtonInterfaces';\nimport { IHomeButtonComponentConfiguration } from './interfaces/IHomeButtonComponentConfiguration';\nimport HomeButtonComponentConfigurationBlurred from './modes/blurred/configuration/HomeButtonComponentConfigurationBlurred';\nimport HomeButtonComponentConfigurationDefault from './modes/default/configuration/HomeButtonComponentConfigurationDefault';\nimport HomeButtonControllerDefault from './modes/default/controllers/HomeButtonControllerDefault';\nimport HomeButtonViewDefault from './modes/default/views/HomeButtonViewDefault';\nimport HomeButtonComponentConfigurationSided from './modes/sided/configuration/HomeButtonComponentConfigurationSided';\n\nexport {\n    IHomeButtonComponentConfiguration,\n    HomeButtonComponentConfigurationDefault,\n    HomeButtonComponentConfigurationBlurred,\n    HomeButtonComponentConfigurationSided,\n    HomeButtonControllerDefault,\n    HomeButtonViewDefault,\n    IButtonProps,\n    IRoundGraphic,\n    HomeButtonModes,\n    IText,\n};\nexport default HomeButtonComponent;\n","import {\n    AddPriority,\n    AssetPriority,\n    AssetsCollection,\n    BaseComponentConfiguration,\n    DefaultAssets,\n    DefaultValue,\n    DynamicPositionObject,\n} from '@egt/core';\nimport { SlotComponents, ZOrders } from '@egt/slot';\nimport { TextAlign } from '@egt/ui-lib';\nimport { IPointData } from 'pixi.js';\nimport { IButtonProps, IGraphic, IRoundGraphic, IText } from '../../../interfaces/HomeButtonInterfaces';\nimport { FooterBackgroundModes } from '@egt/footer-background';\nimport { IHomeButtonComponentConfiguration } from '../../../interfaces/IHomeButtonComponentConfiguration';\n\nexport default class HomeButtonComponentConfigurationBlurred extends BaseComponentConfiguration {}\n\nexport function HomeButtonComponentConfigurationFactoryBlurred(): any {\n    class HomeButtonComponentConfigurationBlurredInternalClass\n        extends HomeButtonComponentConfigurationBlurred\n        implements IHomeButtonComponentConfiguration\n    {\n        public zIndexOff = ZOrders.UI_LEVEL + 1;\n        public zIndexOn = ZOrders.POPUP_LEVEL + 3;\n\n        @DefaultAssets([\n            {\n                id: 'svgHome',\n                url: '../assets/components/slot/home-button/blurred/ui-svg/home.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 60, height: 60 },\n                },\n            },\n            {\n                id: 'svgLobbyPopupClose',\n                url: '../assets/components/slot/home-button/blurred/ui-svg/lobbyPopupClose.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 60, height: 60 },\n                },\n            },\n            {\n                id: 'svgEgtLobbyButton',\n                url: '../assets/components/slot/home-button/common/ui-svg/egtLobbyButton.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 76, height: 76 },\n                },\n            },\n        ])\n        public assets: AssetsCollection;\n\n        @AddPriority<IButtonProps>([\n            {\n                priorityType: { feature: SlotComponents.FOOTER_BACKGROUND, mode: FooterBackgroundModes.BLURRED },\n                priority: 1,\n                value: {\n                    landscape: { x: 36, y: 732 },\n                    portrait: { x: 36, y: 1304 },\n                    desktop: { x: 36, y: 732 },\n                },\n            },\n        ])\n        @DefaultValue<IButtonProps>({\n            defaults: { x: 76.5, y: 699.5, scale: 1, visible: true, textures: ['svgHome'] },\n            portrait: { x: 47, y: 1273 },\n            desktop: { x: 52, y: 747.5 },\n        })\n        public homeButtonPosition: DynamicPositionObject<IButtonProps> & IButtonProps;\n\n        @AddPriority<IPointData>([\n            {\n                priorityType: { feature: SlotComponents.FOOTER_BACKGROUND, mode: FooterBackgroundModes.BLURRED },\n                priority: 1,\n                value: {\n                    landscape: { x: 36, y: 732 },\n                    portrait: { x: 36, y: 1304 },\n                    desktop: { x: 36, y: 732 },\n                },\n            },\n        ])\n        @DefaultValue<IPointData>({\n            defaults: { x: 77, y: 698.5 },\n            portrait: { x: 47, y: 1273 },\n            desktop: { x: 52, y: 747.5 },\n        })\n        public lobbySelectionViewCloseButton: DynamicPositionObject<IPointData> & IPointData;\n\n        // HOME BUTTON\n        @DefaultValue<IRoundGraphic>({\n            defaults: {\n                x: 15,\n                y: 369,\n                beginFill: [0x2e2e2e, 1],\n                drawRect: {\n                    x: 0,\n                    y: 0,\n                    width: 234,\n                    height: 141,\n                    radius: 6,\n                },\n                cursor: 'pointer',\n                interactive: true,\n                visible: true,\n            },\n            portrait: { x: 17, y: 934 },\n            desktop: { x: 35, y: 404 },\n        })\n        public lobbySelectionViewHomeLobbyButtonGraphic: DynamicPositionObject<IRoundGraphic> & IRoundGraphic;\n\n        @DefaultValue<IText>({\n            defaults: {\n                x: 10,\n                y: 469,\n                fontFamily: 'Arial',\n                fontSize: 26,\n                fontWeight: 'bold',\n                fill: '#828282',\n                bounds: {\n                    width: 234,\n                    height: 30,\n                },\n                align: TextAlign.CENTER,\n                shouldFitInBounds: true,\n            },\n            portrait: { x: 17, y: 1034 },\n            desktop: { x: 35, y: 504 },\n        })\n        public lobbySelectionViewHomeText: DynamicPositionObject<IText> & IText;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 90, y: 392 },\n            portrait: { x: 97, y: 950 },\n            desktop: { x: 115, y: 427 },\n        })\n        public lobbySelectionViewHomeLobbyButton: DynamicPositionObject<IPointData> & IPointData;\n\n        // LOBBY BUTTON\n        @DefaultValue<IRoundGraphic>({\n            defaults: {\n                x: 15,\n                y: 522,\n                beginFill: [0x2e2e2e, 1],\n                drawRect: {\n                    x: 0,\n                    y: 0,\n                    width: 234,\n                    height: 141,\n                    radius: 6,\n                },\n                cursor: 'pointer',\n                interactive: true,\n                visible: true,\n            },\n            portrait: { x: 17, y: 1087 },\n            desktop: { x: 35, y: 557 },\n        })\n        public lobbySelectionViewEGTLobbyButtonGraphic: DynamicPositionObject<IRoundGraphic> & IRoundGraphic;\n\n        @DefaultValue<IText>({\n            defaults: {\n                x: 10,\n                y: 624,\n                fontFamily: 'Arial',\n                fontSize: 26,\n                fontWeight: 'bold',\n                fill: '#828282',\n                bounds: {\n                    width: 234,\n                    height: 30,\n                },\n                align: TextAlign.CENTER,\n                shouldFitInBounds: true,\n            },\n            portrait: { x: 17, y: 1189 },\n            desktop: { x: 35, y: 659 },\n        })\n        public lobbySelectionViewLobbyText: DynamicPositionObject<IText> & IText;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 90, y: 540 },\n            portrait: { x: 97, y: 1106 },\n            desktop: { x: 115, y: 575 },\n        })\n        public lobbySelectionViewEGTLobbyButton: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IGraphic>({\n            defaults: {\n                beginFill: [0x000000, 0.7],\n                drawRect: {\n                    x: 0,\n                    y: 0,\n                    width: 1360,\n                    height: 765,\n                },\n                interactive: true,\n                visible: true,\n            },\n            portrait: {\n                interactive: true,\n                visible: false,\n            },\n            landscape: {\n                interactive: true,\n                visible: true,\n            },\n            desktop: {\n                interactive: true,\n                visible: true,\n            },\n        })\n        public lobbySelectionViewLayoutLandscape: DynamicPositionObject<IGraphic> & IGraphic;\n\n        @DefaultValue<IGraphic>({\n            defaults: {\n                beginFill: [0x000000, 0.7],\n                drawRect: {\n                    x: 0,\n                    y: 0,\n                    width: 765,\n                    height: 1360,\n                },\n                interactive: true,\n                visible: true,\n            },\n            portrait: {\n                interactive: true,\n                visible: true,\n            },\n            landscape: {\n                interactive: true,\n                visible: false,\n            },\n            desktop: {\n                interactive: true,\n                visible: false,\n            },\n        })\n        public lobbySelectionViewLayoutPortrait: DynamicPositionObject<IGraphic> & IGraphic;\n    }\n    return HomeButtonComponentConfigurationBlurredInternalClass;\n}\n","import {\n    AddPriority,\n    AssetPriority,\n    AssetsCollection,\n    BaseComponentConfiguration,\n    DefaultAssets,\n    DefaultValue,\n    DynamicPositionObject,\n} from '@egt/core';\nimport { SlotComponents, ZOrders } from '@egt/slot';\nimport { TextAlign } from '@egt/ui-lib';\nimport { IPointData } from 'pixi.js';\nimport { IButtonProps, IGraphic, IRoundGraphic, IText } from '../../../interfaces/HomeButtonInterfaces';\nimport { FooterBackgroundModes } from '@egt/footer-background';\nimport { IHomeButtonComponentConfiguration } from '../../../interfaces/IHomeButtonComponentConfiguration';\n\nexport default class HomeButtonComponentConfigurationDefault extends BaseComponentConfiguration {}\n\nexport function HomeButtonComponentConfigurationFactoryDefault(): any {\n    class HomeButtonComponentConfigurationDefaultInternalClass\n        extends HomeButtonComponentConfigurationDefault\n        implements IHomeButtonComponentConfiguration\n    {\n        public zIndexOff = ZOrders.UI_LEVEL + 1;\n        public zIndexOn = ZOrders.POPUP_LEVEL + 3;\n\n        @DefaultAssets([\n            {\n                id: 'svgHome',\n                url: '../assets/components/slot/home-button/default/ui-svg/home.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                hasDesktopVersion: true,\n                config: {\n                    mobile: { width: 76, height: 76 },\n                    desktop: { width: 32, height: 32 },\n                },\n            },\n            {\n                id: 'svgLobbyPopupClose',\n                url: '../assets/components/slot/home-button/default/ui-svg/lobbyPopupClose.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 76, height: 76 },\n                    desktop: { width: 76, height: 76 },\n                },\n            },\n            {\n                id: 'svgEgtLobbyButton',\n                url: '../assets/components/slot/home-button/common/ui-svg/egtLobbyButton.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                // hasDesktopVersion: true,\n                config: {\n                    mobile: { width: 76, height: 76 },\n                    desktop: { width: 76, height: 76 },\n                },\n            },\n        ])\n        public assets: AssetsCollection;\n\n        @AddPriority<IButtonProps>([\n            {\n                priorityType: { feature: SlotComponents.FOOTER_BACKGROUND, mode: FooterBackgroundModes.BLURRED },\n                priority: 1,\n                value: {\n                    landscape: { x: 36, y: 732 },\n                    portrait: { x: 36, y: 1304 },\n                    desktop: { x: 36, y: 732 },\n                },\n            },\n        ])\n        @DefaultValue<IButtonProps>({\n            defaults: { x: 76.5, y: 699.5, scale: 1, visible: true, textures: ['svgHome'] },\n            portrait: { x: 47, y: 1273 },\n            desktop: { x: 52, y: 747.5 },\n        })\n        public homeButtonPosition: DynamicPositionObject<IButtonProps> & IButtonProps;\n\n        @AddPriority<IPointData>([\n            {\n                priorityType: { feature: SlotComponents.FOOTER_BACKGROUND, mode: FooterBackgroundModes.BLURRED },\n                priority: 1,\n                value: {\n                    landscape: { x: 36, y: 732 },\n                    portrait: { x: 36, y: 1304 },\n                    desktop: { x: 36, y: 732 },\n                },\n            },\n        ])\n        @DefaultValue<IPointData>({\n            defaults: { x: 77, y: 698.5 },\n            portrait: { x: 47, y: 1273 },\n            desktop: { x: 52, y: 747.5 },\n        })\n        public lobbySelectionViewCloseButton: DynamicPositionObject<IPointData> & IPointData;\n\n        // HOME BUTTON\n        @DefaultValue<IRoundGraphic>({\n            defaults: {\n                x: 15,\n                y: 369,\n                beginFill: [0x2e2e2e, 1],\n                drawRect: {\n                    x: 0,\n                    y: 0,\n                    width: 234,\n                    height: 141,\n                    radius: 6,\n                },\n                cursor: 'pointer',\n                interactive: true,\n                visible: true,\n            },\n            portrait: { x: 17, y: 934 },\n            desktop: { x: 35, y: 404 },\n        })\n        public lobbySelectionViewHomeLobbyButtonGraphic: DynamicPositionObject<IRoundGraphic> & IRoundGraphic;\n\n        @DefaultValue<IText>({\n            defaults: {\n                x: 10,\n                y: 469,\n                fontFamily: 'Arial',\n                fontSize: 26,\n                fontWeight: 'bold',\n                fill: '#828282',\n                bounds: {\n                    width: 234,\n                    height: 30,\n                },\n                align: TextAlign.CENTER,\n                shouldFitInBounds: true,\n            },\n            portrait: { x: 17, y: 1034 },\n            desktop: { x: 35, y: 504 },\n        })\n        public lobbySelectionViewHomeText: DynamicPositionObject<IText> & IText;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 90, y: 392 },\n            portrait: { x: 97, y: 950 },\n            desktop: { x: 115, y: 427 },\n        })\n        public lobbySelectionViewHomeLobbyButton: DynamicPositionObject<IPointData> & IPointData;\n\n        // LOBBY BUTTON\n        @DefaultValue<IRoundGraphic>({\n            defaults: {\n                x: 15,\n                y: 522,\n                beginFill: [0x2e2e2e, 1],\n                drawRect: {\n                    x: 0,\n                    y: 0,\n                    width: 234,\n                    height: 141,\n                    radius: 6,\n                },\n                cursor: 'pointer',\n                interactive: true,\n                visible: true,\n            },\n            portrait: { x: 17, y: 1087 },\n            desktop: { x: 35, y: 557 },\n        })\n        public lobbySelectionViewEGTLobbyButtonGraphic: DynamicPositionObject<IRoundGraphic> & IRoundGraphic;\n\n        @DefaultValue<IText>({\n            defaults: {\n                x: 10,\n                y: 624,\n                fontFamily: 'Arial',\n                fontSize: 26,\n                fontWeight: 'bold',\n                fill: '#828282',\n                bounds: {\n                    width: 234,\n                    height: 30,\n                },\n                align: TextAlign.CENTER,\n                shouldFitInBounds: true,\n            },\n            portrait: { x: 17, y: 1189 },\n            desktop: { x: 35, y: 659 },\n        })\n        public lobbySelectionViewLobbyText: DynamicPositionObject<IText> & IText;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 90, y: 540 },\n            portrait: { x: 97, y: 1106 },\n            desktop: { x: 115, y: 575 },\n        })\n        public lobbySelectionViewEGTLobbyButton: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IGraphic>({\n            defaults: {\n                beginFill: [0x000000, 0.7],\n                drawRect: {\n                    x: 0,\n                    y: 0,\n                    width: 1360,\n                    height: 765,\n                },\n                interactive: true,\n                visible: true,\n            },\n            portrait: {\n                interactive: true,\n                visible: false,\n            },\n            landscape: {\n                interactive: true,\n                visible: true,\n            },\n            desktop: {\n                interactive: true,\n                visible: true,\n            },\n        })\n        public lobbySelectionViewLayoutLandscape: DynamicPositionObject<IGraphic> & IGraphic;\n\n        @DefaultValue<IGraphic>({\n            defaults: {\n                beginFill: [0x000000, 0.7],\n                drawRect: {\n                    x: 0,\n                    y: 0,\n                    width: 765,\n                    height: 1360,\n                },\n                interactive: true,\n                visible: true,\n            },\n            portrait: {\n                interactive: true,\n                visible: true,\n            },\n            landscape: {\n                interactive: true,\n                visible: false,\n            },\n            desktop: {\n                interactive: true,\n                visible: false,\n            },\n        })\n        public lobbySelectionViewLayoutPortrait: DynamicPositionObject<IGraphic> & IGraphic;\n    }\n    return HomeButtonComponentConfigurationDefaultInternalClass;\n}\n","import Core, { BaseController, LobbyStyle, AnalyticsDispatcher, UserActionType } from '@egt/core';\nimport { RootStore } from '@egt/slot';\nimport { gsap } from 'gsap';\nimport { fromEvent } from 'rxjs';\nimport { filter, takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport HomeButtonViewDefault from '../views/HomeButtonViewDefault';\nimport { IHomeButtonComponentConfiguration } from '../../../interfaces/IHomeButtonComponentConfiguration';\n\n@injectable()\nexport default class HomeButtonControllerDefault extends BaseController {\n    constructor(\n        @inject('HomeButtonView') protected view: HomeButtonViewDefault,\n        @inject('HomeButtonComponentConfiguration')\n        protected componentConfiguration: IHomeButtonComponentConfiguration,\n        @inject('RootStore') protected rootStore: RootStore,\n    ) {\n        super(view);\n    }\n    public init(): void {\n        this.attachListeners();\n    }\n\n    protected attachListeners(): void {\n        this.rootStore.subjects.KEY_UP.pipe(takeUntil(this.DESTROY)).subscribe(this.onKeyReleased.bind(this));\n\n        this.view\n            .find('homeButton')\n            .CLICK.pipe(\n                filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.onHomeClicked.bind(this));\n\n        this.attachSelectionEventListeners();\n    }\n\n    protected onHomeClicked(): void {\n        if (this.view.homeButton.enabled && !this.rootStore.subjects.DISABLE_MENU_BUTTONS.value) {\n            if (Core.lobbyStore.lobbyStyle === LobbyStyle.COMPLEX) {\n                this.showLobbyButtons();\n            } else {\n                this.onEGTLobbyClicked();\n            }\n            // metrics: track home clicks\n            AnalyticsDispatcher.incrementUserAction(UserActionType.HomeClicked);\n            AnalyticsDispatcher.homeButtonClicked();\n        }\n    }\n\n    protected onEGTLobbyClicked(): void {\n        Core.lobbyStore.operatorLobbyButtonClicked = false;\n        this.hideLobbyButtons();\n\n        if (!Core.configuration.hasPortal || Core.configuration.blockLobby) {\n            Core.EXIT_APPLICATION.next();\n            return;\n        }\n\n        this.rootStore.subjects.CLOSE_ALL_POPUPS.next();\n        Core.UI_BLOCKER.next(true);\n        Core.lobbyStore.showLobby();\n\n        if (Core.configuration.lobbyOpenType === 'fullscreen') {\n            Core.closeGame();\n            // pause the ticker after a little delay to ensure less cpu usage\n            setTimeout(() => gsap.globalTimeline.pause(), 500);\n        }\n    }\n\n    protected showLobbyButtons(): void {\n        if (!this.view.lobbySelectionViewEnabled) {\n            return;\n        }\n        Core.UI_BLOCKER.next(true);\n        this.view.showLobbySectionLayout();\n    }\n\n    protected hideLobbyButtons(): void {\n        if (!this.view.lobbySelectionViewEnabled) {\n            return;\n        }\n\n        this.view.hideLobbySectionLayout();\n        Core.UI_BLOCKER.next(false);\n    }\n\n    protected attachSelectionEventListeners(): void {\n        this.view.lobbySelectionViewCloseButton.CLICK.pipe(\n            filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n            takeUntil(this.DESTROY),\n        ).subscribe(this.hideLobbyButtons.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/home-button/src/egt/modes/default/controllers/HomeButtonControllerDefault.ts:94:9\",(this.view.lobbySelectionViewEGTLobbyButtonGraphic),\"pointertap\"]), fromEvent(this.view.lobbySelectionViewEGTLobbyButtonGraphic, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onEGTLobbyClicked.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/home-button/src/egt/modes/default/controllers/HomeButtonControllerDefault.ts:98:9\",(this.view.lobbySelectionViewHomeLobbyButtonGraphic),\"pointertap\"]), fromEvent(this.view.lobbySelectionViewHomeLobbyButtonGraphic, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onOperatorLobbyButtonClicked.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/home-button/src/egt/modes/default/controllers/HomeButtonControllerDefault.ts:102:9\",(this.view.lobbySelectionViewLayoutPortrait),\"pointertap\"]), fromEvent(this.view.lobbySelectionViewLayoutPortrait, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.hideLobbyButtons.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/home-button/src/egt/modes/default/controllers/HomeButtonControllerDefault.ts:106:9\",(this.view.lobbySelectionViewLayoutLandscape),\"pointertap\"]), fromEvent(this.view.lobbySelectionViewLayoutLandscape, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.hideLobbyButtons.bind(this));\n    }\n\n    protected onOperatorLobbyButtonClicked(): void {\n        Core.lobbyStore.operatorLobbyButtonClicked = true;\n        Core.closeGame();\n        Core.EXIT_APPLICATION.next();\n    }\n\n    protected onKeyReleased(e: KeyboardEvent): void {\n        if (e === null || Core.UI_BLOCKER.value) {\n            return;\n        }\n\n        if ((e.code !== undefined && e.code === 'KeyH') || (e.keyCode !== undefined && e.keyCode === 72)) {\n            if (this.rootStore.subjects.TAB_OPENED.value || this.rootStore.uiStore.SHOW_SETTINGS.value) {\n                this.rootStore.subjects.CLOSE_SETTINGS_POPUP.next();\n                this.rootStore.subjects.RESET_AUTOPLAY_RESTRICTIONS.next();\n                return;\n            }\n\n            if (this.view.find('homeButton').enabled) {\n                this.onHomeClicked();\n            }\n        }\n    }\n}\n","import Core from '@egt/core';\nimport { ISlotConfiguration, RootStore, ServerState, UIState } from '@egt/slot';\nimport { Button, Text, TextConfig, ViewContainer } from '@egt/ui-lib';\nimport { gsap } from 'gsap';\nimport { Graphics, Sprite, TextStyle } from 'pixi.js';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { IHomeButtonComponentConfiguration } from '../../../interfaces/IHomeButtonComponentConfiguration';\n\n@injectable()\nexport default class HomeButtonViewDefault extends ViewContainer {\n    public homeButton: Button;\n    public lobbySelectionView: ViewContainer;\n    public lobbySelectionViewEnabled: boolean = true;\n    public lobbySelectionViewHomeText: Text;\n    public lobbySelectionViewLobbyText: Text;\n    public lobbySelectionViewCloseButton: Button;\n    public lobbySelectionViewEGTLobbyButtonGraphic: Graphics;\n    public lobbySelectionViewEGTLobbyButton: Sprite;\n    public lobbySelectionViewHomeLobbyButtonGraphic: Graphics;\n    public lobbySelectionViewHomeLobbyButton: Sprite;\n    public lobbySelectionViewLayoutLandscape: Graphics;\n    public lobbySelectionViewLayoutPortrait: Graphics;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('HomeButtonComponentConfiguration')\n        protected componentConfiguration: IHomeButtonComponentConfiguration,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n    ) {\n        super();\n        this.name = 'HomeButtonView';\n    }\n\n    public destroy(): void {\n        super.destroy();\n\n        if (this.homeButton) {\n            this.homeButton.destroy();\n            // @ts-ignore\n            this.homeButton = null;\n        }\n\n        if (this.lobbySelectionView) {\n            this.lobbySelectionView.destroy();\n            this.lobbySelectionViewHomeText.destroy();\n            this.lobbySelectionViewLobbyText.destroy();\n            this.lobbySelectionViewCloseButton.destroy();\n            this.lobbySelectionViewEGTLobbyButtonGraphic.destroy();\n            this.lobbySelectionViewEGTLobbyButton.destroy();\n            this.lobbySelectionViewHomeLobbyButtonGraphic.destroy();\n            this.lobbySelectionViewHomeLobbyButton.destroy();\n            this.lobbySelectionViewLayoutLandscape.destroy();\n            this.lobbySelectionViewLayoutPortrait.destroy();\n\n            // @ts-ignore\n            this.lobbySelectionView = null;\n            // @ts-ignore\n            this.lobbySelectionViewHomeText = null;\n            // @ts-ignore\n            this.lobbySelectionViewLobbyText = null;\n            // @ts-ignore\n            this.lobbySelectionViewCloseButton = null;\n            // @ts-ignore\n            this.lobbySelectionViewEGTLobbyButtonGraphic = null;\n            // @ts-ignore\n            this.lobbySelectionViewEGTLobbyButton = null;\n            // @ts-ignore\n            this.lobbySelectionViewHomeLobbyButtonGraphic = null;\n            // @ts-ignore\n            this.lobbySelectionViewHomeLobbyButton = null;\n            // @ts-ignore\n            this.lobbySelectionViewLayoutLandscape = null;\n            // @ts-ignore\n            this.lobbySelectionViewLayoutPortrait = null;\n        }\n    }\n\n    public init(): void {\n        // Attach Subjects\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n        Core.LEFT_HAND_MODE.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n        this.rootStore.uiStore.STATE.pipe(takeUntil(this.DESTROY)).subscribe(this.onStateChanged.bind(this));\n        Core.lobbyStore.LOBBY_INITIALIZED.pipe(takeUntil(this.DESTROY)).subscribe((_v) => {\n            // Check if can enable the lobby/home button\n            this.onStateChanged();\n        });\n        this.zIndex = this.componentConfiguration.zIndexOff;\n\n        // Initialize feature components\n        this.createHomeButton();\n        this.createLobbySelectionLayout();\n        this.setOrientation();\n    }\n\n    public showLobbySectionLayout(): void {\n        if (!this.lobbySelectionViewEnabled) {\n            return;\n        }\n        this.zIndex = this.componentConfiguration.zIndexOn;\n        this.lobbySelectionView.visible = true;\n        this.lobbySelectionViewEnabled = false;\n        this.lobbySelectionViewCloseButton.enabled = false;\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/home-button/src/egt/modes/default/views/HomeButtonViewDefault.ts:104:9\",null]), gsap.to(this.lobbySelectionView, {\n            alpha: 1,\n            duration: 0.3,\n            onComplete: () => {\n                this.lobbySelectionViewEnabled = true;\n                this.lobbySelectionViewCloseButton.enabled = true;\n            },\n        }));\n        this.homeButton.visible = false;\n        this.rootStore.subjects.CLOSE_ALL_POPUPS.next();\n        this.rootStore.subjects.CLOSE_SETTINGS_POPUP.next();\n        this.rootStore.subjects.RESET_AUTOPLAY_RESTRICTIONS.next();\n    }\n\n    public hideLobbySectionLayout(): void {\n        if (!this.lobbySelectionViewEnabled) {\n            return;\n        }\n        this.zIndex = this.componentConfiguration.zIndexOff;\n        this.lobbySelectionView.visible = true;\n        this.lobbySelectionViewEnabled = false;\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/home-button/src/egt/modes/default/views/HomeButtonViewDefault.ts:125:9\",null]), gsap.to(this.lobbySelectionView, {\n            alpha: 0,\n            duration: 0.3,\n            onComplete: () => {\n                this.lobbySelectionView.visible = false;\n                this.lobbySelectionViewEnabled = true;\n            },\n        }));\n        this.homeButton.enabled = true;\n        this.homeButton.visible = true;\n    }\n\n    protected createHomeButton(): void {\n        this.homeButton = new Button([\n            Core.assets.getAsset(this.componentConfiguration.homeButtonPosition.textures[0]).texture,\n        ]);\n        this.homeButton.name = 'homeButton';\n        if (Core.lobbyStore.LOBBY_INITIALIZED.value) {\n            this.homeButton.enabled = true;\n        }\n        this.homeButton.pivot.set(this.homeButton.width / 2, this.homeButton.height / 2);\n        this.addChild(this.homeButton);\n    }\n\n    protected setOrientation(): void {\n        if (!this.homeButton) {\n            return;\n        }\n\n        this.homeButton.x = this.componentConfiguration.homeButtonPosition.x;\n        this.homeButton.y = this.componentConfiguration.homeButtonPosition.y;\n        this.homeButton.scale.set(this.componentConfiguration.homeButtonPosition.scale);\n\n        this.setSelectionButtonsPositions();\n    }\n\n    protected createLobbySelectionLayout(): void {\n        const {\n            lobbySelectionViewHomeLobbyButtonGraphic,\n            lobbySelectionViewEGTLobbyButtonGraphic,\n            lobbySelectionViewLayoutLandscape,\n            lobbySelectionViewLayoutPortrait,\n            lobbySelectionViewHomeText,\n            lobbySelectionViewLobbyText,\n        } = this.componentConfiguration;\n\n        // CONTAINER\n        this.lobbySelectionView = new ViewContainer();\n        this.lobbySelectionView.name = 'lobbySelectionView';\n        this.lobbySelectionView.visible = false;\n        this.lobbySelectionView.alpha = 0;\n\n        const screenWidth = Core.ORIENTATION.value.width;\n        const screenHeight = Core.ORIENTATION.value.height;\n        this.lobbySelectionView.width = screenWidth;\n        this.lobbySelectionView.height = screenHeight;\n        this.lobbySelectionView.x = 0;\n        this.lobbySelectionView.y = 0;\n\n        // BG GRAPHIC LANDSCAPE\n        this.lobbySelectionViewLayoutLandscape = new Graphics();\n        this.lobbySelectionViewLayoutLandscape.beginFill(...lobbySelectionViewLayoutLandscape.beginFill);\n        this.lobbySelectionViewLayoutLandscape.drawRect(\n            lobbySelectionViewLayoutLandscape.drawRect.x,\n            lobbySelectionViewLayoutLandscape.drawRect.y,\n            lobbySelectionViewLayoutLandscape.drawRect.width,\n            lobbySelectionViewLayoutLandscape.drawRect.height,\n        );\n        this.lobbySelectionViewLayoutLandscape.endFill();\n        this.lobbySelectionViewLayoutLandscape.interactive = lobbySelectionViewLayoutLandscape.interactive;\n        this.lobbySelectionViewLayoutLandscape.name = 'layoutLandscape';\n        this.lobbySelectionView.addChild(this.lobbySelectionViewLayoutLandscape);\n\n        // BG GRAPHIC PORTRAIT\n        this.lobbySelectionViewLayoutPortrait = new Graphics();\n        this.lobbySelectionViewLayoutPortrait.beginFill(...lobbySelectionViewLayoutPortrait.beginFill);\n        this.lobbySelectionViewLayoutPortrait.drawRect(\n            lobbySelectionViewLayoutPortrait.drawRect.x,\n            lobbySelectionViewLayoutPortrait.drawRect.y,\n            lobbySelectionViewLayoutPortrait.drawRect.width,\n            lobbySelectionViewLayoutPortrait.drawRect.height,\n        );\n        this.lobbySelectionViewLayoutPortrait.endFill();\n        this.lobbySelectionViewLayoutPortrait.interactive = lobbySelectionViewLayoutPortrait.interactive;\n        this.lobbySelectionViewLayoutPortrait.name = 'layoutPortrait';\n        this.lobbySelectionView.addChild(this.lobbySelectionViewLayoutPortrait);\n\n        // CLOSE BUTTON\n        (this.lobbySelectionViewCloseButton = new Button([Core.assets.getAsset('svgLobbyPopupClose').texture])),\n            (this.lobbySelectionViewCloseButton.name = 'closeButton');\n        this.lobbySelectionViewCloseButton.interactive = true;\n        this.lobbySelectionViewCloseButton.enabled = true;\n        this.lobbySelectionView.addChild(this.lobbySelectionViewCloseButton);\n\n        // EGT BUTTON BG\n        this.lobbySelectionViewEGTLobbyButtonGraphic = new Graphics();\n        this.lobbySelectionViewEGTLobbyButtonGraphic.beginFill(...lobbySelectionViewEGTLobbyButtonGraphic.beginFill);\n        this.lobbySelectionViewEGTLobbyButtonGraphic.drawRoundedRect(\n            lobbySelectionViewEGTLobbyButtonGraphic.drawRect.x,\n            lobbySelectionViewEGTLobbyButtonGraphic.drawRect.y,\n            lobbySelectionViewEGTLobbyButtonGraphic.drawRect.width,\n            lobbySelectionViewEGTLobbyButtonGraphic.drawRect.height,\n            lobbySelectionViewEGTLobbyButtonGraphic.drawRect.radius,\n        );\n        this.lobbySelectionViewEGTLobbyButtonGraphic.endFill();\n        this.lobbySelectionViewEGTLobbyButtonGraphic.cursor = lobbySelectionViewEGTLobbyButtonGraphic.cursor;\n        this.lobbySelectionViewEGTLobbyButtonGraphic.interactive = lobbySelectionViewEGTLobbyButtonGraphic.interactive;\n        this.lobbySelectionViewEGTLobbyButtonGraphic.name = 'egtLobbyPanel';\n        this.lobbySelectionView.addChild(this.lobbySelectionViewEGTLobbyButtonGraphic);\n\n        // EGT BUTTON SPRITE\n        this.lobbySelectionViewEGTLobbyButton = new Sprite(Core.assets.getAsset('svgEgtLobbyButton').texture);\n        this.lobbySelectionViewEGTLobbyButton.name = 'egtLobby';\n        this.lobbySelectionView.addChild(this.lobbySelectionViewEGTLobbyButton);\n\n        // HOME BUTTON BG\n        this.lobbySelectionViewHomeLobbyButtonGraphic = new Graphics();\n        this.lobbySelectionViewHomeLobbyButtonGraphic.beginFill(...lobbySelectionViewHomeLobbyButtonGraphic.beginFill);\n        this.lobbySelectionViewHomeLobbyButtonGraphic.drawRoundedRect(\n            lobbySelectionViewHomeLobbyButtonGraphic.drawRect.x,\n            lobbySelectionViewHomeLobbyButtonGraphic.drawRect.y,\n            lobbySelectionViewHomeLobbyButtonGraphic.drawRect.width,\n            lobbySelectionViewHomeLobbyButtonGraphic.drawRect.height,\n            lobbySelectionViewHomeLobbyButtonGraphic.drawRect.radius,\n        );\n        this.lobbySelectionViewHomeLobbyButtonGraphic.cursor = lobbySelectionViewHomeLobbyButtonGraphic.cursor;\n        this.lobbySelectionViewHomeLobbyButtonGraphic.endFill();\n        this.lobbySelectionViewHomeLobbyButtonGraphic.interactive =\n            lobbySelectionViewHomeLobbyButtonGraphic.interactive;\n        this.lobbySelectionViewHomeLobbyButtonGraphic.name = 'homeLobbyPanel';\n        this.lobbySelectionView.addChild(this.lobbySelectionViewHomeLobbyButtonGraphic);\n\n        // HOME BUTTON SPRITE\n        this.lobbySelectionViewHomeLobbyButton = new Sprite(Core.assets.getAsset('svgExitLobbyButton').texture);\n        this.lobbySelectionViewHomeLobbyButton.name = 'homeLobby';\n        this.lobbySelectionView.addChild(this.lobbySelectionViewHomeLobbyButton);\n\n        // HOME TEXT\n        const textStyleViewHome = new TextStyle({\n            fontFamily: lobbySelectionViewHomeText.fontFamily,\n            fontSize: lobbySelectionViewHomeText.fontSize,\n            fontWeight: lobbySelectionViewHomeText.fontWeight,\n            fill: lobbySelectionViewHomeText.fill,\n        });\n        const textConfigViewHome: TextConfig = new TextConfig();\n        textConfigViewHome.bounds.width = lobbySelectionViewHomeText.bounds.width;\n        textConfigViewHome.bounds.height = Math.floor(lobbySelectionViewHomeText.bounds.height);\n        textConfigViewHome.align = lobbySelectionViewHomeText.align;\n        textConfigViewHome.shouldFitInBounds = lobbySelectionViewHomeText.shouldFitInBounds;\n        this.lobbySelectionViewHomeText = new Text(\n            textConfigViewHome,\n            Core.translator.translate('Exit').toUpperCase(),\n            textStyleViewHome,\n        );\n        this.lobbySelectionView.addChild(this.lobbySelectionViewHomeText);\n\n        // LOBBY TEXT\n        const textStyleViewLobby = new TextStyle({\n            fontFamily: lobbySelectionViewLobbyText.fontFamily,\n            fontSize: lobbySelectionViewLobbyText.fontSize,\n            fontWeight: lobbySelectionViewLobbyText.fontWeight,\n            fill: lobbySelectionViewLobbyText.fill,\n        });\n        const textConfigViewLobby: TextConfig = new TextConfig();\n        textConfigViewLobby.bounds.width = lobbySelectionViewLobbyText.bounds.width;\n        textConfigViewLobby.bounds.height = Math.floor(lobbySelectionViewLobbyText.bounds.height);\n        textConfigViewLobby.align = lobbySelectionViewLobbyText.align;\n        textConfigViewLobby.shouldFitInBounds = lobbySelectionViewLobbyText.shouldFitInBounds;\n        this.lobbySelectionViewLobbyText = new Text(\n            textConfigViewLobby,\n            Core.translator.translate('LOBBY'),\n            textStyleViewLobby,\n        );\n        this.lobbySelectionView.addChild(this.lobbySelectionViewLobbyText);\n\n        // Add the lobbySelectionView to the parent container\n        this.addChild(this.lobbySelectionView);\n    }\n\n    protected setSelectionButtonsPositions(): void {\n        const {\n            lobbySelectionViewCloseButton,\n            lobbySelectionViewHomeLobbyButtonGraphic,\n            lobbySelectionViewEGTLobbyButtonGraphic,\n            lobbySelectionViewHomeText,\n            lobbySelectionViewLobbyText,\n            lobbySelectionViewEGTLobbyButton,\n            lobbySelectionViewHomeLobbyButton,\n            lobbySelectionViewLayoutLandscape,\n            lobbySelectionViewLayoutPortrait,\n        } = this.componentConfiguration;\n\n        // BUTTONS\n        this.lobbySelectionViewCloseButton.x = lobbySelectionViewCloseButton.x;\n        this.lobbySelectionViewCloseButton.y = lobbySelectionViewCloseButton.y;\n        this.lobbySelectionViewCloseButton.scale.set(1);\n        this.lobbySelectionViewCloseButton.pivot.set(\n            this.lobbySelectionViewCloseButton.width / 2,\n            this.lobbySelectionViewCloseButton.height / 2,\n        );\n        this.lobbySelectionViewCloseButton.width = this.homeButton.width;\n        this.lobbySelectionViewCloseButton.height = this.homeButton.height;\n\n        // TEXTS\n        this.lobbySelectionViewHomeText.x = lobbySelectionViewHomeText.x;\n        this.lobbySelectionViewHomeText.y = lobbySelectionViewHomeText.y;\n\n        this.lobbySelectionViewLobbyText.x = lobbySelectionViewLobbyText.x;\n        this.lobbySelectionViewLobbyText.y = lobbySelectionViewLobbyText.y;\n\n        // GRAPHICS\n        this.lobbySelectionViewHomeLobbyButtonGraphic.x = lobbySelectionViewHomeLobbyButtonGraphic.x;\n        this.lobbySelectionViewHomeLobbyButtonGraphic.y = lobbySelectionViewHomeLobbyButtonGraphic.y;\n\n        this.lobbySelectionViewEGTLobbyButtonGraphic.x = lobbySelectionViewEGTLobbyButtonGraphic.x;\n        this.lobbySelectionViewEGTLobbyButtonGraphic.y = lobbySelectionViewEGTLobbyButtonGraphic.y;\n\n        this.lobbySelectionViewLayoutLandscape.visible = lobbySelectionViewLayoutLandscape.visible;\n        this.lobbySelectionViewLayoutPortrait.visible = lobbySelectionViewLayoutPortrait.visible;\n\n        // SPRITES\n        this.lobbySelectionViewEGTLobbyButton.x = lobbySelectionViewEGTLobbyButton.x;\n        this.lobbySelectionViewEGTLobbyButton.y = lobbySelectionViewEGTLobbyButton.y;\n        this.lobbySelectionViewHomeLobbyButton.x = lobbySelectionViewHomeLobbyButton.x;\n        this.lobbySelectionViewHomeLobbyButton.y = lobbySelectionViewHomeLobbyButton.y;\n    }\n\n    protected onStateChanged(): void {\n        if (!this.homeButton) {\n            return;\n        }\n\n        switch (this.rootStore.uiStore.STATE.value) {\n            case UIState.IDLE:\n            case UIState.BONUS_IDLE:\n                if (Core.lobbyStore.LOBBY_INITIALIZED.value) {\n                    this.homeButton.enabled = true;\n                }\n                break;\n            case UIState.UNSET:\n            case UIState.WAITING_FOR_RESPONSE:\n            case UIState.WAITING_FOR_RESPONSE_IN_AUTOPLAY:\n            case UIState.WAITING_FOR_RESPONSE_IN_FREESPIN:\n            case UIState.WAITING_FOR_RESPONSE_IN_RESPIN:\n            case UIState.WIN:\n            case UIState.FREESPIN:\n            case UIState.RESPIN:\n            case UIState.EXIT_FREESPIN:\n            case UIState.BELL_LINK:\n            case UIState.CASH_HEAT:\n            case UIState.GODS_AND_KINGS_LINK:\n            case UIState.BONUS_CHANCE:\n            case UIState.HIGH_CASH_FEATURE:\n            case UIState.MYSTERY:\n            case UIState.PICK_ME_BONUS:\n            case UIState.GAMBLE:\n                this.homeButton.enabled = false;\n                break;\n            case UIState.WAITING_FOR_COLLECT:\n            case UIState.WAITING_FOR_COLLECT_IN_AUTOPLAY:\n                if (\n                    this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT_IN_AUTOPLAY ||\n                    this.rootStore.domainStore.SERVER_STATE.value === ServerState.BONUS_SUMMARY\n                ) {\n                    this.homeButton.enabled = false;\n                } else {\n                    if (Core.lobbyStore.LOBBY_INITIALIZED.value) {\n                        this.homeButton.enabled = true;\n                    }\n                }\n                break;\n        }\n    }\n}\n","import {\n    AddPriority,\n    AssetPriority,\n    AssetsCollection,\n    BaseComponentConfiguration,\n    DefaultAssets,\n    DefaultValue,\n    DynamicPositionObject,\n} from '@egt/core';\nimport { SlotComponents, ZOrders } from '@egt/slot';\nimport { TextAlign } from '@egt/ui-lib';\nimport { IPointData } from 'pixi.js';\nimport { IButtonProps, IGraphic, IRoundGraphic, IText } from '../../../interfaces/HomeButtonInterfaces';\nimport { FooterBackgroundModes } from '@egt/footer-background';\nimport { IHomeButtonComponentConfiguration } from '../../../interfaces/IHomeButtonComponentConfiguration';\n\nexport default class HomeButtonComponentConfigurationSided extends BaseComponentConfiguration {}\n\nexport function HomeButtonComponentConfigurationFactorySided(): any {\n    class HomeButtonComponentConfigurationSidedInternalClass\n        extends HomeButtonComponentConfigurationSided\n        implements IHomeButtonComponentConfiguration\n    {\n        public zIndexOff = ZOrders.UI_LEVEL + 1;\n        public zIndexOn = ZOrders.POPUP_LEVEL + 3;\n\n        @DefaultAssets([\n            {\n                id: 'svgHome',\n                url: '../assets/components/slot/home-button/sided/ui-svg/home.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                hasDesktopVersion: true,\n                config: {\n                    mobile: { width: 65, height: 65 },\n                    desktop: { width: 50, height: 50 },\n                },\n            },\n            {\n                id: 'svgLobbyPopupClose',\n                url: '../assets/components/slot/home-button/sided/ui-svg/lobbyPopupClose.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 65, height: 65 },\n                    desktop: { width: 50, height: 50 },\n                },\n            },\n            {\n                id: 'svgEgtLobbyButton',\n                url: '../assets/components/slot/home-button/common/ui-svg/egtLobbyButton.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                // hasDesktopVersion: true,\n                config: {\n                    mobile: { width: 76, height: 76 },\n                    desktop: { width: 76, height: 76 },\n                },\n            },\n        ])\n        public assets: AssetsCollection;\n\n        @AddPriority<IButtonProps>([\n            {\n                priorityType: { feature: SlotComponents.FOOTER_BACKGROUND, mode: FooterBackgroundModes.BLURRED },\n                priority: 1,\n                value: {\n                    landscape: { x: 36, y: 732 },\n                    portrait: { x: 36, y: 1304 },\n                    desktop: { x: 36, y: 732 },\n                },\n            },\n        ])\n        @DefaultValue<IButtonProps>({\n            defaults: { x: 76.5, y: 699.5, scale: 1, visible: true, textures: ['svgHome'] },\n            portrait: { x: 47, y: 1273 },\n            desktop: { x: 52, y: 747.5 },\n        })\n        public homeButtonPosition: DynamicPositionObject<IButtonProps> & IButtonProps;\n\n        @AddPriority<IPointData>([\n            {\n                priorityType: { feature: SlotComponents.FOOTER_BACKGROUND, mode: FooterBackgroundModes.BLURRED },\n                priority: 1,\n                value: {\n                    landscape: { x: 36, y: 732 },\n                    portrait: { x: 36, y: 1304 },\n                    desktop: { x: 36, y: 732 },\n                },\n            },\n        ])\n        @DefaultValue<IPointData>({\n            defaults: { x: 77, y: 698.5 },\n            portrait: { x: 47, y: 1273 },\n            desktop: { x: 52, y: 747.5 },\n        })\n        public lobbySelectionViewCloseButton: DynamicPositionObject<IPointData> & IPointData;\n\n        // HOME BUTTON\n        @DefaultValue<IRoundGraphic>({\n            defaults: {\n                x: 15,\n                y: 369,\n                beginFill: [0x2e2e2e, 1],\n                drawRect: {\n                    x: 0,\n                    y: 0,\n                    width: 234,\n                    height: 141,\n                    radius: 6,\n                },\n                cursor: 'pointer',\n                interactive: true,\n                visible: true,\n            },\n            portrait: { x: 17, y: 934 },\n            desktop: { x: 35, y: 404 },\n        })\n        public lobbySelectionViewHomeLobbyButtonGraphic: DynamicPositionObject<IRoundGraphic> & IRoundGraphic;\n\n        @DefaultValue<IText>({\n            defaults: {\n                x: 10,\n                y: 469,\n                fontFamily: 'Arial',\n                fontSize: 26,\n                fontWeight: 'bold',\n                fill: '#828282',\n                bounds: {\n                    width: 234,\n                    height: 30,\n                },\n                align: TextAlign.CENTER,\n                shouldFitInBounds: true,\n            },\n            portrait: { x: 17, y: 1034 },\n            desktop: { x: 35, y: 504 },\n        })\n        public lobbySelectionViewHomeText: DynamicPositionObject<IText> & IText;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 90, y: 392 },\n            portrait: { x: 97, y: 950 },\n            desktop: { x: 115, y: 427 },\n        })\n        public lobbySelectionViewHomeLobbyButton: DynamicPositionObject<IPointData> & IPointData;\n\n        // LOBBY BUTTON\n        @DefaultValue<IRoundGraphic>({\n            defaults: {\n                x: 15,\n                y: 522,\n                beginFill: [0x2e2e2e, 1],\n                drawRect: {\n                    x: 0,\n                    y: 0,\n                    width: 234,\n                    height: 141,\n                    radius: 6,\n                },\n                cursor: 'pointer',\n                interactive: true,\n                visible: true,\n            },\n            portrait: { x: 17, y: 1087 },\n            desktop: { x: 35, y: 557 },\n        })\n        public lobbySelectionViewEGTLobbyButtonGraphic: DynamicPositionObject<IRoundGraphic> & IRoundGraphic;\n\n        @DefaultValue<IText>({\n            defaults: {\n                x: 10,\n                y: 624,\n                fontFamily: 'Arial',\n                fontSize: 26,\n                fontWeight: 'bold',\n                fill: '#828282',\n                bounds: {\n                    width: 234,\n                    height: 30,\n                },\n                align: TextAlign.CENTER,\n                shouldFitInBounds: true,\n            },\n            portrait: { x: 17, y: 1189 },\n            desktop: { x: 35, y: 659 },\n        })\n        public lobbySelectionViewLobbyText: DynamicPositionObject<IText> & IText;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 90, y: 540 },\n            portrait: { x: 97, y: 1106 },\n            desktop: { x: 115, y: 575 },\n        })\n        public lobbySelectionViewEGTLobbyButton: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IGraphic>({\n            defaults: {\n                beginFill: [0x000000, 0.7],\n                drawRect: {\n                    x: 0,\n                    y: 0,\n                    width: 1360,\n                    height: 765,\n                },\n                interactive: true,\n                visible: true,\n            },\n            portrait: {\n                interactive: true,\n                visible: false,\n            },\n            landscape: {\n                interactive: true,\n                visible: true,\n            },\n            desktop: {\n                interactive: true,\n                visible: true,\n            },\n        })\n        public lobbySelectionViewLayoutLandscape: DynamicPositionObject<IGraphic> & IGraphic;\n\n        @DefaultValue<IGraphic>({\n            defaults: {\n                beginFill: [0x000000, 0.7],\n                drawRect: {\n                    x: 0,\n                    y: 0,\n                    width: 765,\n                    height: 1360,\n                },\n                interactive: true,\n                visible: true,\n            },\n            portrait: {\n                interactive: true,\n                visible: true,\n            },\n            landscape: {\n                interactive: true,\n                visible: false,\n            },\n            desktop: {\n                interactive: true,\n                visible: false,\n            },\n        })\n        public lobbySelectionViewLayoutPortrait: DynamicPositionObject<IGraphic> & IGraphic;\n    }\n    return HomeButtonComponentConfigurationSidedInternalClass;\n}\n","import { BaseComponent, IModeConfig } from '@egt/core';\nimport { SlotComponents, ZOrders } from '@egt/slot';\nimport { Lifecycle } from 'tsyringe';\nimport { ReelsComponentConfigurationFactoryDefault } from './modes/default/configuration/ReelsComponentConfigurationDefault';\nimport { ReelsComponentConfigurationFactoryDesktopForLandscape } from './modes/desktopForLandscape/configuration/ReelsComponentConfigurationDesktopForLandscape';\nimport ReelsModesConfigurations, { ReelsModes } from './ReelsModeFactory';\n\nexport default class ReelsComponent extends BaseComponent {\n    public static configurationName = 'ReelsComponent';\n\n    public reelsView: any;\n    public componentType = SlotComponents.REELS;\n    public configuration: any;\n    public rootView: any;\n    public reelsController: any;\n\n    constructor(modeConfigOrFactory?: IModeConfig | ((ClassType?: any) => any)) {\n        super();\n        const baseConfigs = {\n            [ReelsModes.DEFAULT]: ReelsComponentConfigurationFactoryDefault,\n            [ReelsModes.DESKTOP_FOR_LANDSCAPE]: ReelsComponentConfigurationFactoryDesktopForLandscape,\n        };\n\n        // Support the old config-factory style for backward compatibility\n        let modeConfig: IModeConfig = {};\n        if (typeof modeConfigOrFactory === 'function') {\n            modeConfig = {\n                modeType: ReelsModes.DEFAULT,\n                configuration: { [ReelsModes.DEFAULT]: modeConfigOrFactory },\n            };\n        } else if (modeConfigOrFactory) {\n            modeConfig = modeConfigOrFactory;\n        }\n\n        this.modeFactory = this.initMode<ReelsModesConfigurations>(modeConfig, {\n            defaultModeType: ReelsModes.DEFAULT,\n            baseConfigs,\n            defaultFactory: ReelsModesConfigurations,\n        });\n    }\n\n    public destroy(): void {\n        this.reelsController.destroy();\n        // @ts-ignore\n        this.reelsController = null;\n        // @ts-ignore\n        this.reelsView = null;\n\n        // @ts-ignore\n        this.rootView = null;\n\n        this.configuration.destroy();\n        // @ts-ignore\n        this.configuration = null;\n\n        super.destroy();\n    }\n\n    public onAfterGameConfigurationCreated(): void {\n        super.onAfterGameConfigurationCreated();\n        this.configuration = this.dependencyContainer.resolve('ReelsComponentConfiguration');\n    }\n\n    public onRegisterDependencies(container: any): void {\n        super.onRegisterDependencies(container);\n\n        // if (!this.dependencyContainer.isRegistered('ReelsView')) {\n        this.dependencyContainer.register(\n            'ReelsView',\n            { useClass: this.mode.view },\n            { lifecycle: Lifecycle.Singleton },\n        );\n        // }\n\n        // if (!this.dependencyContainer.isRegistered('IReels')) {\n        this.dependencyContainer.register(\n            'IReels',\n            { useClass: this.mode.controller },\n            { lifecycle: Lifecycle.Singleton },\n        );\n        // }\n\n        this.dependencyContainer.register(\n            'ReelsComponentConfiguration',\n            { useClass: this.mode.configuration },\n            { lifecycle: Lifecycle.Singleton },\n        );\n    }\n\n    public onRegisterDesktopDependencies(container: any): void {\n        super.onRegisterDesktopDependencies(container);\n\n        if (this.mode.desktopView) {\n            this.dependencyContainer.register(\n                'ReelsView',\n                { useClass: this.mode.desktopView },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n    }\n\n    public onResolveDependencies(container: any): void {\n        super.onResolveDependencies(container);\n\n        this.rootView = this.dependencyContainer.resolve('RootView');\n        this.reelsView = this.dependencyContainer.resolve('ReelsView');\n        this.reelsView.zIndex = ZOrders.REELS_LEVEL;\n        this.rootView.addChild(this.reelsView);\n        this.reelsController = this.dependencyContainer.resolve('IReels');\n    }\n\n    public onInit(): void {\n        this.reelsController.init();\n        this.reelsView.init();\n    }\n\n    public onInitComplete(): void {\n        this.reelsController.initComplete();\n    }\n}\n","import { BaseModesConfigurations, IForceSetConfig, IModes } from '@egt/core';\nimport { ReelsComponentConfigurationFactoryDefault } from './modes/default/configuration/ReelsComponentConfigurationDefault';\nimport ReelsControllerDefault from './modes/default/controllers/ReelsControllerDefault';\nimport ReelsViewDefault from './modes/default/views/ReelsViewDefault';\nimport { ReelsComponentConfigurationFactoryDesktopForLandscape } from './modes/desktopForLandscape/configuration/ReelsComponentConfigurationDesktopForLandscape';\nimport ReelsControllerDesktopForLandscape from './modes/desktopForLandscape/controllers/ReelsControllerDesktopForLandscape';\nimport ReelsViewDesktopForLandscape from './modes/desktopForLandscape/views/ReelsViewDesktopForLandscape';\nimport ReelsViewDesktopDesktopForLandscape from './modes/desktopForLandscape/views/ReelsViewDesktopDesktopForLandscape';\nimport ReelsViewDesktopDefault from './modes/default/views/ReelsViewDesktopDefault';\n\nexport default class ReelsModesConfigurations extends BaseModesConfigurations<ReelsModes> {\n    constructor(modeType: ReelsModes, forceSetConfig?: IForceSetConfig) {\n        super(modeType, forceSetConfig);\n    }\n\n    protected createBaseModesConfig(modeType: ReelsModes): IModes {\n        switch (modeType) {\n            case ReelsModes.DESKTOP_FOR_LANDSCAPE:\n                return {\n                    controller: ReelsControllerDesktopForLandscape,\n                    view: ReelsViewDesktopForLandscape,\n                    desktopView: ReelsViewDesktopDesktopForLandscape,\n                    configuration: ReelsComponentConfigurationFactoryDesktopForLandscape(),\n                };\n            default:\n                return {\n                    controller: ReelsControllerDefault,\n                    view: ReelsViewDefault,\n                    desktopView: ReelsViewDesktopDefault,\n                    configuration: ReelsComponentConfigurationFactoryDefault(),\n                };\n        }\n    }\n}\n\nexport enum ReelsModes {\n    DEFAULT = 'default',\n    DESKTOP_FOR_LANDSCAPE = 'desktopForLandscape',\n    // BELL_LINK = 'bellLink',\n    // BELL_LINK_DESKTOP_FOR_LANDSCAPE = 'desktopForLandscape',\n}\n","import ReelsComponent from './ReelsComponent';\nimport { IReelsComponentConfigurationDefault } from './modes/default/configuration/IReelsComponentConfigurationDefault';\nimport ReelsComponentConfigurationDefault, {\n    ReelsComponentConfigurationFactoryDefault,\n} from './modes/default/configuration/ReelsComponentConfigurationDefault';\nimport ReelsControllerDefault from './modes/default/controllers/ReelsControllerDefault';\nimport ReelStateDefault from './modes/default/enums/ReelStateDefault';\nimport { IReelPositionDefault } from './modes/default/interfaces/IReelPositionDefault';\nimport { IReelsDefault } from './modes/default/interfaces/IReelsDefault';\nimport { IReelsViewDefault } from './modes/default/interfaces/IReelsViewDefault';\nimport ReelDefault from './modes/default/views/ReelDefault';\nimport ReelsViewDefault from './modes/default/views/ReelsViewDefault';\nimport ReelsViewDesktopDefault from './modes/default/views/ReelsViewDesktopDefault';\nimport { IReelsComponentConfigurationDesktopForLandscape } from './modes/desktopForLandscape/configuration/IReelsComponentConfigurationDesktopForLandscape';\nimport { IReelsViewDesktopForLandscape } from './modes/desktopForLandscape/interfaces/IReelsViewDesktopForLandscape';\nimport ReelsComponentConfigurationDesktopForLandscape, {\n    ReelsComponentConfigurationFactoryDesktopForLandscape,\n} from './modes/desktopForLandscape/configuration/ReelsComponentConfigurationDesktopForLandscape';\nimport ReelsControllerDesktopForLandscape from './modes/desktopForLandscape/controllers/ReelsControllerDesktopForLandscape';\nimport ReelDesktopForLandscape from './modes/desktopForLandscape/views/ReelDesktopForLandscape';\nimport ReelsViewDesktopForLandscape from './modes/desktopForLandscape/views/ReelsViewDesktopForLandscape';\nimport ReelsViewDesktopDesktopForLandscape from './modes/desktopForLandscape/views/ReelsViewDesktopDesktopForLandscape';\nimport ReelsModesConfigurations, { ReelsModes } from './ReelsModeFactory';\nimport { IReelPositionDesktopForLandscape } from './modes/desktopForLandscape/interfaces/IReelPositionDesktopForLandscape';\n\n// New-architecture named exports\nexport {\n    ReelsModes,\n    ReelsModesConfigurations,\n    IReelsDefault,\n    IReelsViewDefault,\n    ReelDefault,\n    ReelsControllerDefault,\n    ReelStateDefault,\n    ReelsViewDefault,\n    ReelsViewDesktopDefault,\n    IReelsComponentConfigurationDefault,\n    ReelsComponentConfigurationDefault,\n    ReelsComponentConfigurationFactoryDefault,\n    IReelPositionDefault,\n    // desktopForLandscape mode\n    IReelsComponentConfigurationDesktopForLandscape,\n    IReelsViewDesktopForLandscape,\n    IReelPositionDesktopForLandscape,\n    ReelsComponentConfigurationDesktopForLandscape,\n    ReelsComponentConfigurationFactoryDesktopForLandscape,\n    ReelsControllerDesktopForLandscape,\n    ReelDesktopForLandscape,\n    ReelsViewDesktopForLandscape,\n    ReelsViewDesktopDesktopForLandscape,\n};\n\n// Backward-compatible aliases (old names still work)\nexport {\n    // ReelDefault as Reel,\n};\n\nexport default ReelsComponent;\n","import { BaseComponentConfiguration, DefaultValue, DynamicPositionObject } from '@egt/core';\nimport { IReelPositionDefault } from '../interfaces/IReelPositionDefault';\nimport { IReelsComponentConfigurationDefault } from './IReelsComponentConfigurationDefault';\n\nexport default class ReelsComponentConfigurationDefault extends BaseComponentConfiguration {}\n\nexport function ReelsComponentConfigurationFactoryDefault(\n    ClassType: typeof ReelsComponentConfigurationDefault = ReelsComponentConfigurationDefault,\n): typeof ReelsComponentConfigurationDefault {\n    class InternalReelsComponentConfigurationDefault extends ClassType implements IReelsComponentConfigurationDefault {\n        @DefaultValue<IReelPositionDefault>({\n            defaults: {\n                reelX: 3,\n                reelY: 272,\n                reelWidth: 193,\n                reelHeight: 579,\n                symbolWidth: 193,\n                symbolHeight: 193,\n                symbolResolution: 1,\n                reelSpacing: 22,\n                scale: 1.389,\n                symbolScale: 1,\n                threeDimentionalRadiusesPerReels: [],\n            },\n            landscape: {\n                reelX: 153,\n                reelY: 77,\n                scale: 1,\n            },\n            desktop: {\n                reelX: 180,\n                reelY: 86,\n                scale: 1,\n                symbolScale: 0.9326,\n            },\n        })\n        public reelsPosition: DynamicPositionObject<IReelPositionDefault> & IReelPositionDefault;\n        public numberOfReels: number = 5;\n        public visibleSymbolsPerReel: number = 3;\n        public portraitFirst: boolean = false;\n        public portraitScale: number = 0.72;\n        public useReelStopEffectAnim: boolean = false;\n\n        public initialReels: number[][] = [\n            [1, 1, 1, 1, 1, 1, 1, 1],\n            [2, 2, 2, 2, 2, 2, 2, 2],\n            [3, 3, 3, 3, 3, 3, 3, 3],\n            [4, 4, 4, 4, 4, 4, 4, 4],\n            [5, 5, 5, 5, 5, 5, 5, 5],\n            [6, 6, 6, 6, 6, 6, 6, 6],\n        ];\n        public useBlurredReels: boolean = false;\n        public transparentReels: boolean = false;\n        public reelStartBounceTime: number = 0;\n\n        public reelStopBounceTime: number = 0.3;\n        public reelStopBouncePercent: number = 30;\n        public reelRotationSpeed: number = 55;\n        public reelRotationDirection: number = -1;\n        public reelsMinimumSpinTime: number = 0;\n        public gameInitialReelRotationTime: number = 340;\n        public gameInitialReelRotationTimeInQuickSpin: number = 250;\n        public gameBetweenReelsDelay: number = 320;\n        public gameBetweenReelsDelayInQuickSpin: number = 150;\n        public minTimeReelsPercentDelay: number = 50;\n        public gameAnticipationReelsDelay: number = 2050;\n        public numberOfGuardSymbols: number = 2;\n        public delayBeforeStopAllIsCalledInTurbo: number = 133;\n\n        public fakeReels: number[][];\n        public respinFakeReels: number[][];\n        public freeSpinFakeReels: number[][];\n        public buyBonusFakeReels: number[][];\n        public multiReelsFakeReels: number[][];\n    }\n\n    return InternalReelsComponentConfigurationDefault;\n}\n","import Core, { AnalyticsDispatcher, BaseController, IErrorData, PostMessageDispatcher, Timers } from '@egt/core';\nimport {\n    BetResponse,\n    ISlotConfiguration,\n    ISymbol,\n    InitialSettings,\n    RootStore,\n    SpinAnalyzer,\n    SymbolBase,\n} from '@egt/slot';\nimport { BaseTexture, Texture } from 'pixi.js';\nimport { BehaviorSubject, from, merge, of, Subject, zip } from 'rxjs';\nimport { concatMap, delay, first, map, switchMap, take, takeUntil, toArray } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { IReelsComponentConfigurationDefault } from '../configuration/IReelsComponentConfigurationDefault';\nimport { IReelsDefault } from '../interfaces/IReelsDefault';\nimport { IReelsViewDefault } from '../interfaces/IReelsViewDefault';\nimport ReelDefault from '../views/ReelDefault';\n\n@injectable()\nexport default class ReelsControllerDefault extends BaseController implements IReelsDefault {\n    protected get areReelsRotating(): boolean {\n        for (let i = 0; i < this.rotatingReelsMap.size; i++) {\n            if (this.rotatingReelsMap.get(i)) {\n                return true;\n            }\n        }\n        return false;\n    }\n    protected scattersCount: number = 0;\n    protected stopAllRequested: boolean = false;\n    protected mainSoundsLoaded: boolean = false;\n    protected reelsTimings: number[] = [];\n    protected reels: ReelDefault[] = [];\n    protected reelsStopSounds: string[] = [];\n    protected reelsToStart: number[] = [];\n    protected PREPARE_REEL_ACCELERATION: Subject<number> = new Subject();\n\n    protected isResultReceived: boolean;\n    protected rotatingReelsMap = new Map<number, boolean>();\n    private updateCbk: () => void;\n    protected lastStartedReel: number;\n\n    constructor(\n        @inject('ReelsView') protected view: IReelsViewDefault,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('SpinAnalyzer') protected spinAnalyzer: SpinAnalyzer,\n        @inject('ReelsComponentConfiguration') protected componentConfiguration: IReelsComponentConfigurationDefault,\n        @inject('InitialSettings') protected settings: InitialSettings,\n    ) {\n        super(view);\n    }\n\n    public init(): void {\n        this.rootStore.subjects.FAKE_REELS.next(this.componentConfiguration.fakeReels);\n        this.rootStore.subjects.RESPIN_FAKE_REELS.next(this.componentConfiguration.respinFakeReels);\n        this.rootStore.subjects.FREE_SPINS_FAKE_REELS.next(this.componentConfiguration.freeSpinFakeReels);\n        this.rootStore.subjects.REELS_POSITION = new BehaviorSubject(this.componentConfiguration.reelsPosition);\n        this.rootStore.subjects.PORTRAIT_FIRST.next(this.componentConfiguration.portraitFirst);\n        this.rootStore.subjects.NUMBER_OF_REELS.next(this.componentConfiguration.numberOfReels);\n        this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.next(this.componentConfiguration.visibleSymbolsPerReel);\n        this.rootStore.subjects.TRANSPARENT_REELS.next(this.componentConfiguration.transparentReels);\n        this.rootStore.subjects.REEL_START_BOUNCE_TIME.next(this.componentConfiguration.reelStartBounceTime);\n        this.rootStore.subjects.REEL_STOP_BOUNCE_TIME.next(this.componentConfiguration.reelStopBounceTime);\n        this.rootStore.subjects.REEL_STOP_BOUNCE_PERCENT.next(this.componentConfiguration.reelStopBouncePercent);\n        this.rootStore.subjects.REEL_ROTATION_SPEED.next(this.componentConfiguration.reelRotationSpeed);\n        this.rootStore.subjects.REEL_ROTATION_DIRECTION.next(this.componentConfiguration.reelRotationDirection);\n        this.rootStore.subjects.GAME_INITIAL_REEL_ROTATION_TIME.next(\n            this.componentConfiguration.gameInitialReelRotationTime,\n        );\n        this.rootStore.subjects.GAME_INITIAL_REEL_ROTATION_TIME_IN_QUICK_SPIN.next(\n            this.componentConfiguration.gameInitialReelRotationTimeInQuickSpin,\n        );\n        this.rootStore.subjects.GAME_BETWEEN_REELS_DELAY.next(this.componentConfiguration.gameBetweenReelsDelay);\n        this.rootStore.subjects.GAME_BETWEEN_REELS_DELAY_IN_QUICK_SPIN.next(\n            this.componentConfiguration.gameBetweenReelsDelayInQuickSpin,\n        );\n        this.rootStore.subjects.MIN_TIME_REELS_PERCENT_DELAY.next(this.componentConfiguration.minTimeReelsPercentDelay);\n        this.rootStore.subjects.GAME_ANTICIPATION_REELS_DELAY.next(\n            this.componentConfiguration.gameAnticipationReelsDelay,\n        );\n        this.rootStore.subjects.NUMBER_OF_GUARD_SYMBOLS.next(this.componentConfiguration.numberOfGuardSymbols);\n        this.rootStore.subjects.PORTRAIT_SCALE.next(this.componentConfiguration.portraitScale);\n        // Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.onOrientationChanged.bind(this));\n\n        this.createSymbols();\n        this.initialReelSettings();\n        this.rootStore.uiStore.FAKE_REELS.next(this.componentConfiguration.fakeReels);\n        this.rootStore.uiStore.REAL_REELS.next(this.settings.reels);\n    }\n\n    public initComplete(): void {\n        this.reels = this.view.reels;\n\n        for (let i = 0; i < this.rootStore.subjects.NUMBER_OF_REELS.value; i++) {\n            this.reels[i].STOPPED.pipe(takeUntil(this.DESTROY)).subscribe(this.onReelStopped.bind(this));\n            this.reels[i].BOUNCED.pipe(takeUntil(this.DESTROY)).subscribe(this.onReelBounced.bind(this));\n            this.rotatingReelsMap.set(i, false);\n            this.reelsTimings[i] = 0;\n            this.reelsStopSounds[i] = '';\n            this.reelsToStart[i] = i;\n        }\n\n        this.rootStore.subjects.SPIN_STARTED.pipe(takeUntil(this.DESTROY)).subscribe(this.start.bind(this));\n\n        this.rootStore.subjects.SPIN_STARTED_WITHOUT_NEW_REQUEST.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.startWithoutNewRequest.bind(this),\n        );\n\n        this.rootStore.subjects.CLEAR_CELLS.pipe(takeUntil(this.DESTROY)).subscribe(this.clearReels.bind(this));\n\n        this.rootStore.subjects.SHOW_CELLS.pipe(takeUntil(this.DESTROY)).subscribe(this.showReels.bind(this));\n\n        this.rootStore.subjects.TINT_REELS.pipe(takeUntil(this.DESTROY)).subscribe(this.onTintReels.bind(this));\n\n        Core.SHOW_ERROR.pipe(takeUntil(this.DESTROY)).subscribe(this.onErrorWithInsifitionsFunds.bind(this));\n\n        this.rootStore.uiStore.REAL_REELS.pipe(takeUntil(this.DESTROY)).subscribe(this.onReelsChanged.bind(this));\n        this.rootStore.subjects.REDRAW_REELS.pipe(takeUntil(this.DESTROY)).subscribe(this.redrawReels.bind(this));\n\n        this.PREPARE_REEL_ACCELERATION.pipe(takeUntil(this.DESTROY)).subscribe(this.prepareReelAcceleration.bind(this));\n\n        this.updateCbk = this.update.bind(this);\n\n        Core.stage.ticker.add(this.updateCbk, this);\n    }\n\n    public destroy(): void {\n        this.stopAllRequested = true;\n        this.rootStore.subjects.REELS_FORCE_STOP.next(true);\n        Core.stage.ticker.remove(this.updateCbk, this);\n        // @ts-ignore\n        delete this.reels;\n        // @ts-ignore\n        delete this.view;\n        super.destroy.apply(this, arguments);\n    }\n\n    public update(): void {\n        for (const reel of this.reels) {\n            reel.draw(Core.stage.ticker.deltaMS);\n        }\n    }\n\n    public start(startConfig?: any): void {\n        if (this.areReelsRotating) {\n            return;\n        }\n        this.rootStore.subjects.ARE_REELS_ROTATING.next(true);\n        PostMessageDispatcher.reelsStarted();\n        AnalyticsDispatcher.onSpinStarted({\n            orientation: String(Core.ORIENTATION.value.orientation).toLowerCase(),\n            desktop: Core.isDesktopMode,\n            spinMode: this.rootStore.domainStore.SPIN_MODE.value,\n        });\n\n        if (startConfig && startConfig.reelsToStart) {\n            this.lastStartedReel = startConfig.reelsToStart[startConfig.reelsToStart.length - 1];\n        } else {\n            this.lastStartedReel = this.rootStore.subjects.NUMBER_OF_REELS.value - 1;\n        }\n        this.mainSoundsLoaded = this.mainSoundsLoaded || Core.sounds.soundAssetLoaded('mainSounds');\n        this.isResultReceived = false;\n        this.stopAllRequested = false;\n        this.rootStore.subjects.REELS_FORCE_STOP.next(false);\n        this.rootStore.subjects.REELS_START.next();\n        this.rootStore.domainStore.BET.pipe(first()).subscribe(this.onBetChanged.bind(this));\n\n        const waitForInitialRotationTime = from(\n            startConfig?.reelsToStart ? (startConfig.reelsToStart as number[]) : this.reelsToStart,\n        ).pipe(\n            map((index) => {\n                this.reels[index].start();\n\n                this.rotatingReelsMap.set(index, true);\n                return index;\n            }),\n            toArray(),\n            delay(this.initialRotationTime(startConfig)),\n        );\n\n        // Create Stop All Stream\n        const stopAllStream = zip(\n            waitForInitialRotationTime,\n            this.rootStore.domainStore.BET,\n            this.rootStore.subjects.REELS_STOP_ALL,\n        ).pipe(takeUntil(this.rootStore.subjects.REELS_STOPPED));\n\n        zip(waitForInitialRotationTime, this.rootStore.domainStore.BET)\n            .pipe(\n                switchMap(() =>\n                    from(startConfig?.reelsToStart ? (startConfig.reelsToStart as number[]) : this.reelsToStart),\n                ),\n                concatMap((reelIndex) => {\n                    if (\n                        !this.rootStore.subjects.REEL_ACCELERATE_DISBALED.value &&\n                        this.shouldReelAccelerate(startConfig, reelIndex)\n                    ) {\n                        this.PREPARE_REEL_ACCELERATION.next(reelIndex);\n                    }\n                    this.reelStartStopping(reelIndex);\n                    return of(reelIndex).pipe(\n                        delay(\n                            startConfig?.reelsTimings\n                                ? startConfig.reelsTimings[reelIndex]\n                                : this.reelsTimings[reelIndex],\n                        ),\n                    );\n                }),\n                takeUntil(merge(this.rootStore.subjects.REELS_STOPPED, this.DESTROY, stopAllStream)),\n            )\n            .subscribe(this.onStopReelTimer.bind(this));\n\n        this.subscribeToStopAllStream(stopAllStream, startConfig);\n\n        if (this.rootStore.uiStore.turboModeEnabled && !this.rootStore.uiStore.disableSpecialSpinSpeedForCurrentState) {\n            Timers.setTimeout(() => {\n                this.stopAll();\n            }, this.componentConfiguration.delayBeforeStopAllIsCalledInTurbo);\n        }\n    }\n\n    public startWithoutNewRequest(startConfig?: any): void {\n        if (startConfig?.reelsToStart) {\n            (startConfig.reelsToStart as number[]).map((index) => {\n                this.reels[index].start();\n\n                this.rotatingReelsMap.set(index, true);\n                return index;\n            });\n        }\n    }\n\n    public onTintReels(tint: boolean): void {\n        this.reels.forEach((reel) => {\n            reel.tintAllCells(tint);\n        });\n    }\n\n    public stopAll(): void {\n        if (!this.areReelsRotating) {\n            return;\n        }\n\n        if (this.isResultReceived) {\n            // align all unstopped reels to a single offset, so they'll stop at once\n            const offset =\n                this.rootStore.subjects.REELS_POSITION.value.reelHeight / this.slotConfiguration.numberOfGameSymbols;\n            const length = this.reels.length;\n            for (let i = 0; i < length; i++) {\n                if (this.componentConfiguration.useReelStopEffectAnim && this.reels[i].getState() === 2) {\n                    this.view.showReelStopEffect(i);\n                }\n                this.reels[i].stop(offset);\n            }\n        }\n\n        this.stopAllRequested = true;\n        this.rootStore.subjects.REELS_FORCE_STOP.next(true);\n    }\n\n    public onBetChanged(betResponse: BetResponse): void {\n        this.rootStore.uiStore.REAL_REELS.next(betResponse.reels.slice().map((a) => a.slice()));\n        this.calculateReelTimings(betResponse);\n        this.getSoundsForReels(betResponse);\n        this.resultReceived();\n    }\n\n    public resultReceived(): void {\n        this.isResultReceived = true;\n        if (this.stopAllRequested) {\n            this.stopAll();\n        }\n    }\n\n    public getSoundsForReels(betResponse: BetResponse): void {\n        this.scattersCount = 0;\n        from(betResponse.reels.slice().map((a) => a.slice()))\n            .pipe(\n                map((reel, index) => {\n                    this.scattersCount += this.countFSScatterOnReel(reel);\n                    if (this.spinAnalyzer.shouldPlayWildStopSound(index)) {\n                        if (\n                            Array.isArray(\n                                this.spinAnalyzer.getSybmolFromIndex(this.spinAnalyzer.getWildIndex()).stopWildSound(),\n                            )\n                        ) {\n                            const wildSounds: string[] = this.spinAnalyzer\n                                .getSybmolFromIndex(this.spinAnalyzer.getWildIndex())\n                                .stopWildSound();\n                            if (wildSounds[index] !== '') {\n                                return wildSounds[index];\n                            } else {\n                                return this.spinAnalyzer.getReelStopSound(this.scattersCount, index);\n                            }\n                        } else {\n                            return this.spinAnalyzer\n                                .getSybmolFromIndex(this.spinAnalyzer.getWildIndex())\n                                .stopWildSound();\n                        }\n                    } else {\n                        return this.spinAnalyzer.getReelStopSound(this.scattersCount, index);\n                    }\n                }),\n                toArray(),\n            )\n            .subscribe((calculatedTimings) => {\n                this.reelsStopSounds = calculatedTimings;\n            });\n    }\n\n    public getReelsStopSounds(): string[] {\n        return this.reelsStopSounds;\n    }\n\n    public calculateReelTimings(betResponse: BetResponse): void {\n        this.scattersCount = 0;\n        from(betResponse.reels.slice().map((a) => a.slice()))\n            .pipe(\n                map((reel, index) => {\n                    const result = this.spinAnalyzer.getReelStopDelay(this.scattersCount, index);\n                    this.scattersCount += this.countFSScatterOnReel(reel);\n                    return result;\n                }),\n                toArray(),\n            )\n            .subscribe((calculatedTimings) => {\n                this.reelsTimings = calculatedTimings;\n            });\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public getReelAccelerateSound(reelIndex: number): string {\n        return 'reelAccelerateSound';\n    }\n\n    protected initialRotationTime(startConfig?: any): number {\n        const numberOfReels = startConfig?.reelsToStart?.length ? startConfig?.reelsToStart?.length : this.reels.length;\n        const minimumSpinTime = this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value;\n        const totalReelDelay = (numberOfReels - 1) * this.componentConfiguration.gameBetweenReelsDelay;\n        const lastReelStopTime =\n            (this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value + 1) *\n                this.componentConfiguration.reelRotationSpeed +\n            this.componentConfiguration.reelStopBounceTime * 1000;\n        const totalSpinTime = totalReelDelay + lastReelStopTime;\n        return Math.max(\n            this.rootStore.uiStore.quickSpinEnabled && !this.rootStore.uiStore.disableSpecialSpinSpeedForCurrentState\n                ? this.componentConfiguration.gameInitialReelRotationTimeInQuickSpin\n                : this.componentConfiguration.gameInitialReelRotationTime,\n            minimumSpinTime - totalSpinTime,\n        );\n    }\n\n    protected countFSScatterOnReel(reel: number[]): number {\n        reel.shift();\n        reel.pop();\n        if (this.rootStore.subjects.REEL_ACCELERATE_DISBALED.value) {\n            return 0;\n        }\n        return reel.filter(\n            (symbolIndex) =>\n                symbolIndex ===\n                (this.spinAnalyzer.anticipateScatterSymbol ? this.spinAnalyzer.anticipateScatterSymbol.index : -1),\n        ).length;\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    protected reelStartStopping(reelIndex: number): void {\n        // hook method implementing custom logic when reels start stopping\n    }\n\n    protected playSounds(reelIndex: number): void {\n        if (!this.stopAllRequested && this.mainSoundsLoaded) {\n            Core.sounds.play(this.reelsStopSounds[reelIndex]);\n        }\n    }\n\n    protected onReelStopped(reel: ReelDefault): void {\n        this.rootStore.subjects.REEL_STOPPED.next(reel);\n        this.rotatingReelsMap.set(reel.getIndex(), false);\n        if (this.areReelsRotating) {\n            return;\n        }\n\n        this.onAllReelsStopped();\n    }\n\n    protected onAllReelsStopped(): void {\n        this.scattersCount = 0;\n        if (!this.stopAllRequested || this.rootStore.subjects.SPIN_SPEED.value === 2) {\n            AnalyticsDispatcher.onReelsStopped({\n                quickMode: Boolean(this.rootStore.subjects.SPIN_SPEED.value === 1),\n                turboMode: Boolean(this.rootStore.subjects.SPIN_SPEED.value === 2),\n                specialSpinSpeedDisabled: this.rootStore.uiStore.disableSpecialSpinSpeedForCurrentState,\n            });\n        }\n\n        this.stopAllRequested = false;\n        this.rootStore.subjects.REELS_FORCE_STOP.next(false);\n        this.rootStore.subjects.ARE_REELS_ROTATING.next(false);\n        this.rootStore.subjects.REELS_STOPPED.next();\n        PostMessageDispatcher.reelsStopped();\n    }\n\n    protected prepareReelAcceleration(reelIndex: number): void {\n        if (reelIndex > 0 && this.rotatingReelsMap.get(reelIndex - 1)) {\n            this.reels[reelIndex - 1].BOUNCED.pipe(\n                takeUntil(\n                    merge(\n                        this.rootStore.subjects.REELS_STOPPED,\n                        this.DESTROY,\n                        this.reels[reelIndex - 1].STOPPED,\n                        this.rootStore.subjects.REELS_STOP_ALL,\n                    ),\n                ),\n                take(1),\n            ).subscribe(() => {\n                Core.sounds.play(this.getReelAccelerateSound(reelIndex));\n                this.rootStore.subjects.REEL_ACCELERATE.next(this.reels[reelIndex]);\n            });\n        } else {\n            Core.sounds.play(this.getReelAccelerateSound(reelIndex));\n            this.rootStore.subjects.REEL_ACCELERATE.next(this.reels[reelIndex]);\n        }\n    }\n\n    protected onReelBounced(reel: ReelDefault): void {\n        this.rootStore.subjects.REEL_BOUNCED.next(reel);\n        if (this.stopAllRequested) {\n            if (reel.getIndex() === this.lastStartedReel) {\n                Core.sounds.stop('spinSound');\n                Core.sounds.stop(this.getReelAccelerateSound(reel.getIndex()));\n                Core.sounds.stop('stopReelSound');\n                (this.rootStore.uiStore.turboModeEnabled || this.rootStore.subjects.TOGGLE_TURBO_SPIN.value) &&\n                !this.rootStore.uiStore.disableSpecialSpinSpeedForCurrentState\n                    ? Core.sounds.play('turboReelsStop')\n                    : Core.sounds.play('stopReelAllSound');\n            }\n        }\n    }\n\n    protected redrawReels(): void {\n        this.reels.forEach((reel) => {\n            reel.redraw();\n        });\n    }\n\n    protected createSymbols(): void {\n        const symbols: ISymbol[] = [];\n        const emptyTexture = new Texture(\n            new BaseTexture(undefined, {\n                width: this.rootStore.subjects.REELS_POSITION.value.reelWidth,\n                height: this.rootStore.subjects.REELS_POSITION.value.symbolHeight,\n            }),\n        );\n        this.slotConfiguration.symbolsConfig.forEach((item: any) => {\n            let sprite: string = 'symbols';\n            if (item.spriteID) {\n                sprite = item.spriteID;\n            }\n            const symbol: ISymbol = new SymbolBase(\n                item.texture ? Core.assets.getTextureFromSpriteSheet(sprite, item.texture) : emptyTexture,\n                item.topTexture ? Core.assets.getTextureFromSpriteSheet(sprite, item.topTexture) : emptyTexture,\n                item.blurredTexture ? Core.assets.getTextureFromSpriteSheet(sprite, item.blurredTexture) : emptyTexture,\n\n                item.index,\n                item.name,\n                item.video,\n                item.expandVideo,\n                item.expandSound,\n                item.isScatter,\n                item.isStackedScatter,\n                item.isVerticalStackedSymbol,\n                item.isWild,\n                item.stopWildSound,\n                item.scatterConfig,\n                item.stopVideo,\n            );\n            symbols.push(symbol);\n        });\n\n        this.slotConfiguration.symbols = symbols;\n    }\n\n    protected initialReelSettings(): void {\n        let restore: any;\n        if (this.settings.settings.game?.restore) {\n            restore = this.settings.settings.game?.restore[this.settings.settings.game?.result?.restorePoints[0]];\n        }\n        if (\n            (!this.settings.settings.game?.result?.spins || !this.settings.settings.game?.result?.spins[0]?.reels) &&\n            (!restore || !restore.spins[0].reels)\n        ) {\n            let reels: number[][] = [];\n            if (this.slotConfiguration.initialReels !== null) {\n                reels = this.slotConfiguration.initialReels;\n            } else {\n                for (let i: number = 0; i < this.rootStore.subjects.NUMBER_OF_REELS.value; i++) {\n                    reels.push(\n                        this.componentConfiguration.initialReels[i].slice(\n                            0,\n                            this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value +\n                                this.rootStore.subjects.NUMBER_OF_GUARD_SYMBOLS.value,\n                        ),\n                    );\n                }\n            }\n\n            this.settings.reels = reels;\n        }\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    protected subscribeToStopAllStream(stopAllStream: any, startConfig?): void {\n        stopAllStream.subscribe(this.stopAll.bind(this));\n    }\n\n    protected shouldReelAccelerate(startConfig: any, reelIndex: number): boolean {\n        return (\n            (startConfig?.reelsTimings ? startConfig.reelsTimings[reelIndex] : this.reelsTimings[reelIndex]) ===\n            this.componentConfiguration.gameAnticipationReelsDelay\n        );\n    }\n\n    // protected onOrientationChanged(): void {\n    //     this.rootStore.subjects.REELS_POSITION.next(this.componentConfiguration.reelsPosition);\n    // }\n\n    private onErrorWithInsifitionsFunds(error: IErrorData): void {\n        const errorCode = error.code.toString();\n        if ((errorCode === '4813' || errorCode === '4818') && this.areReelsRotating) {\n            this.stopAllRequested = true;\n            this.rootStore.subjects.REELS_FORCE_STOP.next(true);\n            const obj = {\n                referenceId: error.payload.referenceId,\n                sessionKey: error.payload.sessionKey,\n                event: error.payload.event,\n                balance: error.payload.balance,\n                game: {\n                    state: {\n                        matchId: this.rootStore.settings.matchId,\n                        bet: {\n                            level: this.rootStore.uiStore.SELECTED_BET.value,\n                            factor: this.rootStore.settings.factor,\n                            denomination: Core.SELECTED_DENOMINATION.value,\n                            lines: this.rootStore.uiStore.LINES.value,\n                        },\n                        totalWin: '0',\n                        totalWinAmount: '0',\n                        gambles: 0,\n                    },\n                    result: {\n                        spins: [\n                            {\n                                entries: [],\n                                mutations: [],\n                                totalWinAmount: '0',\n                                reels: this.rootStore.uiStore.REAL_REELS.value,\n                                type: 'SPIN',\n                                bonuses: [],\n                                totalWin: 0,\n                            },\n                        ],\n                    },\n                },\n                state: 'idle',\n                context: {},\n            };\n            this.rootStore.domainStore.setBet(obj, 0);\n            this.rootStore.domainStore.setBalance(obj);\n        }\n    }\n\n    private clearReels(cells: []): void {\n        cells.forEach((cell) => {\n            // @ts-ignore\n            this.reels[cell.row].clearCell(cell.col);\n        });\n    }\n\n    private showReels(cells: []): void {\n        cells.forEach((cell) => {\n            // @ts-ignore\n            this.reels[cell.row].showCell(cell.col);\n        });\n    }\n\n    protected onStopReelTimer(index: any): void {\n        if (\n            (this.rootStore.uiStore.turboModeEnabled &&\n                !this.rootStore.uiStore.disableSpecialSpinSpeedForCurrentState) ||\n            this.stopAllRequested\n        ) {\n            return;\n        }\n\n        this.reels[index].stop();\n        if (this.componentConfiguration.useReelStopEffectAnim) {\n            this.view.showReelStopEffect(index);\n        }\n        of(index)\n            .pipe(delay(this.componentConfiguration.reelStopBounceTime * 1000))\n            .subscribe(this.playSounds.bind(this));\n    }\n\n    private onReelsChanged(): void {\n        this.view.onReelsChanged(this.rootStore.uiStore.REAL_REELS.value);\n    }\n}\n","const enum ReelStateDefault {\n    REEL_IDLE = 0,\n    REEL_STARTING = 1,\n    REEL_ROTATING = 2,\n    REEL_STOPPING = 3,\n    REEL_BOUNCING = 4,\n}\nexport default ReelStateDefault;\n","import { Log } from '@egt/core';\nimport { ISlotConfiguration, ISymbol, RootStore } from '@egt/slot';\nimport { gsap } from 'gsap';\nimport { BaseTexture, Container, Point, Sprite, Texture } from 'pixi.js';\nimport { BehaviorSubject, Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { injectable } from 'tsyringe';\nimport { IReelsComponentConfigurationDefault } from '../configuration/IReelsComponentConfigurationDefault';\nimport ReelStateDefault from '../enums/ReelStateDefault';\n\n@injectable()\nexport default class ReelDefault {\n    protected static readonly EMPTY_IMAGE_INDEX = -1;\n    protected static readonly FAKE_IMAGE_INDEX = -2;\n\n    public readonly BOUNCED = new Subject();\n    public readonly STOPPED = new Subject();\n    public readonly DESTROY: Subject<void> = new Subject<void>();\n    public sprites: any;\n    public topSprites: any;\n    public imageIndex: number;\n\n    public _x: number;\n    public _y: number;\n\n    public clearedCellsIndex: number[];\n\n    protected isTinted: boolean = false;\n    protected tintColor: number = 0x797979;\n    protected spritesCardIndexMap: Map<number, number> = new Map();\n\n    protected tween: any;\n    protected fakeReel: any;\n    protected realReel: any;\n    protected _offset: number; // current offset in the reel (in pixels)\n    protected result: any = null;\n    protected bounce: number = 0;\n    protected reelLength: number = 0;\n    protected finalOffset: number = 0;\n    protected distToEnd: number = -1;\n    protected resultIndex: number = -1;\n    protected drawnOnce: boolean = false;\n    protected rotating: boolean = false;\n    protected stopAfterStart: boolean = false;\n    protected state: BehaviorSubject<number> = new BehaviorSubject<number>(ReelStateDefault.REEL_IDLE);\n    protected dispatchStop: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n\n    protected parent: any;\n    protected sprite: any;\n    protected topSprite: any;\n    protected spriteIndex: number;\n    protected spriteY: number;\n    protected imageHeight: number;\n    protected image: any;\n    protected rotationSpeed: number;\n    protected reelPixels: number;\n\n    // set to false on Reels with mask and remove after we make all the reels with masks\n\n    constructor(\n        protected _config: ISlotConfiguration,\n        protected rootStore: RootStore,\n        protected overlayContainer: Container,\n        protected reelIndex: number,\n        protected setIndexes: boolean,\n        protected componentConfiguration: IReelsComponentConfigurationDefault,\n    ) {\n        this.init();\n    }\n    public init(): void {\n        this._x =\n            this.rootStore.subjects.REELS_POSITION.value.reelX +\n            this.rootStore.subjects.REELS_POSITION.value.reelWidth / 2 +\n            this.reelIndex *\n                (this.rootStore.subjects.REELS_POSITION.value.reelWidth +\n                    this.rootStore.subjects.REELS_POSITION.value.reelSpacing);\n        this._y =\n            this.rootStore.subjects.REELS_POSITION.value.reelY +\n            this.rootStore.subjects.REELS_POSITION.value.symbolHeight / 2;\n\n        this.sprites = [];\n        this.topSprites = [];\n        this.clearedCellsIndex = [];\n        this.imageHeight = this.rootStore.subjects.REELS_POSITION.value.symbolHeight;\n\n        this._offset = this.rootStore.subjects.REELS_POSITION.value.symbolHeight;\n\n        this.bounce = Math.floor(\n            (this.rootStore.subjects.REEL_ROTATION_DIRECTION.value *\n                this.rootStore.subjects.REELS_POSITION.value.symbolHeight *\n                this.componentConfiguration.reelStopBouncePercent) /\n                100,\n        );\n        this.state.pipe(takeUntil(this.DESTROY)).subscribe(this.onStateChanged.bind(this));\n        this.dispatchStop.pipe(takeUntil(this.DESTROY)).subscribe(this.dispatchEventOnStop.bind(this));\n\n        this._config.symbols.forEach((symbol: ISymbol) => {\n            this.rootStore.texturesMap.set(symbol.index(), symbol.texture());\n            this.rootStore.topTexturesMap.set(symbol.index(), symbol.topTexture());\n            this.rootStore.blurredTexturesMap.set(symbol.index(), symbol.blurredTexture());\n        });\n        this.rootStore.texturesMap.set(ReelDefault.EMPTY_IMAGE_INDEX, new Texture(new BaseTexture(undefined)));\n        this.rootStore.topTexturesMap.set(ReelDefault.EMPTY_IMAGE_INDEX, new Texture(new BaseTexture(undefined)));\n        this.rootStore.blurredTexturesMap.set(ReelDefault.EMPTY_IMAGE_INDEX, new Texture(new BaseTexture(undefined)));\n\n        this.createSprites();\n    }\n\n    public dispatchEventOnStop(): void {\n        if (this.dispatchStop.value) {\n            this.state.next(ReelStateDefault.REEL_IDLE);\n            this.dispatchStop.next(false);\n            this.STOPPED.next(this);\n        }\n    }\n\n    public getSetOffset(value?: number): number | undefined {\n        if (value === undefined) {\n            return this._offset;\n        } else {\n            this._offset = value;\n        }\n    }\n\n    public getIndex(): number {\n        return this.reelIndex;\n    }\n\n    public getState(): number {\n        switch (this.state.value) {\n            case ReelStateDefault.REEL_STARTING:\n            case ReelStateDefault.REEL_ROTATING:\n                return ReelStateDefault.REEL_ROTATING;\n            case ReelStateDefault.REEL_STOPPING:\n            case ReelStateDefault.REEL_BOUNCING:\n                return ReelStateDefault.REEL_STOPPING;\n        }\n        return ReelStateDefault.REEL_IDLE;\n    }\n\n    public changeFakeReel(arr: any): void {\n        this.reelLength = arr.length;\n        this.fakeReel = [];\n        this.realReel = [];\n        let i: number;\n        for (i = 0; i < this.reelLength; i++) {\n            this.fakeReel[i] = arr[i];\n            this.realReel[i] = ReelDefault.FAKE_IMAGE_INDEX;\n        }\n        const len = this.result.length;\n        for (i = 0; i < len; i++) {\n            this.realReel[i] = this.result[i];\n        }\n        this._offset = this.rootStore.subjects.REELS_POSITION.value.symbolHeight;\n    }\n\n    public setFakeReel(arr: any): void {\n        let updateFakeReels: boolean = false;\n        if (this.fakeReel) {\n            Log.debug('Changing fake reels!', this.constructor.name);\n            updateFakeReels = true;\n        }\n\n        this.reelLength = arr.length;\n        this.reelPixels = this.reelLength * this.imageHeight;\n        this.fakeReel = [];\n        if (!updateFakeReels) {\n            this.realReel = [];\n        }\n        for (let i = 0; i < this.reelLength; i++) {\n            this.fakeReel[i] = arr[i];\n            if (!updateFakeReels) {\n                this.realReel[i] = ReelDefault.FAKE_IMAGE_INDEX;\n            }\n        }\n        this.result = [];\n        this.clearResult();\n    }\n\n    public setResult(result: any, showNow?: boolean): void {\n        let image = (this.getCurrentTopImage() + this.reelLength - 1) % this.reelLength;\n        const len =\n            this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value +\n            this.rootStore.subjects.NUMBER_OF_GUARD_SYMBOLS.value;\n        if (showNow) {\n            this.resultIndex = image;\n        }\n        for (let i = 0; i < len; i++) {\n            if (showNow) {\n                this.realReel[image] = result[i];\n                image = (image + 1) % this.reelLength;\n            }\n            this.result[i] = result[i];\n        }\n        this.drawnOnce = false;\n        if (showNow) {\n            this.draw(1);\n        }\n    }\n\n    public getResult(): number[] {\n        return this.result;\n    }\n\n    public start(): void {\n        if (this.state.value === ReelStateDefault.REEL_IDLE) {\n            this.showAllCells();\n            this.clearResult();\n            /////////////////////////////////////////////////////////////////////////////////\n            // Workaround for #22\n            this._offset =\n                this._offset % (this.rootStore.subjects.REELS_POSITION.value.symbolHeight * this.fakeReel.length);\n            /////////////////////////////////////////////////////////////////////////////////\n            this.state.next(ReelStateDefault.REEL_STARTING);\n            this.stopAfterStart = false;\n        }\n    }\n\n    public stop(distToEnd?: number): void {\n        if (distToEnd === undefined) {\n            distToEnd = 0;\n        }\n        switch (this.state.value) {\n            case ReelStateDefault.REEL_STARTING:\n                this.distToEnd = -1;\n                this.stopAfterStart = true;\n                break;\n            case ReelStateDefault.REEL_ROTATING:\n                this.distToEnd = distToEnd;\n                this.state.next(ReelStateDefault.REEL_STOPPING);\n                break;\n            case ReelStateDefault.REEL_STOPPING:\n                this._offset =\n                    this.finalOffset -\n                    (this.rootStore.subjects.REEL_ROTATION_DIRECTION.value === 1 ? distToEnd : -distToEnd);\n                break;\n        }\n    }\n\n    public getDistToStop(): number {\n        if (this.state.value === ReelStateDefault.REEL_STOPPING) {\n            return Math.abs(this._offset - this.finalOffset);\n        }\n        return -1;\n    }\n\n    public getDistToRest(): number {\n        if (this.state.value === ReelStateDefault.REEL_BOUNCING) {\n            return Math.abs(this._offset - (this.finalOffset - this.bounce));\n        }\n        return -1;\n    }\n\n    public clearCell(cell: number): void {\n        if (this.sprites[cell]) {\n            this.sprites[cell].visible = false;\n        }\n        if (this.topSprites[cell]) {\n            this.topSprites[cell].visible = false;\n        }\n        this.clearedCellsIndex.push(cell);\n    }\n\n    public redraw(): void {\n        this.drawnOnce = false;\n        this.draw(1);\n    }\n\n    public refreshLayout(): void {\n        const previousSymbolHeight = this.imageHeight || this.rootStore.subjects.REELS_POSITION.value.symbolHeight;\n        const currentSymbolHeight = this.rootStore.subjects.REELS_POSITION.value.symbolHeight;\n        const symbolScale = this.rootStore.subjects.REELS_POSITION.value.symbolScale;\n        const resizeRatio = previousSymbolHeight !== 0 ? currentSymbolHeight / previousSymbolHeight : 1;\n\n        if (resizeRatio !== 1) {\n            this._offset *= resizeRatio;\n            this.finalOffset *= resizeRatio;\n            if (this.distToEnd > 0) {\n                this.distToEnd *= resizeRatio;\n            }\n        }\n\n        this.imageHeight = currentSymbolHeight;\n        this.bounce = Math.floor(\n            (this.rootStore.subjects.REEL_ROTATION_DIRECTION.value *\n                currentSymbolHeight *\n                this.componentConfiguration.reelStopBouncePercent) /\n                100,\n        );\n        this.reelPixels = this.reelLength * this.imageHeight;\n\n        this.sprites.forEach((sprite) => {\n            sprite.scale.set(symbolScale, symbolScale);\n        });\n        this.topSprites.forEach((sprite) => {\n            sprite.scale.set(symbolScale, symbolScale);\n        });\n\n        if (this.tween && resizeRatio !== 1) {\n            this.tween.vars.getSetOffset *= resizeRatio;\n            this.tween.invalidate();\n        }\n    }\n\n    public draw(compensation: number): void {\n        if (this.shouldDrawReel()) {\n            return;\n        }\n\n        this.drawnOnce = true;\n        this.rotationSpeed = 0;\n        if (this.rotating) {\n            this.rotationSpeed =\n                (this.rootStore.subjects.REELS_POSITION.value.symbolHeight /\n                    this.componentConfiguration.reelRotationSpeed) *\n                compensation *\n                this.rootStore.subjects.REEL_ROTATION_DIRECTION.value;\n        }\n\n        let offset = this._offset;\n        this._offset += this.rotationSpeed;\n\n        if (this.state.value === ReelStateDefault.REEL_STOPPING) {\n            if (\n                (this.rootStore.subjects.REEL_ROTATION_DIRECTION.value === 1 && this._offset >= this.finalOffset) ||\n                (this.rootStore.subjects.REEL_ROTATION_DIRECTION.value === -1 && this._offset <= this.finalOffset)\n            ) {\n                this._offset = this.finalOffset;\n                this.state.next(ReelStateDefault.REEL_BOUNCING);\n            }\n        }\n\n        offset = offset % this.reelPixels;\n        if (offset < 0) {\n            offset = this.reelPixels + offset;\n        }\n\n        this.imageIndex = Math.floor(offset / this.imageHeight);\n\n        if (this.rootStore.subjects.REEL_ROTATION_DIRECTION.value === 1) {\n            this.realReel[(this.imageIndex + this.reelLength - 1) % this.reelLength] = ReelDefault.EMPTY_IMAGE_INDEX;\n        }\n\n        this.spriteY = -(offset % this.imageHeight);\n        this.spriteIndex = 0;\n\n        while (\n            this.spriteY <=\n            this.imageHeight * Math.round(this.rootStore.subjects.REELS_POSITION.value.reelHeight / this.imageHeight)\n        ) {\n            this.image = this.realReel[this.imageIndex];\n            if (this.image === ReelDefault.FAKE_IMAGE_INDEX) {\n                this.image = this.fakeReel[this.imageIndex];\n            }\n            this.sprite = this.sprites[this.spriteIndex];\n            this.topSprite = this.topSprites[this.spriteIndex];\n\n            this.spritesCardIndexMap.set(this.spriteIndex, this.image);\n            if (\n                this.componentConfiguration.useBlurredReels &&\n                (this.state.value === ReelStateDefault.REEL_ROTATING ||\n                    this.state.value === ReelStateDefault.REEL_STOPPING)\n            ) {\n                this.sprite.texture = this.rootStore.blurredTexturesMap.get(this.image);\n                this.topSprite.texture = this.rootStore.blurredTexturesMap.get(this.image);\n            } else {\n                this.sprite.texture = this.rootStore.texturesMap.get(this.image);\n                this.topSprite.texture = this.rootStore.topTexturesMap.get(this.image);\n            }\n\n            this.sprite.x = this._x /*+ (this.config.reelWidth - sprite.width) / 2*/;\n            this.sprite.y = this.spriteY + this._y;\n\n            if (this._config.noTintedSymbols && this._config.noTintedSymbols.indexOf(this.image) !== -1) {\n                this.sprite.tint = 0xffffff; // NO TINT\n                this.topSprite.tint = 0xffffff; // NO TINT\n            } else {\n                if (this.isTinted) {\n                    this.sprite.tint = this.tintColor;\n                    this.topSprite.tint = this.tintColor;\n                }\n            }\n\n            // This is a hook for extention\n            this.drawHook(this.sprite, this.topSprite, this.image);\n\n            this.parent = this.topSprite.parent;\n\n            if (this.setIndexes) {\n                if (\n                    (this.state.value === ReelStateDefault.REEL_IDLE ||\n                        this.state.value === ReelStateDefault.REEL_BOUNCING) &&\n                    this.topSprite.height > this.rootStore.subjects.REELS_POSITION.value.symbolHeight &&\n                    Math.floor(this.spriteY) >= 0\n                ) {\n                    if (this.parent.getChildIndex(this.overlayContainer) > this.parent.getChildIndex(this.topSprite)) {\n                        this.parent.setChildIndex(this.topSprite, this.parent.getChildIndex(this.overlayContainer));\n                    }\n                    this.setTopSpritesOrder();\n                } else {\n                    this.parent.setChildIndex(this.topSprite, this.parent.getChildIndex(this.overlayContainer) - 1);\n                }\n            }\n\n            this.topSprite.x = this.sprite.x;\n            this.topSprite.y = this.sprite.y;\n\n            if (\n                ((this.state.value === ReelStateDefault.REEL_IDLE && this.spriteIndex === this.sprites.length - 1) ||\n                    (this.state.value === ReelStateDefault.REEL_BOUNCING &&\n                        this.topSprite.y + this.topSprite.height / 2 - (this.topSprite.height - this.imageHeight) / 2 >=\n                            this.rootStore.subjects.REELS_POSITION.value.reelHeight + this._y)) &&\n                this.topSprite.height > this.rootStore.subjects.REELS_POSITION.value.symbolHeight\n            ) {\n                this.topSprite.visible = false;\n            } else if (this.clearedCellsIndex.indexOf(this.spriteIndex) === -1) {\n                this.topSprite.visible = true;\n            }\n\n            this.spriteY += this.imageHeight;\n\n            this.imageIndex = (this.imageIndex + 1) % this.reelLength;\n            this.spriteIndex++;\n        }\n\n        if (this.rootStore.subjects.REEL_ROTATION_DIRECTION.value === -1) {\n            const stopIndex =\n                this.resultIndex === -1\n                    ? (this.getCurrentTopImage() + this.reelLength - 2) % this.reelLength\n                    : (this.resultIndex + this.reelLength - 1) % this.reelLength;\n            do {\n                this.imageIndex++;\n                this.imageIndex = this.imageIndex % this.reelLength;\n                this.realReel[this.imageIndex] = ReelDefault.FAKE_IMAGE_INDEX;\n            } while (this.imageIndex !== stopIndex);\n        }\n    }\n\n    public removeSymbolFromRealReel(symbol): void {\n        this.realReel.forEach((el, index) => {\n            if (el === symbol) {\n                this.realReel[index] = -symbol;\n            }\n        });\n    }\n\n    public restoreSymbol(symbol): void {\n        this.realReel.forEach((el, index) => {\n            if (el === -symbol) {\n                this.realReel[index] = symbol;\n            }\n        });\n    }\n\n    public destroy(): void {\n        if (this.tween) {\n            this.tween.kill();\n            this.tween = null;\n        }\n        this.DESTROY.next();\n        this.DESTROY.complete();\n        if (this.sprites) {\n            this.sprites.forEach((spr) => {\n                spr.destroy();\n                // @ts-ignore\n                spr = null;\n            });\n            this.sprites.length = 0;\n            this.sprites = null;\n        }\n\n        if (this.topSprites) {\n            this.topSprites.forEach((spr) => {\n                spr.destroy();\n                // @ts-ignore\n                spr = null;\n            });\n            this.topSprites.length = 0;\n            // @ts-ignore;\n            this.topSprites = null;\n        }\n\n        this.spritesCardIndexMap.clear();\n        // @ts-ignore\n        this.spritesCardIndexMap = null;\n\n        this.state.complete();\n        // @ts-ignore\n        this.state = null;\n        this.dispatchStop.complete();\n        // @ts-ignore;\n        this.dispatchStop = null;\n\n        this.clearedCellsIndex.length = 0;\n        // @ts-ignore\n        this.clearedCellsIndex = null;\n\n        this.fakeReel.length = 0;\n        this.realReel.length = 0;\n        // @ts-ignore\n        this.fakeReel = null;\n        // @ts-ignore\n        this.realReel = null;\n    }\n\n    public showReel(): void {\n        // implement\n    }\n\n    public showCell(cell: number): void {\n        if (this.sprites[cell]) {\n            this.sprites[cell].visible = true;\n        }\n        if (this.topSprites[cell]) {\n            this.topSprites[cell].visible = true;\n        }\n        const clearedIndex = this.clearedCellsIndex.indexOf(cell);\n        if (clearedIndex !== -1) {\n            this.clearedCellsIndex.splice(clearedIndex, 1);\n        }\n\n        this.redraw();\n    }\n\n    public tintAllCells(tint: boolean = true): void {\n        this.isTinted = tint;\n        this.spritesCardIndexMap.forEach((value, key) => {\n            if (this._config.noTintedSymbols && this._config.noTintedSymbols.indexOf(value) === -1) {\n                this.sprites[key].tint = tint ? this.tintColor : 0xffffff;\n                this.topSprites[key].tint = tint ? this.tintColor : 0xffffff;\n            }\n        });\n    }\n\n    public tintCell(cell: number): void {\n        this.sprites[cell].tint = this.tintColor;\n        this.topSprites[cell].tint = this.tintColor;\n    }\n\n    protected shouldDrawReel(): boolean {\n        return this.state.value === ReelStateDefault.REEL_IDLE && this.drawnOnce;\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    protected drawHook(sprite: Sprite, topSpirte: Sprite, image: number): void {\n        return;\n    }\n\n    protected getCurrentTopImage(): number {\n        // this.reelPixels = this.rootStore.subjects.REELS_POSITION.value.symbolHeight * this.reelLength;\n        let idx = this._offset % this.reelPixels;\n        if (idx < 0) {\n            idx = this.reelPixels + idx;\n        }\n        return Math.floor(idx / this.rootStore.subjects.REELS_POSITION.value.symbolHeight);\n    }\n\n    protected setTopSpritesOrder(): void {\n        for (let i = 0; i < this.topSprites.length; i++) {\n            this.parent = this.topSprites[i].parent;\n            if (this.parent.getChildIndex(this.overlayContainer) < this.parent.getChildIndex(this.topSprites[i])) {\n                this.parent.setChildIndex(this.topSprites[i], this.parent.children.length - 1);\n            } else {\n                this.parent.setChildIndex(this.topSprites[i], this.parent.getChildIndex(this.overlayContainer) - 1);\n            }\n        }\n    }\n\n    protected onStateChanged(state: number): void {\n        switch (state) {\n            case ReelStateDefault.REEL_STARTING:\n                this.onReelStarting();\n                break;\n            case ReelStateDefault.REEL_ROTATING:\n                this.onReelRotating();\n                break;\n            case ReelStateDefault.REEL_STOPPING:\n                this.onReelStopping();\n                break;\n            case ReelStateDefault.REEL_BOUNCING:\n                this.onReelBouncing();\n                break;\n        }\n    }\n\n    protected showAllCells(): void {\n        for (const sprite of this.sprites) {\n            sprite.visible = true;\n        }\n    }\n\n    protected createSprites(): void {\n        for (let i = 0; i < this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value + 1; i++) {\n            this.sprites[i] = new Sprite(this.rootStore.texturesMap.get(0));\n            this.sprites[i].x = this._x;\n            this.sprites[i].anchor = new Point(0.5, 0.5);\n            this.spritesCardIndexMap.set(i, -1);\n            this.topSprites[i] = new Sprite(this.rootStore.topTexturesMap.get(0));\n            this.topSprites[i].x = this._x;\n            this.topSprites[i].anchor = new Point(0.5, 0.5);\n            this.sprites[i].scale = new Point(\n                this.rootStore.subjects.REELS_POSITION.value.symbolScale,\n                this.rootStore.subjects.REELS_POSITION.value.symbolScale,\n            );\n            this.topSprites[i].scale = new Point(\n                this.rootStore.subjects.REELS_POSITION.value.symbolScale,\n                this.rootStore.subjects.REELS_POSITION.value.symbolScale,\n            );\n        }\n    }\n\n    private clearResult(): void {\n        const len = this.result.length;\n        for (let i = 0; i < len; i++) {\n            this.result[i] = -1;\n        }\n    }\n\n    private onReelBouncing(): void {\n        this.BOUNCED.next(this);\n\n        this.rotating = false;\n        this.tween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/reels/src/egt/modes/default/views/ReelDefault.ts:623:22\",null]), gsap.to(this, {\n            duration: this.componentConfiguration.reelStopBounceTime,\n            getSetOffset: this._offset - this.bounce,\n            ease: 'power2.out',\n            onComplete: this.onTweenEnd.bind(this),\n            onCompleteParams: [ReelStateDefault.REEL_IDLE],\n        }));\n    }\n\n    protected onReelStopping(): void {\n        const offset = this._offset;\n        let stopOffset =\n            offset +\n            this.rootStore.subjects.REEL_ROTATION_DIRECTION.value *\n                (this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value + 2) *\n                this.rootStore.subjects.REELS_POSITION.value.symbolHeight;\n\n        // --- round the offset forward along the reel movement to the closest symbol boundary\n\n        const frac = stopOffset % this.rootStore.subjects.REELS_POSITION.value.symbolHeight;\n        if (frac !== 0) {\n            if (this.rootStore.subjects.REEL_ROTATION_DIRECTION.value > 0) {\n                stopOffset += this.rootStore.subjects.REELS_POSITION.value.symbolHeight - frac;\n            } else if (stopOffset < 0) {\n                stopOffset -= this.rootStore.subjects.REELS_POSITION.value.symbolHeight + frac;\n            } else {\n                stopOffset -= frac;\n            }\n        }\n\n        // --- plant the real slots into the reel\n\n        this.reelPixels = this.reelLength * this.rootStore.subjects.REELS_POSITION.value.symbolHeight;\n        let img = stopOffset % this.reelPixels;\n        if (img < 0) {\n            img += this.reelPixels;\n        }\n        img = Math.floor(img / this.rootStore.subjects.REELS_POSITION.value.symbolHeight);\n\n        this.resultIndex = img;\n        const len = this.result.length;\n        for (let j = 0; j < len; ++j) {\n            this.realReel[img] = this.result[j];\n            img = (img + 1) % this.reelLength;\n        }\n        stopOffset -=\n            this.rootStore.subjects.REEL_ROTATION_DIRECTION.value *\n            this.rootStore.subjects.REELS_POSITION.value.symbolHeight; // compensate for the 1 guarding symbol of the real reel\n        stopOffset += this.bounce; // bounce\n        this.finalOffset = stopOffset;\n\n        if (this.distToEnd > 0) {\n            this._offset =\n                this.finalOffset -\n                (this.rootStore.subjects.REEL_ROTATION_DIRECTION.value === 1 ? this.distToEnd : -this.distToEnd);\n        }\n    }\n\n    private onReelRotating(): void {\n        this.rotating = true;\n\n        if (this.stopAfterStart) {\n            this.state.next(ReelStateDefault.REEL_STOPPING);\n        }\n    }\n\n    protected onReelStarting(): void {\n        this.rotating = false;\n        if (this.componentConfiguration.reelStartBounceTime > 0) {\n            this.tween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/reels/src/egt/modes/default/views/ReelDefault.ts:692:26\",null]), gsap.to(this, {\n                duration: this.componentConfiguration.reelStartBounceTime,\n                getSetOffset:\n                    this._offset +\n                    this.rootStore.subjects.REEL_ROTATION_DIRECTION.value *\n                        this.rootStore.subjects.REELS_POSITION.value.symbolHeight,\n                ease: 'sine.in',\n                onComplete: this.onTweenEnd.bind(this),\n                onCompleteParams: [ReelStateDefault.REEL_ROTATING],\n            }));\n        } else {\n            this.state.next(ReelStateDefault.REEL_ROTATING);\n            // this.maskAllSprites();\n        }\n    }\n\n    private maskAllSprites(): void {\n        const length = this.sprites.length;\n        for (let i = 0; i < length; i++) {\n            this.topSprites[i].parent.setChildIndex(\n                this.topSprites[i],\n                this.topSprites[i].parent.getChildIndex(this.overlayContainer) - 1,\n            );\n        }\n    }\n\n    protected onTweenEnd(nextState: number): void {\n        if (nextState === ReelStateDefault.REEL_IDLE) {\n            this.dispatchStop.next(true);\n            this.drawnOnce = false;\n        } else {\n            this.state.next(nextState);\n        }\n        if (this.tween) {\n            this.tween.kill();\n        }\n        this.tween = null;\n    }\n}\n","import Core, { IOrientation } from '@egt/core';\nimport { ISlotConfiguration, RootStore } from '@egt/slot';\nimport { IBackgroundAssets, ViewContainer } from '@egt/ui-lib';\nimport { Container, Sprite } from 'pixi.js';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { IReelsComponentConfigurationDefault } from '../configuration/IReelsComponentConfigurationDefault';\nimport ReelDefault from './ReelDefault';\n\n@injectable()\nexport default class ReelsViewDefault extends ViewContainer {\n    get reels(): ReelDefault[] {\n        return this._reels;\n    }\n    public overlayTextures = {};\n    protected _reels: ReelDefault[] = [];\n    protected currentFakeReels: number[][] = [];\n\n    protected topPart: Sprite;\n    protected bottomPart: Sprite;\n    protected reelsContainer: Sprite;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('ReelsOverlay') public overlay: Container,\n        @inject('ReelsComponentConfiguration') protected componentConfiguration: IReelsComponentConfigurationDefault,\n    ) {\n        super();\n    }\n\n    public init(): void {\n        this.reelsContainer = new Sprite();\n        this.addChild(this.reelsContainer);\n\n        this.generateOverlayTextures();\n        this.topPart = new Sprite();\n        this.bottomPart = new Sprite();\n\n        this.overlay.addChild(this.topPart);\n        this.overlay.addChild(this.bottomPart);\n\n        this.initialRender();\n        if (this.componentConfiguration.useReelStopEffectAnim) {\n            this.createReelStopAnimation();\n        }\n\n        this.rootStore.uiStore.FAKE_REELS.pipe(takeUntil(this.DESTROY)).subscribe(this.onFakeReelsChanged.bind(this));\n        this.rootStore.subjects.CHANGE_BACKGROUND.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onBackgroundChanged.bind(this),\n        );\n\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n    }\n\n    public onBackgroundChanged(param: IBackgroundAssets): void {\n        this.overlayTextures = param;\n        this.setOrientation(Core.ORIENTATION.value);\n    }\n\n    public initialRender(): void {\n        for (let i = 0; i < this.rootStore.subjects.NUMBER_OF_REELS.value; i++) {\n            // TODO: Think a way to refactor this using the dependecy injection\n            // Problem for now is using i as index of each reelView\n            this._reels[i] = new ReelDefault(\n                this.slotConfiguration,\n                this.rootStore,\n                this.overlay,\n                i,\n                true,\n                this.componentConfiguration,\n            );\n            this._reels[i].sprites.forEach((sprite) => {\n                this.reelsContainer.addChild(sprite);\n            });\n\n            this._reels[i].topSprites.forEach((topSprite) => {\n                this.reelsContainer.addChild(topSprite);\n            });\n        }\n        this.reelsContainer.addChild(this.overlay);\n    }\n\n    public destroy(): void {\n        this._reels.forEach((reel) => {\n            reel.sprites.forEach((sprite) => {\n                this.reelsContainer.removeChild(sprite);\n            });\n            reel.topSprites.forEach((sprite) => {\n                this.reelsContainer.removeChild(sprite);\n            });\n            reel.destroy();\n        });\n        this._reels.length = 0;\n        // @ts-ignore\n        this._reels = null;\n\n        if (this.topPart) {\n            this.topPart.destroy();\n            // @ts-ignore\n            this.topPart = null;\n        }\n\n        if (this.bottomPart) {\n            this.bottomPart.destroy();\n            // @ts-ignore\n            this.bottomPart = null;\n        }\n        if (this.overlay) {\n            this.overlay.destroy();\n            // @ts-ignore\n            this.overlay = null;\n        }\n\n        Object.keys(this.overlayTextures).forEach((element) => {\n            Object.keys(this.overlayTextures[element]).forEach((texture) => {\n                if (this.overlayTextures[element][texture] && this.overlayTextures[element] !== 'backgroundAnimation') {\n                    this.overlayTextures[element][texture].destroy();\n                    this.overlayTextures[element][texture] = null;\n                }\n            });\n        });\n        // @ts-ignore\n        this.overlayTextures = null;\n        super.destroy.apply(this, arguments);\n    }\n\n    public onReelsChanged(realReels: number[][]): void {\n        const length = this._reels.length;\n        for (let i = 0; i < length; i++) {\n            this._reels[i].setResult(realReels[i], this.rootStore.uiStore.drawNow);\n        }\n        if (this.rootStore.uiStore.drawNow) {\n            this.rootStore.uiStore.drawNow = false;\n        }\n    }\n\n    public setOrientation(value: IOrientation): void {\n        this._reels.forEach((reel) => {\n            reel.refreshLayout();\n        });\n\n        this.topPart.texture = this.overlayTextures[value.orientation.toLowerCase()].topPart;\n        this.bottomPart.texture = this.overlayTextures[value.orientation.toLowerCase()].bottomPart;\n        this.bottomPart.width = this.overlayTextures[value.orientation.toLowerCase()].bottomPart.width;\n        this.topPart.width = this.overlayTextures[value.orientation.toLowerCase()].topPart.width;\n        this.topPart.height = this.overlayTextures[value.orientation.toLowerCase()].topPart.height;\n        this.bottomPart.height = this.overlayTextures[value.orientation.toLowerCase()].bottomPart.height;\n\n        if (value.isLandscape) {\n            this.bottomPart.y =\n                this.rootStore.subjects.REELS_POSITION.value.reelY +\n                this.rootStore.subjects.REELS_POSITION.value.reelHeight;\n            this.topPart.x = 0;\n            this.topPart.y = 0;\n            this.reelsContainer.scale.set(1, 1);\n            this.overlay.scale.set(1, 1);\n        } else {\n            this.bottomPart.y = Core.display.stage.height - this.bottomPart.texture.height;\n            this.topPart.x = 0;\n            this.topPart.y = 0;\n            this.reelsContainer.scale.set(\n                this.componentConfiguration.portraitScale,\n                this.componentConfiguration.portraitScale,\n            );\n            this.overlay.scale.set(\n                this.rootStore.subjects.REELS_POSITION.value.scale,\n                this.rootStore.subjects.REELS_POSITION.value.scale,\n            );\n        }\n        this.changeReelsPosition(\n            this.rootStore.subjects.REELS_POSITION.value.reelX * this.rootStore.subjects.REELS_POSITION.value.scale,\n            this.rootStore.subjects.REELS_POSITION.value.reelY * this.rootStore.subjects.REELS_POSITION.value.scale,\n        );\n        if (this.componentConfiguration.useReelStopEffectAnim) {\n            this.changeReelStopEffectAnimPosition();\n        }\n        const slicesScaleFactor = this.slotConfiguration.desktopScale;\n        if (slicesScaleFactor && Core.isDesktopMode) {\n            this.topPart.scale.set(slicesScaleFactor);\n            this.bottomPart.scale.set(slicesScaleFactor);\n        }\n    }\n\n    public onFakeReelsChanged(fakeReels: number[][]): void {\n        if (fakeReels && fakeReels.length > 0) {\n            const length = this._reels.length;\n            for (let i = 0; i < length; i++) {\n                this._reels[i].setFakeReel(fakeReels[i]);\n            }\n            this.currentFakeReels = fakeReels;\n        }\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public showReelStopEffect(reelIndex: number): void {\n        // override\n    }\n\n    protected changeReelStopEffectAnimPosition(): void {\n        // override\n    }\n\n    protected createReelStopAnimation(): void {\n        // override\n    }\n\n    protected changeReelsPosition(x: number, y: number): void {\n        this._reels.forEach((reel, index) => {\n            reel._x =\n                x +\n                this.rootStore.subjects.REELS_POSITION.value.reelWidth / 2 +\n                index *\n                    (this.rootStore.subjects.REELS_POSITION.value.reelWidth +\n                        this.rootStore.subjects.REELS_POSITION.value.reelSpacing);\n            reel._y = y + this.rootStore.subjects.REELS_POSITION.value.symbolHeight / 2;\n            reel.redraw();\n        });\n    }\n\n    protected generateOverlayTextures(): void {\n        this.overlayTextures = {\n            landscape: {\n                background: Core.assets.getTextureFromSpriteSheet('mainResources', 'backgroundLandscape.png'),\n                topPart: Core.assets.getTextureFromSpriteSheet('mainResources', 'backgroundSlice1Landscape.png'),\n                bottomPart: Core.assets.getTextureFromSpriteSheet('mainResources', 'backgroundSlice2Landscape.png'),\n            },\n            portrait: {\n                background: Core.assets.getTextureFromSpriteSheet('mainResources', 'backgroundPortrait.png'),\n                topPart: Core.assets.getTextureFromSpriteSheet('mainResources', 'backgroundSlice1Portrait.png'),\n                bottomPart: Core.assets.getTextureFromSpriteSheet('mainResources', 'backgroundSlice2Portrait.png'),\n            },\n        };\n    }\n}\n","import { ISlotConfiguration, RootStore } from '@egt/slot';\nimport { Container } from 'pixi.js';\nimport { inject, injectable } from 'tsyringe';\nimport { IReelsComponentConfigurationDefault } from '../configuration/IReelsComponentConfigurationDefault';\nimport ReelsViewDefault from './ReelsViewDefault';\n\n@injectable()\nexport default class ReelsViewDesktopDefault extends ReelsViewDefault {\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('ReelsOverlay') public overlay: Container,\n        @inject('ReelsComponentConfiguration') protected componentConfiguration: IReelsComponentConfigurationDefault,\n    ) {\n        super(rootStore, slotConfiguration, overlay, componentConfiguration);\n    }\n\n    public setOrientation(value): void {\n        super.setOrientation(value);\n        const slicesScaleFactor = this.slotConfiguration.desktopScale;\n        if (slicesScaleFactor) {\n            this.topPart.scale.set(slicesScaleFactor);\n            this.bottomPart.scale.set(slicesScaleFactor);\n        }\n    }\n}\n","import { BaseComponentConfiguration, DefaultValue, DynamicPositionObject } from '@egt/core';\nimport { IReelPositionDesktopForLandscape } from '../interfaces/IReelPositionDesktopForLandscape';\nimport { IReelsComponentConfigurationDesktopForLandscape } from './IReelsComponentConfigurationDesktopForLandscape';\n\nexport default class ReelsComponentConfigurationDesktopForLandscape extends BaseComponentConfiguration {}\n\nexport function ReelsComponentConfigurationFactoryDesktopForLandscape(\n    ClassType: typeof ReelsComponentConfigurationDesktopForLandscape = ReelsComponentConfigurationDesktopForLandscape,\n): typeof ReelsComponentConfigurationDesktopForLandscape {\n    class InternalReelsComponentConfigurationDesktopForLandscape\n        extends ClassType\n        implements IReelsComponentConfigurationDesktopForLandscape\n    {\n        @DefaultValue<IReelPositionDesktopForLandscape>({\n            defaults: {\n                reelX: 3,\n                reelY: 272,\n                reelWidth: 193,\n                reelHeight: 579,\n                symbolWidth: 193,\n                symbolHeight: 193,\n                symbolResolution: 1,\n                reelSpacing: 22,\n                scale: 1,\n                symbolScale: 0.72,\n                threeDimentionalRadiusesPerReels: [],\n            },\n            landscape: {\n                reelX: 180,\n                reelY: 86,\n                scale: 1,\n                symbolScale: 0.9326,\n            },\n            desktop: {\n                reelX: 180,\n                reelY: 86,\n                scale: 1,\n                symbolScale: 0.9326,\n            },\n        })\n        public reelsPosition: DynamicPositionObject<IReelPositionDesktopForLandscape> &\n            IReelPositionDesktopForLandscape;\n        public numberOfReels: number = 5;\n        public visibleSymbolsPerReel: number = 3;\n        public portraitFirst: boolean = false;\n        public portraitScale: number = 1;\n        public useReelStopEffectAnim: boolean = false;\n\n        public initialReels: number[][] = [\n            [1, 1, 1, 1, 1, 1, 1, 1],\n            [2, 2, 2, 2, 2, 2, 2, 2],\n            [3, 3, 3, 3, 3, 3, 3, 3],\n            [4, 4, 4, 4, 4, 4, 4, 4],\n            [5, 5, 5, 5, 5, 5, 5, 5],\n            [6, 6, 6, 6, 6, 6, 6, 6],\n        ];\n        public useBlurredReels: boolean = false;\n        public transparentReels: boolean = false;\n        public reelStartBounceTime: number = 0;\n\n        public reelStopBounceTime: number = 0.3;\n        public reelStopBouncePercent: number = 30;\n        public reelRotationSpeed: number = 55;\n        public reelRotationDirection: number = -1;\n        public reelsMinimumSpinTime: number = 0;\n        public gameInitialReelRotationTime: number = 340;\n        public gameInitialReelRotationTimeInQuickSpin: number = 250;\n        public gameBetweenReelsDelay: number = 320;\n        public gameBetweenReelsDelayInQuickSpin: number = 150;\n        public minTimeReelsPercentDelay: number = 50;\n        public gameAnticipationReelsDelay: number = 2050;\n        public numberOfGuardSymbols: number = 2;\n        public delayBeforeStopAllIsCalledInTurbo: number = 133;\n\n        public fakeReels: number[][];\n        public respinFakeReels: number[][];\n        public freeSpinFakeReels: number[][];\n        public buyBonusFakeReels: number[][];\n        public multiReelsFakeReels: number[][];\n    }\n\n    return InternalReelsComponentConfigurationDesktopForLandscape;\n}\n","import Core, { AnalyticsDispatcher, BaseController, IErrorData, PostMessageDispatcher, Timers } from '@egt/core';\nimport {\n    BetResponse,\n    ISlotConfiguration,\n    ISymbol,\n    InitialSettings,\n    RootStore,\n    SpinAnalyzer,\n    SymbolBase,\n} from '@egt/slot';\nimport { BaseTexture, Texture } from 'pixi.js';\nimport { BehaviorSubject, from, merge, of, Subject, zip } from 'rxjs';\nimport { concatMap, delay, first, map, switchMap, take, takeUntil, toArray } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { IReelsComponentConfigurationDesktopForLandscape } from '../configuration/IReelsComponentConfigurationDesktopForLandscape';\nimport { IReelsDesktopForLandscape } from '../interfaces/IReelsDesktopForLandscape';\nimport { IReelsViewDesktopForLandscape } from '../interfaces/IReelsViewDesktopForLandscape';\nimport ReelDesktopForLandscape from '../views/ReelDesktopForLandscape';\n\n@injectable()\nexport default class ReelsControllerDesktopForLandscape extends BaseController implements IReelsDesktopForLandscape {\n    protected get areReelsRotating(): boolean {\n        for (let i = 0; i < this.rotatingReelsMap.size; i++) {\n            if (this.rotatingReelsMap.get(i)) {\n                return true;\n            }\n        }\n        return false;\n    }\n    protected scattersCount: number = 0;\n    protected stopAllRequested: boolean = false;\n    protected mainSoundsLoaded: boolean = false;\n    protected reelsTimings: number[] = [];\n    protected reels: ReelDesktopForLandscape[] = [];\n    protected reelsStopSounds: string[] = [];\n    protected reelsToStart: number[] = [];\n    protected PREPARE_REEL_ACCELERATION: Subject<number> = new Subject();\n\n    protected isResultReceived: boolean;\n    protected rotatingReelsMap = new Map<number, boolean>();\n    private updateCbk: () => void;\n    protected lastStartedReel: number;\n\n    constructor(\n        @inject('ReelsView') protected view: IReelsViewDesktopForLandscape,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('SpinAnalyzer') protected spinAnalyzer: SpinAnalyzer,\n        @inject('ReelsComponentConfiguration')\n        protected componentConfiguration: IReelsComponentConfigurationDesktopForLandscape,\n        @inject('InitialSettings') protected settings: InitialSettings,\n    ) {\n        super(view);\n    }\n\n    public init(): void {\n        this.rootStore.subjects.FAKE_REELS.next(this.componentConfiguration.fakeReels);\n        this.rootStore.subjects.RESPIN_FAKE_REELS.next(this.componentConfiguration.respinFakeReels);\n        this.rootStore.subjects.FREE_SPINS_FAKE_REELS.next(this.componentConfiguration.freeSpinFakeReels);\n        this.rootStore.subjects.REELS_POSITION = new BehaviorSubject(this.componentConfiguration.reelsPosition);\n        this.rootStore.subjects.PORTRAIT_FIRST.next(this.componentConfiguration.portraitFirst);\n        this.rootStore.subjects.NUMBER_OF_REELS.next(this.componentConfiguration.numberOfReels);\n        this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.next(this.componentConfiguration.visibleSymbolsPerReel);\n        this.rootStore.subjects.TRANSPARENT_REELS.next(this.componentConfiguration.transparentReels);\n        this.rootStore.subjects.REEL_START_BOUNCE_TIME.next(this.componentConfiguration.reelStartBounceTime);\n        this.rootStore.subjects.REEL_STOP_BOUNCE_TIME.next(this.componentConfiguration.reelStopBounceTime);\n        this.rootStore.subjects.REEL_STOP_BOUNCE_PERCENT.next(this.componentConfiguration.reelStopBouncePercent);\n        this.rootStore.subjects.REEL_ROTATION_SPEED.next(this.componentConfiguration.reelRotationSpeed);\n        this.rootStore.subjects.REEL_ROTATION_DIRECTION.next(this.componentConfiguration.reelRotationDirection);\n        this.rootStore.subjects.GAME_INITIAL_REEL_ROTATION_TIME.next(\n            this.componentConfiguration.gameInitialReelRotationTime,\n        );\n        this.rootStore.subjects.GAME_INITIAL_REEL_ROTATION_TIME_IN_QUICK_SPIN.next(\n            this.componentConfiguration.gameInitialReelRotationTimeInQuickSpin,\n        );\n        this.rootStore.subjects.GAME_BETWEEN_REELS_DELAY.next(this.componentConfiguration.gameBetweenReelsDelay);\n        this.rootStore.subjects.GAME_BETWEEN_REELS_DELAY_IN_QUICK_SPIN.next(\n            this.componentConfiguration.gameBetweenReelsDelayInQuickSpin,\n        );\n        this.rootStore.subjects.MIN_TIME_REELS_PERCENT_DELAY.next(this.componentConfiguration.minTimeReelsPercentDelay);\n        this.rootStore.subjects.GAME_ANTICIPATION_REELS_DELAY.next(\n            this.componentConfiguration.gameAnticipationReelsDelay,\n        );\n        this.rootStore.subjects.NUMBER_OF_GUARD_SYMBOLS.next(this.componentConfiguration.numberOfGuardSymbols);\n        this.rootStore.subjects.PORTRAIT_SCALE.next(this.componentConfiguration.portraitScale);\n\n        this.createSymbols();\n        this.initialReelSettings();\n        this.rootStore.uiStore.FAKE_REELS.next(this.componentConfiguration.fakeReels);\n        this.rootStore.uiStore.REAL_REELS.next(this.settings.reels);\n    }\n\n    public initComplete(): void {\n        this.reels = this.view.reels;\n\n        for (let i = 0; i < this.rootStore.subjects.NUMBER_OF_REELS.value; i++) {\n            this.reels[i].STOPPED.pipe(takeUntil(this.DESTROY)).subscribe(this.onReelStopped.bind(this));\n            this.reels[i].BOUNCED.pipe(takeUntil(this.DESTROY)).subscribe(this.onReelBounced.bind(this));\n            this.rotatingReelsMap.set(i, false);\n            this.reelsTimings[i] = 0;\n            this.reelsStopSounds[i] = '';\n            this.reelsToStart[i] = i;\n        }\n\n        this.rootStore.subjects.SPIN_STARTED.pipe(takeUntil(this.DESTROY)).subscribe(this.start.bind(this));\n\n        this.rootStore.subjects.SPIN_STARTED_WITHOUT_NEW_REQUEST.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.startWithoutNewRequest.bind(this),\n        );\n\n        this.rootStore.subjects.CLEAR_CELLS.pipe(takeUntil(this.DESTROY)).subscribe(this.clearReels.bind(this));\n\n        this.rootStore.subjects.SHOW_CELLS.pipe(takeUntil(this.DESTROY)).subscribe(this.showReels.bind(this));\n\n        this.rootStore.subjects.TINT_REELS.pipe(takeUntil(this.DESTROY)).subscribe(this.onTintReels.bind(this));\n\n        Core.SHOW_ERROR.pipe(takeUntil(this.DESTROY)).subscribe(this.onErrorWithInsifitionsFunds.bind(this));\n\n        this.rootStore.uiStore.REAL_REELS.pipe(takeUntil(this.DESTROY)).subscribe(this.onReelsChanged.bind(this));\n        this.rootStore.subjects.REDRAW_REELS.pipe(takeUntil(this.DESTROY)).subscribe(this.redrawReels.bind(this));\n\n        this.PREPARE_REEL_ACCELERATION.pipe(takeUntil(this.DESTROY)).subscribe(this.prepareReelAcceleration.bind(this));\n\n        this.updateCbk = this.update.bind(this);\n\n        Core.stage.ticker.add(this.updateCbk, this);\n    }\n\n    public destroy(): void {\n        this.stopAllRequested = true;\n        this.rootStore.subjects.REELS_FORCE_STOP.next(true);\n        Core.stage.ticker.remove(this.updateCbk, this);\n        // @ts-ignore\n        delete this.reels;\n        // @ts-ignore\n        delete this.view;\n        super.destroy.apply(this, arguments);\n    }\n\n    public update(): void {\n        for (const reel of this.reels) {\n            reel.draw(Core.stage.ticker.deltaMS);\n        }\n    }\n\n    public start(startConfig?: any): void {\n        if (this.areReelsRotating) {\n            return;\n        }\n        this.rootStore.subjects.ARE_REELS_ROTATING.next(true);\n        PostMessageDispatcher.reelsStarted();\n        AnalyticsDispatcher.onSpinStarted({\n            orientation: String(Core.ORIENTATION.value.orientation).toLowerCase(),\n            desktop: Core.isDesktopMode,\n            spinMode: this.rootStore.domainStore.SPIN_MODE.value,\n        });\n\n        if (startConfig && startConfig.reelsToStart) {\n            this.lastStartedReel = startConfig.reelsToStart[startConfig.reelsToStart.length - 1];\n        } else {\n            this.lastStartedReel = this.rootStore.subjects.NUMBER_OF_REELS.value - 1;\n        }\n        this.mainSoundsLoaded = this.mainSoundsLoaded || Core.sounds.soundAssetLoaded('mainSounds');\n        this.isResultReceived = false;\n        this.stopAllRequested = false;\n        this.rootStore.subjects.REELS_FORCE_STOP.next(false);\n        this.rootStore.subjects.REELS_START.next();\n        this.rootStore.domainStore.BET.pipe(first()).subscribe(this.onBetChanged.bind(this));\n\n        const waitForInitialRotationTime = from(\n            startConfig?.reelsToStart ? (startConfig.reelsToStart as number[]) : this.reelsToStart,\n        ).pipe(\n            map((index) => {\n                this.reels[index].start();\n\n                this.rotatingReelsMap.set(index, true);\n                return index;\n            }),\n            toArray(),\n            delay(this.initialRotationTime(startConfig)),\n        );\n\n        // Create Stop All Stream\n        const stopAllStream = zip(\n            waitForInitialRotationTime,\n            this.rootStore.domainStore.BET,\n            this.rootStore.subjects.REELS_STOP_ALL,\n        ).pipe(takeUntil(this.rootStore.subjects.REELS_STOPPED));\n\n        zip(waitForInitialRotationTime, this.rootStore.domainStore.BET)\n            .pipe(\n                switchMap(() =>\n                    from(startConfig?.reelsToStart ? (startConfig.reelsToStart as number[]) : this.reelsToStart),\n                ),\n                concatMap((reelIndex) => {\n                    if (\n                        !this.rootStore.subjects.REEL_ACCELERATE_DISBALED.value &&\n                        this.shouldReelAccelerate(startConfig, reelIndex)\n                    ) {\n                        this.PREPARE_REEL_ACCELERATION.next(reelIndex);\n                    }\n                    this.reelStartStopping(reelIndex);\n                    return of(reelIndex).pipe(\n                        delay(\n                            startConfig?.reelsTimings\n                                ? startConfig.reelsTimings[reelIndex]\n                                : this.reelsTimings[reelIndex],\n                        ),\n                    );\n                }),\n                takeUntil(merge(this.rootStore.subjects.REELS_STOPPED, this.DESTROY, stopAllStream)),\n            )\n            .subscribe(this.onStopReelTimer.bind(this));\n\n        this.subscribeToStopAllStream(stopAllStream, startConfig);\n\n        if (this.rootStore.uiStore.turboModeEnabled && !this.rootStore.uiStore.disableSpecialSpinSpeedForCurrentState) {\n            Timers.setTimeout(() => {\n                this.stopAll();\n            }, this.componentConfiguration.delayBeforeStopAllIsCalledInTurbo);\n        }\n    }\n\n    public startWithoutNewRequest(startConfig?: any): void {\n        if (startConfig?.reelsToStart) {\n            (startConfig.reelsToStart as number[]).map((index) => {\n                this.reels[index].start();\n\n                this.rotatingReelsMap.set(index, true);\n                return index;\n            });\n        }\n    }\n\n    public onTintReels(tint: boolean): void {\n        this.reels.forEach((reel) => {\n            reel.tintAllCells(tint);\n        });\n    }\n\n    public stopAll(): void {\n        if (!this.areReelsRotating) {\n            return;\n        }\n\n        if (this.isResultReceived) {\n            // align all unstopped reels to a single offset, so they'll stop at once\n            const offset =\n                this.rootStore.subjects.REELS_POSITION.value.reelHeight / this.slotConfiguration.numberOfGameSymbols;\n            const length = this.reels.length;\n            for (let i = 0; i < length; i++) {\n                if (this.componentConfiguration.useReelStopEffectAnim && this.reels[i].getState() === 2) {\n                    this.view.showReelStopEffect(i);\n                }\n                this.reels[i].stop(offset);\n            }\n        }\n\n        this.stopAllRequested = true;\n        this.rootStore.subjects.REELS_FORCE_STOP.next(true);\n    }\n\n    public onBetChanged(betResponse: BetResponse): void {\n        this.rootStore.uiStore.REAL_REELS.next(betResponse.reels.slice().map((a) => a.slice()));\n        this.calculateReelTimings(betResponse);\n        this.getSoundsForReels(betResponse);\n        this.resultReceived();\n    }\n\n    public resultReceived(): void {\n        this.isResultReceived = true;\n        if (this.stopAllRequested) {\n            this.stopAll();\n        }\n    }\n\n    public getSoundsForReels(betResponse: BetResponse): void {\n        this.scattersCount = 0;\n        from(betResponse.reels.slice().map((a) => a.slice()))\n            .pipe(\n                map((reel, index) => {\n                    this.scattersCount += this.countFSScatterOnReel(reel);\n                    if (this.spinAnalyzer.shouldPlayWildStopSound(index)) {\n                        if (\n                            Array.isArray(\n                                this.spinAnalyzer.getSybmolFromIndex(this.spinAnalyzer.getWildIndex()).stopWildSound(),\n                            )\n                        ) {\n                            const wildSounds: string[] = this.spinAnalyzer\n                                .getSybmolFromIndex(this.spinAnalyzer.getWildIndex())\n                                .stopWildSound();\n                            if (wildSounds[index] !== '') {\n                                return wildSounds[index];\n                            } else {\n                                return this.spinAnalyzer.getReelStopSound(this.scattersCount, index);\n                            }\n                        } else {\n                            return this.spinAnalyzer\n                                .getSybmolFromIndex(this.spinAnalyzer.getWildIndex())\n                                .stopWildSound();\n                        }\n                    } else {\n                        return this.spinAnalyzer.getReelStopSound(this.scattersCount, index);\n                    }\n                }),\n                toArray(),\n            )\n            .subscribe((calculatedTimings) => {\n                this.reelsStopSounds = calculatedTimings;\n            });\n    }\n\n    public getReelsStopSounds(): string[] {\n        return this.reelsStopSounds;\n    }\n\n    public calculateReelTimings(betResponse: BetResponse): void {\n        this.scattersCount = 0;\n        from(betResponse.reels.slice().map((a) => a.slice()))\n            .pipe(\n                map((reel, index) => {\n                    const result = this.spinAnalyzer.getReelStopDelay(this.scattersCount, index);\n                    this.scattersCount += this.countFSScatterOnReel(reel);\n                    return result;\n                }),\n                toArray(),\n            )\n            .subscribe((calculatedTimings) => {\n                this.reelsTimings = calculatedTimings;\n            });\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public getReelAccelerateSound(reelIndex: number): string {\n        return 'reelAccelerateSound';\n    }\n\n    protected initialRotationTime(startConfig?: any): number {\n        const numberOfReels = startConfig?.reelsToStart?.length ? startConfig?.reelsToStart?.length : this.reels.length;\n        const minimumSpinTime = this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value;\n        const totalReelDelay = (numberOfReels - 1) * this.componentConfiguration.gameBetweenReelsDelay;\n        const lastReelStopTime =\n            (this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value + 1) *\n                this.componentConfiguration.reelRotationSpeed +\n            this.componentConfiguration.reelStopBounceTime * 1000;\n        const totalSpinTime = totalReelDelay + lastReelStopTime;\n        return Math.max(\n            this.rootStore.uiStore.quickSpinEnabled && !this.rootStore.uiStore.disableSpecialSpinSpeedForCurrentState\n                ? this.componentConfiguration.gameInitialReelRotationTimeInQuickSpin\n                : this.componentConfiguration.gameInitialReelRotationTime,\n            minimumSpinTime - totalSpinTime,\n        );\n    }\n\n    protected countFSScatterOnReel(reel: number[]): number {\n        reel.shift();\n        reel.pop();\n        if (this.rootStore.subjects.REEL_ACCELERATE_DISBALED.value) {\n            return 0;\n        }\n        return reel.filter(\n            (symbolIndex) =>\n                symbolIndex ===\n                (this.spinAnalyzer.anticipateScatterSymbol ? this.spinAnalyzer.anticipateScatterSymbol.index : -1),\n        ).length;\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    protected reelStartStopping(reelIndex: number): void {\n        // hook method implementing custom logic when reels start stopping\n    }\n\n    protected playSounds(reelIndex: number): void {\n        if (!this.stopAllRequested && this.mainSoundsLoaded) {\n            Core.sounds.play(this.reelsStopSounds[reelIndex]);\n        }\n    }\n\n    protected onReelStopped(reel: ReelDesktopForLandscape): void {\n        this.rootStore.subjects.REEL_STOPPED.next(reel);\n        this.rotatingReelsMap.set(reel.getIndex(), false);\n        if (this.areReelsRotating) {\n            return;\n        }\n\n        this.onAllReelsStopped();\n    }\n\n    protected onAllReelsStopped(): void {\n        this.scattersCount = 0;\n        if (!this.stopAllRequested || this.rootStore.subjects.SPIN_SPEED.value === 2) {\n            AnalyticsDispatcher.onReelsStopped({\n                quickMode: Boolean(this.rootStore.subjects.SPIN_SPEED.value === 1),\n                turboMode: Boolean(this.rootStore.subjects.SPIN_SPEED.value === 2),\n                specialSpinSpeedDisabled: this.rootStore.uiStore.disableSpecialSpinSpeedForCurrentState,\n            });\n        }\n\n        this.stopAllRequested = false;\n        this.rootStore.subjects.REELS_FORCE_STOP.next(false);\n        this.rootStore.subjects.ARE_REELS_ROTATING.next(false);\n        this.rootStore.subjects.REELS_STOPPED.next();\n        PostMessageDispatcher.reelsStopped();\n    }\n\n    protected prepareReelAcceleration(reelIndex: number): void {\n        if (reelIndex > 0 && this.rotatingReelsMap.get(reelIndex - 1)) {\n            this.reels[reelIndex - 1].BOUNCED.pipe(\n                takeUntil(\n                    merge(\n                        this.rootStore.subjects.REELS_STOPPED,\n                        this.DESTROY,\n                        this.reels[reelIndex - 1].STOPPED,\n                        this.rootStore.subjects.REELS_STOP_ALL,\n                    ),\n                ),\n                take(1),\n            ).subscribe(() => {\n                Core.sounds.play(this.getReelAccelerateSound(reelIndex));\n                this.rootStore.subjects.REEL_ACCELERATE.next(this.reels[reelIndex]);\n            });\n        } else {\n            Core.sounds.play(this.getReelAccelerateSound(reelIndex));\n            this.rootStore.subjects.REEL_ACCELERATE.next(this.reels[reelIndex]);\n        }\n    }\n\n    protected onReelBounced(reel: ReelDesktopForLandscape): void {\n        this.rootStore.subjects.REEL_BOUNCED.next(reel);\n        if (this.stopAllRequested) {\n            if (reel.getIndex() === this.lastStartedReel) {\n                Core.sounds.stop('spinSound');\n                Core.sounds.stop(this.getReelAccelerateSound(reel.getIndex()));\n                Core.sounds.stop('stopReelSound');\n                (this.rootStore.uiStore.turboModeEnabled || this.rootStore.subjects.TOGGLE_TURBO_SPIN.value) &&\n                !this.rootStore.uiStore.disableSpecialSpinSpeedForCurrentState\n                    ? Core.sounds.play('turboReelsStop')\n                    : Core.sounds.play('stopReelAllSound');\n            }\n        }\n    }\n\n    protected redrawReels(): void {\n        this.reels.forEach((reel) => {\n            reel.redraw();\n        });\n    }\n\n    protected createSymbols(): void {\n        const symbols: ISymbol[] = [];\n        const emptyTexture = new Texture(\n            new BaseTexture(undefined, {\n                width: this.rootStore.subjects.REELS_POSITION.value.reelWidth,\n                height: this.rootStore.subjects.REELS_POSITION.value.symbolHeight,\n            }),\n        );\n        this.slotConfiguration.symbolsConfig.forEach((item: any) => {\n            let sprite: string = 'symbols';\n            if (item.spriteID) {\n                sprite = item.spriteID;\n            }\n            const symbol: ISymbol = new SymbolBase(\n                item.texture ? Core.assets.getTextureFromSpriteSheet(sprite, item.texture) : emptyTexture,\n                item.topTexture ? Core.assets.getTextureFromSpriteSheet(sprite, item.topTexture) : emptyTexture,\n                item.blurredTexture ? Core.assets.getTextureFromSpriteSheet(sprite, item.blurredTexture) : emptyTexture,\n\n                item.index,\n                item.name,\n                item.video,\n                item.expandVideo,\n                item.expandSound,\n                item.isScatter,\n                item.isStackedScatter,\n                item.isVerticalStackedSymbol,\n                item.isWild,\n                item.stopWildSound,\n                item.scatterConfig,\n                item.stopVideo,\n            );\n            symbols.push(symbol);\n        });\n\n        this.slotConfiguration.symbols = symbols;\n    }\n\n    protected initialReelSettings(): void {\n        let restore: any;\n        if (this.settings.settings.game?.restore) {\n            restore = this.settings.settings.game?.restore[this.settings.settings.game?.result?.restorePoints[0]];\n        }\n        if (\n            (!this.settings.settings.game?.result?.spins || !this.settings.settings.game?.result?.spins[0]?.reels) &&\n            (!restore || !restore.spins[0].reels)\n        ) {\n            let reels: number[][] = [];\n            if (this.slotConfiguration.initialReels !== null) {\n                reels = this.slotConfiguration.initialReels;\n            } else {\n                for (let i: number = 0; i < this.rootStore.subjects.NUMBER_OF_REELS.value; i++) {\n                    reels.push(\n                        this.componentConfiguration.initialReels[i].slice(\n                            0,\n                            this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value +\n                                this.rootStore.subjects.NUMBER_OF_GUARD_SYMBOLS.value,\n                        ),\n                    );\n                }\n            }\n\n            this.settings.reels = reels;\n        }\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    protected subscribeToStopAllStream(stopAllStream: any, startConfig?): void {\n        stopAllStream.subscribe(this.stopAll.bind(this));\n    }\n\n    protected shouldReelAccelerate(startConfig: any, reelIndex: number): boolean {\n        return (\n            (startConfig?.reelsTimings ? startConfig.reelsTimings[reelIndex] : this.reelsTimings[reelIndex]) ===\n            this.componentConfiguration.gameAnticipationReelsDelay\n        );\n    }\n\n    private onErrorWithInsifitionsFunds(error: IErrorData): void {\n        const errorCode = error.code.toString();\n        if ((errorCode === '4813' || errorCode === '4818') && this.areReelsRotating) {\n            this.stopAllRequested = true;\n            this.rootStore.subjects.REELS_FORCE_STOP.next(true);\n            const obj = {\n                referenceId: error.payload.referenceId,\n                sessionKey: error.payload.sessionKey,\n                event: error.payload.event,\n                balance: error.payload.balance,\n                game: {\n                    state: {\n                        matchId: this.rootStore.settings.matchId,\n                        bet: {\n                            level: this.rootStore.uiStore.SELECTED_BET.value,\n                            factor: this.rootStore.settings.factor,\n                            denomination: Core.SELECTED_DENOMINATION.value,\n                            lines: this.rootStore.uiStore.LINES.value,\n                        },\n                        totalWin: '0',\n                        totalWinAmount: '0',\n                        gambles: 0,\n                    },\n                    result: {\n                        spins: [\n                            {\n                                entries: [],\n                                mutations: [],\n                                totalWinAmount: '0',\n                                reels: this.rootStore.uiStore.REAL_REELS.value,\n                                type: 'SPIN',\n                                bonuses: [],\n                                totalWin: 0,\n                            },\n                        ],\n                    },\n                },\n                state: 'idle',\n                context: {},\n            };\n            this.rootStore.domainStore.setBet(obj, 0);\n            this.rootStore.domainStore.setBalance(obj);\n        }\n    }\n\n    private clearReels(cells: []): void {\n        cells.forEach((cell) => {\n            // @ts-ignore\n            this.reels[cell.row].clearCell(cell.col);\n        });\n    }\n\n    private showReels(cells: []): void {\n        cells.forEach((cell) => {\n            // @ts-ignore\n            this.reels[cell.row].showCell(cell.col);\n        });\n    }\n\n    protected onStopReelTimer(index: any): void {\n        if (\n            (this.rootStore.uiStore.turboModeEnabled &&\n                !this.rootStore.uiStore.disableSpecialSpinSpeedForCurrentState) ||\n            this.stopAllRequested\n        ) {\n            return;\n        }\n\n        this.reels[index].stop();\n        if (this.componentConfiguration.useReelStopEffectAnim) {\n            this.view.showReelStopEffect(index);\n        }\n        of(index)\n            .pipe(delay(this.componentConfiguration.reelStopBounceTime * 1000))\n            .subscribe(this.playSounds.bind(this));\n    }\n\n    private onReelsChanged(): void {\n        this.view.onReelsChanged(this.rootStore.uiStore.REAL_REELS.value);\n    }\n}\n","const enum ReelStateDesktopForLandscape {\n    REEL_IDLE = 0,\n    REEL_STARTING = 1,\n    REEL_ROTATING = 2,\n    REEL_STOPPING = 3,\n    REEL_BOUNCING = 4,\n}\nexport default ReelStateDesktopForLandscape;\n","import { Log } from '@egt/core';\nimport { ISlotConfiguration, ISymbol, RootStore } from '@egt/slot';\nimport { gsap } from 'gsap';\nimport { BaseTexture, Container, Point, Sprite, Texture } from 'pixi.js';\nimport { BehaviorSubject, Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { injectable } from 'tsyringe';\nimport { IReelsComponentConfigurationDesktopForLandscape } from '../configuration/IReelsComponentConfigurationDesktopForLandscape';\nimport ReelStateDesktopForLandscape from '../enums/ReelStateDesktopForLandscape';\n\n@injectable()\nexport default class ReelDesktopForLandscape {\n    protected static readonly EMPTY_IMAGE_INDEX = -1;\n    protected static readonly FAKE_IMAGE_INDEX = -2;\n\n    public readonly BOUNCED = new Subject();\n    public readonly STOPPED = new Subject();\n    public readonly DESTROY: Subject<void> = new Subject<void>();\n    public sprites: any;\n    public topSprites: any;\n    public imageIndex: number;\n\n    public _x: number;\n    public _y: number;\n\n    public clearedCellsIndex: number[];\n\n    protected isTinted: boolean = false;\n    protected tintColor: number = 0x797979;\n    protected spritesCardIndexMap: Map<number, number> = new Map();\n\n    protected tween: any;\n    protected fakeReel: any;\n    protected realReel: any;\n    protected _offset: number; // current offset in the reel (in pixels)\n    protected result: any = null;\n    protected bounce: number = 0;\n    protected reelLength: number = 0;\n    protected finalOffset: number = 0;\n    protected distToEnd: number = -1;\n    protected resultIndex: number = -1;\n    protected drawnOnce: boolean = false;\n    protected rotating: boolean = false;\n    protected stopAfterStart: boolean = false;\n    protected state: BehaviorSubject<number> = new BehaviorSubject<number>(ReelStateDesktopForLandscape.REEL_IDLE);\n    protected dispatchStop: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n\n    protected parent: any;\n    protected sprite: any;\n    protected topSprite: any;\n    protected spriteIndex: number;\n    protected spriteY: number;\n    protected imageHeight: number;\n    protected image: any;\n    protected rotationSpeed: number;\n    protected reelPixels: number;\n\n    // set to false on Reels with mask and remove after we make all the reels with masks\n\n    constructor(\n        protected _config: ISlotConfiguration,\n        protected rootStore: RootStore,\n        protected overlayContainer: Container,\n        protected reelIndex: number,\n        protected setIndexes: boolean,\n        protected componentConfiguration: IReelsComponentConfigurationDesktopForLandscape,\n    ) {\n        this.init();\n    }\n    public init(): void {\n        this._x =\n            this.rootStore.subjects.REELS_POSITION.value.reelX +\n            this.rootStore.subjects.REELS_POSITION.value.reelWidth / 2 +\n            this.reelIndex *\n                (this.rootStore.subjects.REELS_POSITION.value.reelWidth +\n                    this.rootStore.subjects.REELS_POSITION.value.reelSpacing);\n        this._y =\n            this.rootStore.subjects.REELS_POSITION.value.reelY +\n            this.rootStore.subjects.REELS_POSITION.value.symbolHeight / 2;\n\n        this.sprites = [];\n        this.topSprites = [];\n        this.clearedCellsIndex = [];\n        this.imageHeight = this.rootStore.subjects.REELS_POSITION.value.symbolHeight;\n\n        this._offset = this.rootStore.subjects.REELS_POSITION.value.symbolHeight;\n\n        this.bounce = Math.floor(\n            (this.rootStore.subjects.REEL_ROTATION_DIRECTION.value *\n                this.rootStore.subjects.REELS_POSITION.value.symbolHeight *\n                this.componentConfiguration.reelStopBouncePercent) /\n                100,\n        );\n        this.state.pipe(takeUntil(this.DESTROY)).subscribe(this.onStateChanged.bind(this));\n        this.dispatchStop.pipe(takeUntil(this.DESTROY)).subscribe(this.dispatchEventOnStop.bind(this));\n\n        this._config.symbols.forEach((symbol: ISymbol) => {\n            this.rootStore.texturesMap.set(symbol.index(), symbol.texture());\n            this.rootStore.topTexturesMap.set(symbol.index(), symbol.topTexture());\n            this.rootStore.blurredTexturesMap.set(symbol.index(), symbol.blurredTexture());\n        });\n        this.rootStore.texturesMap.set(\n            ReelDesktopForLandscape.EMPTY_IMAGE_INDEX,\n            new Texture(new BaseTexture(undefined)),\n        );\n        this.rootStore.topTexturesMap.set(\n            ReelDesktopForLandscape.EMPTY_IMAGE_INDEX,\n            new Texture(new BaseTexture(undefined)),\n        );\n        this.rootStore.blurredTexturesMap.set(\n            ReelDesktopForLandscape.EMPTY_IMAGE_INDEX,\n            new Texture(new BaseTexture(undefined)),\n        );\n\n        this.createSprites();\n    }\n\n    public dispatchEventOnStop(): void {\n        if (this.dispatchStop.value) {\n            this.state.next(ReelStateDesktopForLandscape.REEL_IDLE);\n            this.dispatchStop.next(false);\n            this.STOPPED.next(this);\n        }\n    }\n\n    public getSetOffset(value?: number): number | undefined {\n        if (value === undefined) {\n            return this._offset;\n        } else {\n            this._offset = value;\n        }\n    }\n\n    public getIndex(): number {\n        return this.reelIndex;\n    }\n\n    public getState(): number {\n        switch (this.state.value) {\n            case ReelStateDesktopForLandscape.REEL_STARTING:\n            case ReelStateDesktopForLandscape.REEL_ROTATING:\n                return ReelStateDesktopForLandscape.REEL_ROTATING;\n            case ReelStateDesktopForLandscape.REEL_STOPPING:\n            case ReelStateDesktopForLandscape.REEL_BOUNCING:\n                return ReelStateDesktopForLandscape.REEL_STOPPING;\n        }\n        return ReelStateDesktopForLandscape.REEL_IDLE;\n    }\n\n    public changeFakeReel(arr: any): void {\n        this.reelLength = arr.length;\n        this.fakeReel = [];\n        this.realReel = [];\n        let i: number;\n        for (i = 0; i < this.reelLength; i++) {\n            this.fakeReel[i] = arr[i];\n            this.realReel[i] = ReelDesktopForLandscape.FAKE_IMAGE_INDEX;\n        }\n        const len = this.result.length;\n        for (i = 0; i < len; i++) {\n            this.realReel[i] = this.result[i];\n        }\n        this._offset = this.rootStore.subjects.REELS_POSITION.value.symbolHeight;\n    }\n\n    public setFakeReel(arr: any): void {\n        let updateFakeReels: boolean = false;\n        if (this.fakeReel) {\n            Log.debug('Changing fake reels!', this.constructor.name);\n            updateFakeReels = true;\n        }\n\n        this.reelLength = arr.length;\n        this.reelPixels = this.reelLength * this.imageHeight;\n        this.fakeReel = [];\n        if (!updateFakeReels) {\n            this.realReel = [];\n        }\n        for (let i = 0; i < this.reelLength; i++) {\n            this.fakeReel[i] = arr[i];\n            if (!updateFakeReels) {\n                this.realReel[i] = ReelDesktopForLandscape.FAKE_IMAGE_INDEX;\n            }\n        }\n        this.result = [];\n        this.clearResult();\n    }\n\n    public setResult(result: any, showNow?: boolean): void {\n        let image = (this.getCurrentTopImage() + this.reelLength - 1) % this.reelLength;\n        const len =\n            this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value +\n            this.rootStore.subjects.NUMBER_OF_GUARD_SYMBOLS.value;\n        if (showNow) {\n            this.resultIndex = image;\n        }\n        for (let i = 0; i < len; i++) {\n            if (showNow) {\n                this.realReel[image] = result[i];\n                image = (image + 1) % this.reelLength;\n            }\n            this.result[i] = result[i];\n        }\n        this.drawnOnce = false;\n        if (showNow) {\n            this.draw(1);\n        }\n    }\n\n    public getResult(): number[] {\n        return this.result;\n    }\n\n    public start(): void {\n        if (this.state.value === ReelStateDesktopForLandscape.REEL_IDLE) {\n            this.showAllCells();\n            this.clearResult();\n            /////////////////////////////////////////////////////////////////////////////////\n            // Workaround for #22\n            this._offset =\n                this._offset % (this.rootStore.subjects.REELS_POSITION.value.symbolHeight * this.fakeReel.length);\n            /////////////////////////////////////////////////////////////////////////////////\n            this.state.next(ReelStateDesktopForLandscape.REEL_STARTING);\n            this.stopAfterStart = false;\n        }\n    }\n\n    public stop(distToEnd?: number): void {\n        if (distToEnd === undefined) {\n            distToEnd = 0;\n        }\n        switch (this.state.value) {\n            case ReelStateDesktopForLandscape.REEL_STARTING:\n                this.distToEnd = -1;\n                this.stopAfterStart = true;\n                break;\n            case ReelStateDesktopForLandscape.REEL_ROTATING:\n                this.distToEnd = distToEnd;\n                this.state.next(ReelStateDesktopForLandscape.REEL_STOPPING);\n                break;\n            case ReelStateDesktopForLandscape.REEL_STOPPING:\n                this._offset =\n                    this.finalOffset -\n                    (this.rootStore.subjects.REEL_ROTATION_DIRECTION.value === 1 ? distToEnd : -distToEnd);\n                break;\n        }\n    }\n\n    public getDistToStop(): number {\n        if (this.state.value === ReelStateDesktopForLandscape.REEL_STOPPING) {\n            return Math.abs(this._offset - this.finalOffset);\n        }\n        return -1;\n    }\n\n    public getDistToRest(): number {\n        if (this.state.value === ReelStateDesktopForLandscape.REEL_BOUNCING) {\n            return Math.abs(this._offset - (this.finalOffset - this.bounce));\n        }\n        return -1;\n    }\n\n    public clearCell(cell: number): void {\n        if (this.sprites[cell]) {\n            this.sprites[cell].visible = false;\n        }\n        if (this.topSprites[cell]) {\n            this.topSprites[cell].visible = false;\n        }\n        this.clearedCellsIndex.push(cell);\n    }\n\n    public redraw(): void {\n        this.drawnOnce = false;\n        this.draw(1);\n    }\n\n    public refreshLayout(): void {\n        const previousSymbolHeight = this.imageHeight || this.rootStore.subjects.REELS_POSITION.value.symbolHeight;\n        const currentSymbolHeight = this.rootStore.subjects.REELS_POSITION.value.symbolHeight;\n        const symbolScale = this.rootStore.subjects.REELS_POSITION.value.symbolScale;\n        const resizeRatio = previousSymbolHeight !== 0 ? currentSymbolHeight / previousSymbolHeight : 1;\n\n        if (resizeRatio !== 1) {\n            this._offset *= resizeRatio;\n            this.finalOffset *= resizeRatio;\n            if (this.distToEnd > 0) {\n                this.distToEnd *= resizeRatio;\n            }\n        }\n\n        this.imageHeight = currentSymbolHeight;\n        this.bounce = Math.floor(\n            (this.rootStore.subjects.REEL_ROTATION_DIRECTION.value *\n                currentSymbolHeight *\n                this.componentConfiguration.reelStopBouncePercent) /\n                100,\n        );\n        this.reelPixels = this.reelLength * this.imageHeight;\n\n        this.sprites.forEach((sprite) => {\n            sprite.scale.set(symbolScale, symbolScale);\n        });\n        this.topSprites.forEach((sprite) => {\n            sprite.scale.set(symbolScale, symbolScale);\n        });\n\n        if (this.tween && resizeRatio !== 1) {\n            this.tween.vars.getSetOffset *= resizeRatio;\n            this.tween.invalidate();\n        }\n    }\n\n    public draw(compensation: number): void {\n        if (this.shouldDrawReel()) {\n            return;\n        }\n\n        this.drawnOnce = true;\n        this.rotationSpeed = 0;\n        if (this.rotating) {\n            this.rotationSpeed =\n                (this.rootStore.subjects.REELS_POSITION.value.symbolHeight /\n                    this.componentConfiguration.reelRotationSpeed) *\n                compensation *\n                this.rootStore.subjects.REEL_ROTATION_DIRECTION.value;\n        }\n\n        let offset = this._offset;\n        this._offset += this.rotationSpeed;\n\n        if (this.state.value === ReelStateDesktopForLandscape.REEL_STOPPING) {\n            if (\n                (this.rootStore.subjects.REEL_ROTATION_DIRECTION.value === 1 && this._offset >= this.finalOffset) ||\n                (this.rootStore.subjects.REEL_ROTATION_DIRECTION.value === -1 && this._offset <= this.finalOffset)\n            ) {\n                this._offset = this.finalOffset;\n                this.state.next(ReelStateDesktopForLandscape.REEL_BOUNCING);\n            }\n        }\n\n        offset = offset % this.reelPixels;\n        if (offset < 0) {\n            offset = this.reelPixels + offset;\n        }\n\n        this.imageIndex = Math.floor(offset / this.imageHeight);\n\n        if (this.rootStore.subjects.REEL_ROTATION_DIRECTION.value === 1) {\n            this.realReel[(this.imageIndex + this.reelLength - 1) % this.reelLength] =\n                ReelDesktopForLandscape.EMPTY_IMAGE_INDEX;\n        }\n\n        this.spriteY = -(offset % this.imageHeight);\n        this.spriteIndex = 0;\n\n        while (\n            this.spriteY <=\n            this.imageHeight * Math.round(this.rootStore.subjects.REELS_POSITION.value.reelHeight / this.imageHeight)\n        ) {\n            this.image = this.realReel[this.imageIndex];\n            if (this.image === ReelDesktopForLandscape.FAKE_IMAGE_INDEX) {\n                this.image = this.fakeReel[this.imageIndex];\n            }\n            this.sprite = this.sprites[this.spriteIndex];\n            this.topSprite = this.topSprites[this.spriteIndex];\n\n            this.spritesCardIndexMap.set(this.spriteIndex, this.image);\n            if (\n                this.componentConfiguration.useBlurredReels &&\n                (this.state.value === ReelStateDesktopForLandscape.REEL_ROTATING ||\n                    this.state.value === ReelStateDesktopForLandscape.REEL_STOPPING)\n            ) {\n                this.sprite.texture = this.rootStore.blurredTexturesMap.get(this.image);\n                this.topSprite.texture = this.rootStore.blurredTexturesMap.get(this.image);\n            } else {\n                this.sprite.texture = this.rootStore.texturesMap.get(this.image);\n                this.topSprite.texture = this.rootStore.topTexturesMap.get(this.image);\n            }\n\n            this.sprite.x = this._x /*+ (this.config.reelWidth - sprite.width) / 2*/;\n            this.sprite.y = this.spriteY + this._y;\n\n            if (this._config.noTintedSymbols && this._config.noTintedSymbols.indexOf(this.image) !== -1) {\n                this.sprite.tint = 0xffffff; // NO TINT\n                this.topSprite.tint = 0xffffff; // NO TINT\n            } else {\n                if (this.isTinted) {\n                    this.sprite.tint = this.tintColor;\n                    this.topSprite.tint = this.tintColor;\n                }\n            }\n\n            // This is a hook for extention\n            this.drawHook(this.sprite, this.topSprite, this.image);\n\n            this.parent = this.topSprite.parent;\n\n            if (this.setIndexes) {\n                if (\n                    (this.state.value === ReelStateDesktopForLandscape.REEL_IDLE ||\n                        this.state.value === ReelStateDesktopForLandscape.REEL_BOUNCING) &&\n                    this.topSprite.height > this.rootStore.subjects.REELS_POSITION.value.symbolHeight &&\n                    Math.floor(this.spriteY) >= 0\n                ) {\n                    if (this.parent.getChildIndex(this.overlayContainer) > this.parent.getChildIndex(this.topSprite)) {\n                        this.parent.setChildIndex(this.topSprite, this.parent.getChildIndex(this.overlayContainer));\n                    }\n                    this.setTopSpritesOrder();\n                } else {\n                    this.parent.setChildIndex(this.topSprite, this.parent.getChildIndex(this.overlayContainer) - 1);\n                }\n            }\n\n            this.topSprite.x = this.sprite.x;\n            this.topSprite.y = this.sprite.y;\n\n            if (\n                ((this.state.value === ReelStateDesktopForLandscape.REEL_IDLE &&\n                    this.spriteIndex === this.sprites.length - 1) ||\n                    (this.state.value === ReelStateDesktopForLandscape.REEL_BOUNCING &&\n                        this.topSprite.y + this.topSprite.height / 2 - (this.topSprite.height - this.imageHeight) / 2 >=\n                            this.rootStore.subjects.REELS_POSITION.value.reelHeight + this._y)) &&\n                this.topSprite.height > this.rootStore.subjects.REELS_POSITION.value.symbolHeight\n            ) {\n                this.topSprite.visible = false;\n            } else if (this.clearedCellsIndex.indexOf(this.spriteIndex) === -1) {\n                this.topSprite.visible = true;\n            }\n\n            this.spriteY += this.imageHeight;\n\n            this.imageIndex = (this.imageIndex + 1) % this.reelLength;\n            this.spriteIndex++;\n        }\n\n        if (this.rootStore.subjects.REEL_ROTATION_DIRECTION.value === -1) {\n            const stopIndex =\n                this.resultIndex === -1\n                    ? (this.getCurrentTopImage() + this.reelLength - 2) % this.reelLength\n                    : (this.resultIndex + this.reelLength - 1) % this.reelLength;\n            do {\n                this.imageIndex++;\n                this.imageIndex = this.imageIndex % this.reelLength;\n                this.realReel[this.imageIndex] = ReelDesktopForLandscape.FAKE_IMAGE_INDEX;\n            } while (this.imageIndex !== stopIndex);\n        }\n    }\n\n    public removeSymbolFromRealReel(symbol): void {\n        this.realReel.forEach((el, index) => {\n            if (el === symbol) {\n                this.realReel[index] = -symbol;\n            }\n        });\n    }\n\n    public restoreSymbol(symbol): void {\n        this.realReel.forEach((el, index) => {\n            if (el === -symbol) {\n                this.realReel[index] = symbol;\n            }\n        });\n    }\n\n    public destroy(): void {\n        if (this.tween) {\n            this.tween.kill();\n            this.tween = null;\n        }\n        this.DESTROY.next();\n        this.DESTROY.complete();\n        if (this.sprites) {\n            this.sprites.forEach((spr) => {\n                spr.destroy();\n                // @ts-ignore\n                spr = null;\n            });\n            this.sprites.length = 0;\n            this.sprites = null;\n        }\n\n        if (this.topSprites) {\n            this.topSprites.forEach((spr) => {\n                spr.destroy();\n                // @ts-ignore\n                spr = null;\n            });\n            this.topSprites.length = 0;\n            // @ts-ignore;\n            this.topSprites = null;\n        }\n\n        this.spritesCardIndexMap.clear();\n        // @ts-ignore\n        this.spritesCardIndexMap = null;\n\n        this.state.complete();\n        // @ts-ignore\n        this.state = null;\n        this.dispatchStop.complete();\n        // @ts-ignore;\n        this.dispatchStop = null;\n\n        this.clearedCellsIndex.length = 0;\n        // @ts-ignore\n        this.clearedCellsIndex = null;\n\n        this.fakeReel.length = 0;\n        this.realReel.length = 0;\n        // @ts-ignore\n        this.fakeReel = null;\n        // @ts-ignore\n        this.realReel = null;\n    }\n\n    public showReel(): void {\n        // implement\n    }\n\n    public showCell(cell: number): void {\n        if (this.sprites[cell]) {\n            this.sprites[cell].visible = true;\n        }\n        if (this.topSprites[cell]) {\n            this.topSprites[cell].visible = true;\n        }\n        const clearedIndex = this.clearedCellsIndex.indexOf(cell);\n        if (clearedIndex !== -1) {\n            this.clearedCellsIndex.splice(clearedIndex, 1);\n        }\n\n        this.redraw();\n    }\n\n    public tintAllCells(tint: boolean = true): void {\n        this.isTinted = tint;\n        this.spritesCardIndexMap.forEach((value, key) => {\n            if (this._config.noTintedSymbols && this._config.noTintedSymbols.indexOf(value) === -1) {\n                this.sprites[key].tint = tint ? this.tintColor : 0xffffff;\n                this.topSprites[key].tint = tint ? this.tintColor : 0xffffff;\n            }\n        });\n    }\n\n    public tintCell(cell: number): void {\n        this.sprites[cell].tint = this.tintColor;\n        this.topSprites[cell].tint = this.tintColor;\n    }\n\n    protected shouldDrawReel(): boolean {\n        return this.state.value === ReelStateDesktopForLandscape.REEL_IDLE && this.drawnOnce;\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    protected drawHook(sprite: Sprite, topSpirte: Sprite, image: number): void {\n        return;\n    }\n\n    protected getCurrentTopImage(): number {\n        // this.reelPixels = this.rootStore.subjects.REELS_POSITION.value.symbolHeight * this.reelLength;\n        let idx = this._offset % this.reelPixels;\n        if (idx < 0) {\n            idx = this.reelPixels + idx;\n        }\n        return Math.floor(idx / this.rootStore.subjects.REELS_POSITION.value.symbolHeight);\n    }\n\n    protected setTopSpritesOrder(): void {\n        for (let i = 0; i < this.topSprites.length; i++) {\n            this.parent = this.topSprites[i].parent;\n            if (this.parent.getChildIndex(this.overlayContainer) < this.parent.getChildIndex(this.topSprites[i])) {\n                this.parent.setChildIndex(this.topSprites[i], this.parent.children.length - 1);\n            } else {\n                this.parent.setChildIndex(this.topSprites[i], this.parent.getChildIndex(this.overlayContainer) - 1);\n            }\n        }\n    }\n\n    protected onStateChanged(state: number): void {\n        switch (state) {\n            case ReelStateDesktopForLandscape.REEL_STARTING:\n                this.onReelStarting();\n                break;\n            case ReelStateDesktopForLandscape.REEL_ROTATING:\n                this.onReelRotating();\n                break;\n            case ReelStateDesktopForLandscape.REEL_STOPPING:\n                this.onReelStopping();\n                break;\n            case ReelStateDesktopForLandscape.REEL_BOUNCING:\n                this.onReelBouncing();\n                break;\n        }\n    }\n\n    protected showAllCells(): void {\n        for (const sprite of this.sprites) {\n            sprite.visible = true;\n        }\n    }\n\n    protected createSprites(): void {\n        for (let i = 0; i < this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value + 1; i++) {\n            this.sprites[i] = new Sprite(this.rootStore.texturesMap.get(0));\n            this.sprites[i].x = this._x;\n            this.sprites[i].anchor = new Point(0.5, 0.5);\n            this.spritesCardIndexMap.set(i, -1);\n            this.topSprites[i] = new Sprite(this.rootStore.topTexturesMap.get(0));\n            this.topSprites[i].x = this._x;\n            this.topSprites[i].anchor = new Point(0.5, 0.5);\n            this.sprites[i].scale = new Point(\n                this.rootStore.subjects.REELS_POSITION.value.symbolScale,\n                this.rootStore.subjects.REELS_POSITION.value.symbolScale,\n            );\n            this.topSprites[i].scale = new Point(\n                this.rootStore.subjects.REELS_POSITION.value.symbolScale,\n                this.rootStore.subjects.REELS_POSITION.value.symbolScale,\n            );\n        }\n    }\n\n    private clearResult(): void {\n        const len = this.result.length;\n        for (let i = 0; i < len; i++) {\n            this.result[i] = -1;\n        }\n    }\n\n    private onReelBouncing(): void {\n        this.BOUNCED.next(this);\n\n        this.rotating = false;\n        this.tween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/reels/src/egt/modes/desktopForLandscape/views/ReelDesktopForLandscape.ts:634:22\",null]), gsap.to(this, {\n            duration: this.componentConfiguration.reelStopBounceTime,\n            getSetOffset: this._offset - this.bounce,\n            ease: 'power2.out',\n            onComplete: this.onTweenEnd.bind(this),\n            onCompleteParams: [ReelStateDesktopForLandscape.REEL_IDLE],\n        }));\n    }\n\n    protected onReelStopping(): void {\n        const offset = this._offset;\n        let stopOffset =\n            offset +\n            this.rootStore.subjects.REEL_ROTATION_DIRECTION.value *\n                (this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value + 2) *\n                this.rootStore.subjects.REELS_POSITION.value.symbolHeight;\n\n        // --- round the offset forward along the reel movement to the closest symbol boundary\n\n        const frac = stopOffset % this.rootStore.subjects.REELS_POSITION.value.symbolHeight;\n        if (frac !== 0) {\n            if (this.rootStore.subjects.REEL_ROTATION_DIRECTION.value > 0) {\n                stopOffset += this.rootStore.subjects.REELS_POSITION.value.symbolHeight - frac;\n            } else if (stopOffset < 0) {\n                stopOffset -= this.rootStore.subjects.REELS_POSITION.value.symbolHeight + frac;\n            } else {\n                stopOffset -= frac;\n            }\n        }\n\n        // --- plant the real slots into the reel\n\n        this.reelPixels = this.reelLength * this.rootStore.subjects.REELS_POSITION.value.symbolHeight;\n        let img = stopOffset % this.reelPixels;\n        if (img < 0) {\n            img += this.reelPixels;\n        }\n        img = Math.floor(img / this.rootStore.subjects.REELS_POSITION.value.symbolHeight);\n\n        this.resultIndex = img;\n        const len = this.result.length;\n        for (let j = 0; j < len; ++j) {\n            this.realReel[img] = this.result[j];\n            img = (img + 1) % this.reelLength;\n        }\n        stopOffset -=\n            this.rootStore.subjects.REEL_ROTATION_DIRECTION.value *\n            this.rootStore.subjects.REELS_POSITION.value.symbolHeight; // compensate for the 1 guarding symbol of the real reel\n        stopOffset += this.bounce; // bounce\n        this.finalOffset = stopOffset;\n\n        if (this.distToEnd > 0) {\n            this._offset =\n                this.finalOffset -\n                (this.rootStore.subjects.REEL_ROTATION_DIRECTION.value === 1 ? this.distToEnd : -this.distToEnd);\n        }\n    }\n\n    private onReelRotating(): void {\n        this.rotating = true;\n\n        if (this.stopAfterStart) {\n            this.state.next(ReelStateDesktopForLandscape.REEL_STOPPING);\n        }\n    }\n\n    protected onReelStarting(): void {\n        this.rotating = false;\n        if (this.componentConfiguration.reelStartBounceTime > 0) {\n            this.tween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/reels/src/egt/modes/desktopForLandscape/views/ReelDesktopForLandscape.ts:703:26\",null]), gsap.to(this, {\n                duration: this.componentConfiguration.reelStartBounceTime,\n                getSetOffset:\n                    this._offset +\n                    this.rootStore.subjects.REEL_ROTATION_DIRECTION.value *\n                        this.rootStore.subjects.REELS_POSITION.value.symbolHeight,\n                ease: 'sine.in',\n                onComplete: this.onTweenEnd.bind(this),\n                onCompleteParams: [ReelStateDesktopForLandscape.REEL_ROTATING],\n            }));\n        } else {\n            this.state.next(ReelStateDesktopForLandscape.REEL_ROTATING);\n            // this.maskAllSprites();\n        }\n    }\n\n    private maskAllSprites(): void {\n        const length = this.sprites.length;\n        for (let i = 0; i < length; i++) {\n            this.topSprites[i].parent.setChildIndex(\n                this.topSprites[i],\n                this.topSprites[i].parent.getChildIndex(this.overlayContainer) - 1,\n            );\n        }\n    }\n\n    protected onTweenEnd(nextState: number): void {\n        if (nextState === ReelStateDesktopForLandscape.REEL_IDLE) {\n            this.dispatchStop.next(true);\n            this.drawnOnce = false;\n        } else {\n            this.state.next(nextState);\n        }\n        if (this.tween) {\n            this.tween.kill();\n        }\n        this.tween = null;\n    }\n}\n","import { ISlotConfiguration, RootStore } from '@egt/slot';\nimport { Container } from 'pixi.js';\nimport { inject, injectable } from 'tsyringe';\nimport { IReelsComponentConfigurationDesktopForLandscape } from '../configuration/IReelsComponentConfigurationDesktopForLandscape';\nimport ReelsViewDesktopForLandscape from './ReelsViewDesktopForLandscape';\n\n@injectable()\nexport default class ReelsViewDesktopDesktopForLandscape extends ReelsViewDesktopForLandscape {\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('ReelsOverlay') public overlay: Container,\n        @inject('ReelsComponentConfiguration')\n        protected componentConfiguration: IReelsComponentConfigurationDesktopForLandscape,\n    ) {\n        super(rootStore, slotConfiguration, overlay, componentConfiguration);\n    }\n\n    public setOrientation(value): void {\n        super.setOrientation(value);\n        const slicesScaleFactor = this.slotConfiguration.desktopScale;\n        if (slicesScaleFactor) {\n            this.topPart.scale.set(slicesScaleFactor);\n            this.bottomPart.scale.set(slicesScaleFactor);\n        }\n    }\n}\n","import Core, { IOrientation } from '@egt/core';\nimport { ISlotConfiguration, RootStore } from '@egt/slot';\nimport { IBackgroundAssets, ViewContainer } from '@egt/ui-lib';\nimport { Container, Sprite } from 'pixi.js';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { IReelsComponentConfigurationDesktopForLandscape } from '../configuration/IReelsComponentConfigurationDesktopForLandscape';\nimport ReelDesktopForLandscape from './ReelDesktopForLandscape';\n\n@injectable()\nexport default class ReelsViewDesktopForLandscape extends ViewContainer {\n    get reels(): ReelDesktopForLandscape[] {\n        return this._reels;\n    }\n    public overlayTextures = {};\n    protected _reels: ReelDesktopForLandscape[] = [];\n    protected currentFakeReels: number[][] = [];\n\n    protected topPart: Sprite;\n    protected bottomPart: Sprite;\n    protected reelsContainer: Sprite;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('ReelsOverlay') public overlay: Container,\n        @inject('ReelsComponentConfiguration')\n        protected componentConfiguration: IReelsComponentConfigurationDesktopForLandscape,\n    ) {\n        super();\n    }\n\n    public init(): void {\n        this.reelsContainer = new Sprite();\n        this.addChild(this.reelsContainer);\n\n        this.generateOverlayTextures();\n        this.topPart = new Sprite();\n        this.bottomPart = new Sprite();\n\n        this.overlay.addChild(this.topPart);\n        this.overlay.addChild(this.bottomPart);\n\n        this.initialRender();\n        if (this.componentConfiguration.useReelStopEffectAnim) {\n            this.createReelStopAnimation();\n        }\n\n        this.rootStore.uiStore.FAKE_REELS.pipe(takeUntil(this.DESTROY)).subscribe(this.onFakeReelsChanged.bind(this));\n        this.rootStore.subjects.CHANGE_BACKGROUND.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onBackgroundChanged.bind(this),\n        );\n\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n    }\n\n    public onBackgroundChanged(param: IBackgroundAssets): void {\n        this.overlayTextures = param;\n        this.setOrientation(Core.ORIENTATION.value);\n    }\n\n    public initialRender(): void {\n        for (let i = 0; i < this.rootStore.subjects.NUMBER_OF_REELS.value; i++) {\n            // TODO: Think a way to refactor this using the dependecy injection\n            // Problem for now is using i as index of each reelView\n            this._reels[i] = new ReelDesktopForLandscape(\n                this.slotConfiguration,\n                this.rootStore,\n                this.overlay,\n                i,\n                true,\n                this.componentConfiguration,\n            );\n            this._reels[i].sprites.forEach((sprite) => {\n                this.reelsContainer.addChild(sprite);\n            });\n\n            this._reels[i].topSprites.forEach((topSprite) => {\n                this.reelsContainer.addChild(topSprite);\n            });\n        }\n        this.reelsContainer.addChild(this.overlay);\n    }\n\n    public destroy(): void {\n        this._reels.forEach((reel) => {\n            reel.sprites.forEach((sprite) => {\n                this.reelsContainer.removeChild(sprite);\n            });\n            reel.topSprites.forEach((sprite) => {\n                this.reelsContainer.removeChild(sprite);\n            });\n            reel.destroy();\n        });\n        this._reels.length = 0;\n        // @ts-ignore\n        this._reels = null;\n\n        if (this.topPart) {\n            this.topPart.destroy();\n            // @ts-ignore\n            this.topPart = null;\n        }\n\n        if (this.bottomPart) {\n            this.bottomPart.destroy();\n            // @ts-ignore\n            this.bottomPart = null;\n        }\n        if (this.overlay) {\n            this.overlay.destroy();\n            // @ts-ignore\n            this.overlay = null;\n        }\n\n        Object.keys(this.overlayTextures).forEach((element) => {\n            Object.keys(this.overlayTextures[element]).forEach((texture) => {\n                if (this.overlayTextures[element][texture] && this.overlayTextures[element] !== 'backgroundAnimation') {\n                    this.overlayTextures[element][texture].destroy();\n                    this.overlayTextures[element][texture] = null;\n                }\n            });\n        });\n        // @ts-ignore\n        this.overlayTextures = null;\n        super.destroy.apply(this, arguments);\n    }\n\n    public onReelsChanged(realReels: number[][]): void {\n        const length = this._reels.length;\n        for (let i = 0; i < length; i++) {\n            this._reels[i].setResult(realReels[i], this.rootStore.uiStore.drawNow);\n        }\n        if (this.rootStore.uiStore.drawNow) {\n            this.rootStore.uiStore.drawNow = false;\n        }\n    }\n\n    public setOrientation(value: IOrientation): void {\n        // Lay out from the position that is currently active rather than forcing the static\n        // reelsPosition. This lets features that drive REELS_POSITION (e.g. bl-jackpot\n        // reels-boost 5x4) keep their layout across orientation changes. No-op for games\n        // that never change it (REELS_POSITION starts as reelsPosition).\n        this.rootStore.subjects.REELS_POSITION.next(this.rootStore.subjects.REELS_POSITION.value);\n        this._reels.forEach((reel) => {\n            reel.refreshLayout();\n        });\n\n        this.topPart.texture = this.overlayTextures[value.orientation.toLowerCase()].topPart;\n        this.bottomPart.texture = this.overlayTextures[value.orientation.toLowerCase()].bottomPart;\n        this.bottomPart.width = this.overlayTextures[value.orientation.toLowerCase()].bottomPart.width;\n        this.topPart.width = this.overlayTextures[value.orientation.toLowerCase()].topPart.width;\n        this.topPart.height = this.overlayTextures[value.orientation.toLowerCase()].topPart.height;\n        this.bottomPart.height = this.overlayTextures[value.orientation.toLowerCase()].bottomPart.height;\n\n        if (value.isLandscape) {\n            this.bottomPart.y =\n                this.rootStore.subjects.REELS_POSITION.value.reelY +\n                this.rootStore.subjects.REELS_POSITION.value.reelHeight;\n            this.topPart.x = 0;\n            this.topPart.y = 0;\n            this.reelsContainer.scale.set(1, 1);\n            this.overlay.scale.set(1, 1);\n        } else {\n            this.bottomPart.y = Core.display.stage.height - this.bottomPart.texture.height;\n            this.topPart.x = 0;\n            this.topPart.y = 0;\n            this.reelsContainer.scale.set(\n                this.componentConfiguration.portraitScale,\n                this.componentConfiguration.portraitScale,\n            );\n            this.overlay.scale.set(\n                this.rootStore.subjects.REELS_POSITION.value.scale,\n                this.rootStore.subjects.REELS_POSITION.value.scale,\n            );\n        }\n        this.changeReelsPosition(\n            this.rootStore.subjects.REELS_POSITION.value.reelX * this.rootStore.subjects.REELS_POSITION.value.scale,\n            this.rootStore.subjects.REELS_POSITION.value.reelY * this.rootStore.subjects.REELS_POSITION.value.scale,\n        );\n        if (this.componentConfiguration.useReelStopEffectAnim) {\n            this.changeReelStopEffectAnimPosition();\n        }\n        const slicesScaleFactor = this.slotConfiguration.desktopScale;\n        if (slicesScaleFactor && Core.isDesktopMode) {\n            this.topPart.scale.set(slicesScaleFactor);\n            this.bottomPart.scale.set(slicesScaleFactor);\n        }\n    }\n\n    public onFakeReelsChanged(fakeReels: number[][]): void {\n        if (fakeReels && fakeReels.length > 0) {\n            const length = this._reels.length;\n            for (let i = 0; i < length; i++) {\n                this._reels[i].setFakeReel(fakeReels[i]);\n            }\n            this.currentFakeReels = fakeReels;\n        }\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public showReelStopEffect(reelIndex: number): void {\n        // override\n    }\n\n    protected changeReelStopEffectAnimPosition(): void {\n        // override\n    }\n\n    protected createReelStopAnimation(): void {\n        // override\n    }\n\n    protected changeReelsPosition(x: number, y: number): void {\n        this._reels.forEach((reel, index) => {\n            reel._x =\n                x +\n                this.rootStore.subjects.REELS_POSITION.value.reelWidth / 2 +\n                index *\n                    (this.rootStore.subjects.REELS_POSITION.value.reelWidth +\n                        this.rootStore.subjects.REELS_POSITION.value.reelSpacing);\n            reel._y = y + this.rootStore.subjects.REELS_POSITION.value.symbolHeight / 2;\n            reel.redraw();\n        });\n    }\n\n    protected generateOverlayTextures(): void {\n        this.overlayTextures = {\n            landscape: {\n                background: Core.assets.getTextureFromSpriteSheet('mainResources', 'backgroundLandscape.png'),\n                topPart: Core.assets.getTextureFromSpriteSheet('mainResources', 'backgroundSlice1Landscape.png'),\n                bottomPart: Core.assets.getTextureFromSpriteSheet('mainResources', 'backgroundSlice2Landscape.png'),\n            },\n            portrait: {\n                background: Core.assets.getTextureFromSpriteSheet('mainResources', 'backgroundPortrait.png'),\n                topPart: Core.assets.getTextureFromSpriteSheet('mainResources', 'backgroundSlice1Portrait.png'),\n                bottomPart: Core.assets.getTextureFromSpriteSheet('mainResources', 'backgroundSlice2Portrait.png'),\n            },\n        };\n    }\n}\n","import Core, { AssetPriority, BaseComponent, IBaseComponentView, IModeConfig } from '@egt/core';\nimport { ISlotConfiguration, SlotComponents, ZOrders } from '@egt/slot';\nimport { Lifecycle } from 'tsyringe';\nimport UIMainPanelComponentConfigurationDefault, {\n    UIMainPanelComponentConfigurationFactoryDefault,\n} from './modes/default/configuration/UIMainPanelComponentConfigurationDefault';\nimport UIMainPanelControllerDefault from './modes/default/controllers/UIMainPanelControllerDefault';\nimport { UIMainPanelComponentConfigurationFactoryBlurred } from './modes/blurred/configuration/UIMainPanelComponentConfigurationBlurred';\nimport UIMainPanelModesConfigurations, { UIMainPanelModes } from './UIMainPanelFactory';\nimport { UIMainPanelComponentConfigurationFactorySided } from './modes/sided/configuration/UIMainPanelComponentConfigurationSided';\n\nexport default class UIMainPanelComponent extends BaseComponent {\n    public static configurationName = 'UIMainPanelComponent';\n    public uiMainView: IBaseComponentView;\n    public controller: UIMainPanelControllerDefault;\n    public componentType = SlotComponents.UI_MAIN_PANEL;\n    public configuration;\n    public rootView;\n\n    constructor(modeConfig: IModeConfig) {\n        super();\n        const baseConfigs = {\n            [UIMainPanelModes.DEFAULT]: UIMainPanelComponentConfigurationFactoryDefault,\n            [UIMainPanelModes.BLURRED]: UIMainPanelComponentConfigurationFactoryBlurred,\n            [UIMainPanelModes.SIDED]: UIMainPanelComponentConfigurationFactorySided,\n        };\n        this.modeFactory = this.initMode<UIMainPanelModesConfigurations>(modeConfig, {\n            defaultModeType: UIMainPanelModes.DEFAULT,\n            baseConfigs,\n            defaultFactory: UIMainPanelModesConfigurations,\n        });\n    }\n\n    public destroy(): void {\n        this.controller.destroy();\n        // @ts-ignore\n        this.controller = null;\n\n        // @ts-ignore\n        this.uiMainView = null;\n\n        // @ts-ignore\n        this.configuration = null;\n        // @ts-ignore\n        this.rootView = null;\n\n        // @ts-ignore\n        this.config = null;\n\n        super.destroy();\n    }\n\n    public onAfterGameConfigurationCreated(): void {\n        super.onAfterGameConfigurationCreated();\n        const slotConfig: ISlotConfiguration = this.dependencyContainer.resolve('ISlotConfiguration');\n        const config: UIMainPanelComponentConfigurationDefault = this.dependencyContainer.resolve(\n            'UIMainPanelComponentConfiguration',\n        );\n        if (slotConfig.componentsConfiguration.hasOwnProperty(UIMainPanelComponent.configurationName)) {\n            Object.keys(slotConfig.componentsConfiguration[UIMainPanelComponent.configurationName]).forEach((key) => {\n                config[key] = slotConfig.componentsConfiguration[UIMainPanelComponent.configurationName][key];\n            });\n        }\n    }\n\n    public onRegisterDependencies(container: any): void {\n        super.onRegisterDependencies(container);\n        // this.dependencyContainer.register('UIMainView', { useClass: UIMainView }, { lifecycle: Lifecycle.Singleton });\n\n        this.dependencyContainer.register('UIMainPanelComponentConfiguration', this.mode.configuration);\n\n        if (!this.dependencyContainer.isRegistered('UIMainView')) {\n            this.dependencyContainer.register(\n                'UIMainView',\n                { useClass: this.mode.view },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n    }\n\n    public onResolveDependencies(container: any): void {\n        super.onResolveDependencies(container);\n        this.rootView = this.dependencyContainer.resolve('RootView');\n        this.uiMainView = this.dependencyContainer.resolve('UIMainView');\n\n        this.controller = this.dependencyContainer.resolve('UIMainPanelController');\n        this.uiMainView.zIndex = ZOrders.UI_LEVEL;\n        this.rootView.addChild(this.uiMainView);\n    }\n\n    public onRegisterMobileDependencies(): void {\n        if (!this.dependencyContainer.isRegistered('UIMainPanelController')) {\n            this.dependencyContainer.register(\n                'UIMainPanelController',\n                { useClass: this.mode.controller },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n    }\n    public onRegisterDesktopDependencies(): void {\n        if (!this.dependencyContainer.isRegistered('UIMainPanelController')) {\n            this.dependencyContainer.register(\n                'UIMainPanelController',\n                { useClass: this.mode.desktopController },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n    }\n    public onPrepareResources(): void {\n        Core.assets.addAssets([\n            {\n                id: 'jackpotsCountersBitmapFont',\n                url: '../assets/commons/images/fonts/jackpotsCountersBitmapFont.fnt',\n                priority: AssetPriority.HIGHEST,\n                type: 'texture',\n            },\n        ]);\n        this.configuration = this.dependencyContainer.resolve('UIMainPanelComponentConfiguration');\n        Core.assets.addAssets(this.configuration?.assets?.toArray() || []);\n    }\n}\n","import { BaseModesConfigurations, IForceSetConfig, IModes } from '@egt/core';\nimport { UIMainPanelComponentConfigurationFactoryDefault } from './modes/default/configuration/UIMainPanelComponentConfigurationDefault';\nimport UIMainPanelControllerDefault from './modes/default/controllers/UIMainPanelControllerDefault';\nimport UIMainPanelViewDefault from './modes/default/views/UIMainPanelViewDefault';\nimport { UIMainPanelComponentConfigurationFactoryBlurred } from './modes/blurred/configuration/UIMainPanelComponentConfigurationBlurred';\nimport UIMainPanelControllerDesktopDefault from './modes/default/controllers/UIMainPanelControllerDesktopDefault';\nimport { UIMainPanelComponentConfigurationFactorySided } from './modes/sided/configuration/UIMainPanelComponentConfigurationSided';\nimport UIMainPanelViewBlurred from './modes/blurred/views/UIMainPanelViewBlurred';\n\nexport default class UIMainPanelModesConfigurations extends BaseModesConfigurations<UIMainPanelModes> {\n    constructor(modeType: UIMainPanelModes, forceSetConfig?: IForceSetConfig) {\n        super(modeType, forceSetConfig);\n    }\n\n    protected createBaseModesConfig(modeType: UIMainPanelModes): IModes {\n        switch (modeType) {\n            case UIMainPanelModes.BLURRED:\n                return {\n                    controller: UIMainPanelControllerDefault,\n                    desktopController: UIMainPanelControllerDesktopDefault,\n                    view: UIMainPanelViewBlurred,\n                    configuration: UIMainPanelComponentConfigurationFactoryBlurred(),\n                };\n            case UIMainPanelModes.SIDED:\n                return {\n                    controller: UIMainPanelControllerDefault,\n                    desktopController: UIMainPanelControllerDesktopDefault,\n                    view: UIMainPanelViewDefault,\n                    configuration: UIMainPanelComponentConfigurationFactorySided(),\n                };\n            default:\n                return {\n                    controller: UIMainPanelControllerDefault,\n                    desktopController: UIMainPanelControllerDesktopDefault,\n                    view: UIMainPanelViewDefault,\n                    configuration: UIMainPanelComponentConfigurationFactoryDefault(),\n                };\n        }\n    }\n}\n\nexport enum UIMainPanelModes {\n    DEFAULT = 'default',\n    BLURRED = 'blurred',\n    SIDED = 'sided',\n}\n","import IUIMainPanelView from './IUIMainPanelView';\nimport UIMainPanelComponentConfigurationDefault from './modes/default/configuration/UIMainPanelComponentConfigurationDefault';\nimport UIMainPanelControllerDefault from './modes/default/controllers/UIMainPanelControllerDefault';\nimport UIMainPanelControllerDesktopDefault from './modes/default/controllers/UIMainPanelControllerDesktopDefault';\nimport {\n    IButtonPropsDefault,\n    IMoneyFieldDefault,\n    IUIMainPanelComponentConfigurationDefault,\n} from './modes/default/interfaces/IUIMainPanelComponentConfigurationDefault';\nimport UIMainPanelViewDefault from './modes/default/views/UIMainPanelViewDefault';\nimport UIMainPanelViewBlurred from './modes/blurred/views/UIMainPanelViewBlurred';\nimport UIMainPanelComponentConfigurationBlurred from './modes/blurred/configuration/UIMainPanelComponentConfigurationBlurred';\nimport {\n    IMoneyFieldBlurred,\n    IButtonPropsBlurred,\n    IBalanceFadeConfig,\n} from './modes/blurred/interfaces/IUIMainPanelComponentConfigurationBlurred';\nimport UIMainPanelComponent from './UIMainPanelComponent';\nimport { UIMainPanelModes } from './UIMainPanelFactory';\nimport UIMainPanelComponentConfigurationSided from './modes/sided/configuration/UIMainPanelComponentConfigurationSided';\nimport { IMoneyFieldSided, IButtonPropsSided } from './modes/sided/interfaces/IUIMainPanelComponentConfigurationSided';\n\nexport {\n    UIMainPanelViewDefault,\n    UIMainPanelViewBlurred,\n    UIMainPanelComponentConfigurationDefault,\n    UIMainPanelComponentConfigurationBlurred,\n    IMoneyFieldDefault,\n    IButtonPropsDefault,\n    IUIMainPanelComponentConfigurationDefault,\n    UIMainPanelControllerDefault,\n    UIMainPanelControllerDesktopDefault,\n    IUIMainPanelView,\n    UIMainPanelModes,\n    IMoneyFieldBlurred,\n    IButtonPropsBlurred,\n    UIMainPanelComponentConfigurationSided,\n    IMoneyFieldSided,\n    IButtonPropsSided,\n    IBalanceFadeConfig,\n};\nexport default UIMainPanelComponent;\n","import {\n    AddPriority,\n    AssetPriority,\n    AssetsCollection,\n    BaseComponentConfiguration,\n    DefaultAssets,\n    DefaultValue,\n    DynamicPositionObject,\n} from '@egt/core';\nimport { FooterBackgroundModes } from '@egt/footer-background';\nimport { SlotComponents } from '@egt/slot';\nimport { TextStyle } from 'pixi.js';\nimport {\n    IBalanceFadeConfig,\n    IButtonPropsBlurred,\n    IMoneyFieldBlurred,\n    IUIMainPanelComponentConfigurationBlurred,\n} from '../interfaces/IUIMainPanelComponentConfigurationBlurred';\n\nexport default class UIMainPanelComponentConfigurationBlurred extends BaseComponentConfiguration {}\nexport function UIMainPanelComponentConfigurationFactoryBlurred(): any {\n    class UIMainPanelComponentConfigurationBlurredInternalClass\n        extends UIMainPanelComponentConfigurationBlurred\n        implements IUIMainPanelComponentConfigurationBlurred\n    {\n        public mainPanelHeight: number = 214;\n        public mainPanelWidth: number = 1360;\n        public winAndBalanceFieldsWidthBuffer = 10;\n\n        @DefaultValue<IBalanceFadeConfig>({\n            defaults: {\n                create: false,\n                visible: true,\n                x: 0,\n                y: 0,\n            },\n        })\n        public balanceFadeConfig: DynamicPositionObject<IBalanceFadeConfig> & IBalanceFadeConfig;\n\n        @DefaultAssets([\n            {\n                id: 'svgFullscreenExit',\n                url: '../assets/components/slot/ui-main-panel/blurred/ui-svg/exitFullscreen.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    desktop: { width: 60, height: 60 },\n                },\n            },\n            {\n                id: 'svgFullscreen',\n                url: '../assets/components/slot/ui-main-panel/blurred/ui-svg/fullscreen.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    desktop: { width: 60, height: 60 },\n                },\n            },\n            {\n                id: 'svgHelp',\n                url: '../assets/components/slot/ui-main-panel/blurred/ui-svg/help.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 60, height: 60 },\n                },\n            },\n            {\n                id: 'svgInfo',\n                url: '../assets/components/slot/ui-main-panel/blurred/ui-svg/info.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 60, height: 60 },\n                },\n            },\n            {\n                id: 'svgSettings',\n                url: '../assets/components/slot/ui-main-panel/blurred/ui-svg/settings.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 60, height: 60 },\n                },\n            },\n            {\n                id: 'svgSettingsClose',\n                url: '../assets/components/slot/ui-main-panel/blurred/ui-svg/settingsClose.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 60, height: 60 },\n                },\n            },\n            {\n                id: 'svgSound',\n                url: '../assets/components/slot/ui-main-panel/blurred/ui-svg/speak.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 60, height: 60 },\n                },\n            },\n            {\n                id: 'svgSoundOff',\n                url: '../assets/components/slot/ui-main-panel/blurred/ui-svg/speakOff.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 60, height: 60 },\n                },\n            },\n        ])\n        public assets: AssetsCollection;\n\n        @AddPriority<IButtonPropsBlurred>([\n            {\n                priorityType: { feature: SlotComponents.BACKGROUND_SOUND },\n                priority: 2,\n                value: {\n                    desktop: { x: 975, y: 747 },\n                },\n            },\n            {\n                priorityType: { feature: SlotComponents.FOOTER_BACKGROUND, mode: FooterBackgroundModes.BLURRED },\n                priority: 4,\n                value: {\n                    landscape: { x: 130, y: 732 },\n                    portrait: { x: 130, y: 1304 },\n                    desktop: { x: 130, y: 732 },\n                },\n            },\n        ])\n        @DefaultValue<IButtonPropsBlurred>({\n            defaults: { x: 74, y: 617, scale: 1, visible: true, textures: ['svgInfo'] },\n            portrait: { x: 114, y: 1273 },\n            desktop: { x: 1043, y: 747 },\n        })\n        public paytableButtonPosition: DynamicPositionObject<IButtonPropsBlurred> & IButtonPropsBlurred;\n\n        @AddPriority<IButtonPropsBlurred>([\n            {\n                priorityType: { feature: SlotComponents.FOOTER_BACKGROUND, mode: FooterBackgroundModes.BLURRED },\n                priority: 3,\n                value: {\n                    landscape: { x: 0, y: 0, visible: false },\n                    portrait: { x: 0, y: 0, visible: false },\n                    desktop: { x: 1252, y: 732, visible: true },\n                },\n            },\n        ])\n        @DefaultValue<IButtonPropsBlurred>({\n            defaults: { x: 0, y: 0, scale: 1, visible: false, textures: ['svgFullscreenExit', 'svgFullscreen'] },\n            desktop: { x: 1240, y: 747, visible: true },\n        })\n        public fullScreenButton: DynamicPositionObject<IButtonPropsBlurred> & IButtonPropsBlurred;\n\n        @AddPriority<IButtonPropsBlurred>([\n            {\n                priorityType: { feature: SlotComponents.BACKGROUND_SOUND },\n                priority: 2,\n                value: {\n                    landscape: { x: 1322 },\n                },\n            },\n            {\n                priorityType: { feature: SlotComponents.FOOTER_BACKGROUND, mode: FooterBackgroundModes.BLURRED },\n                priority: 4,\n                value: {\n                    landscape: { x: 1230, y: 732, visible: true },\n                    portrait: { x: 635, y: 1304, visible: true },\n                    desktop: { x: 1180, y: 732, visible: true },\n                },\n            },\n        ])\n        @DefaultValue<IButtonPropsBlurred>({\n            defaults: { x: 1287, y: 617, scale: 1, visible: true, textures: ['svgSoundOff', 'svgSound'] },\n            portrait: { x: 636, y: 1272 },\n            desktop: { x: 1172, y: 747 },\n        })\n        public soundButton: DynamicPositionObject<IButtonPropsBlurred> & IButtonPropsBlurred;\n\n        @AddPriority<IButtonPropsBlurred>([\n            {\n                priorityType: { feature: SlotComponents.BACKGROUND_SOUND },\n                priority: 2,\n                value: {\n                    desktop: { x: 1040 },\n                },\n            },\n            {\n                priorityType: { feature: SlotComponents.FOOTER_BACKGROUND, mode: FooterBackgroundModes.BLURRED },\n                priority: 4,\n                value: {\n                    landscape: { x: 224, y: 732, visible: true },\n                    portrait: { x: 224, y: 1304, visible: true },\n                    desktop: { x: 224, y: 732, visible: true },\n                },\n            },\n        ])\n        @DefaultValue<IButtonPropsBlurred>({\n            defaults: { x: 0, y: 0, visible: false, scale: 1, textures: ['svgHelp'] },\n            desktop: { x: 1108, y: 747, visible: true },\n        })\n        public helpButton: DynamicPositionObject<IButtonPropsBlurred> & IButtonPropsBlurred;\n\n        @AddPriority<IButtonPropsBlurred>([\n            {\n                priorityType: { feature: SlotComponents.FOOTER_BACKGROUND, mode: FooterBackgroundModes.BLURRED },\n                priority: 3,\n                value: {\n                    landscape: { x: 1324, y: 732 },\n                    portrait: { x: 729, y: 1304 },\n                    desktop: { x: 1324, y: 732 },\n                },\n            },\n        ])\n        @DefaultValue<IButtonPropsBlurred>({\n            defaults: { x: 1286, y: 699, visible: true, scale: 1, textures: ['svgSettingsClose', 'svgSettings'] },\n            portrait: { x: 719, y: 1272 },\n            desktop: { x: 1308, y: 747, textures: ['svgSettings', 'svgSettings'] },\n        })\n        public settingsButtonProps: DynamicPositionObject<IButtonPropsBlurred> & IButtonPropsBlurred;\n\n        @DefaultValue<IMoneyFieldBlurred>({\n            defaults: {\n                x: 152,\n                y: 673,\n                width: 171,\n                height: 80,\n                currencyWidth: 171,\n                currencyHeight: 15,\n                currencyLineOffset: 0,\n                currencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fontSize: 22,\n                    fill: '#C6C5C5',\n                }),\n                moneyWidth: 171,\n                moneyHeight: 16,\n                moneyLineOffset: 0,\n                moneyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    fontSize: 30,\n                    fill: '#FFD200',\n                }),\n                moneyTint: 0xffd200,\n\n                creditsWidth: 171,\n                creditsHeight: 28,\n                creditsLineOffset: 11,\n                creditsStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fontSize: 48,\n                    fill: '#FFFFFF',\n                }),\n\n                labelWidth: 171,\n                labelHeight: 20,\n                labelStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fontSize: 30,\n                    padding: 5,\n                    fill: '#FFD200',\n                }),\n                labelLineOffset: 37,\n            },\n            portrait: {\n                x: 10,\n                y: 721,\n                width: 201,\n                height: 90,\n                currencyLineOffset: 0,\n                currencyWidth: 201,\n                currencyHeight: 15,\n                currencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fontSize: 22,\n                    fill: '#C6C5C5',\n                }),\n                moneyWidth: 201,\n                moneyHeight: 19,\n                creditsWidth: 201,\n                creditsHeight: 34,\n                creditsLineOffset: 9,\n                labelWidth: 201,\n                labelHeight: 22,\n                labelLineOffset: 41,\n                labelStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fontSize: 33,\n                    padding: 5,\n                    fill: '#FFD200',\n                }),\n            },\n            landscape: {\n                width: 171,\n                currencyWidth: 171,\n                creditsWidth: 171,\n                creditsHeight: 30,\n                moneyWidth: 171,\n                labelWidth: 171,\n            },\n            desktop: {\n                width: 171,\n                currencyWidth: 171,\n                creditsWidth: 171,\n                creditsHeight: 30,\n                moneyWidth: 171,\n                labelWidth: 171,\n            },\n        })\n        public balanceContainerProperties: DynamicPositionObject<IMoneyFieldBlurred> & IMoneyFieldBlurred;\n\n        @DefaultValue<IMoneyFieldBlurred>({\n            defaults: {\n                x: 1036,\n                y: 673,\n                width: 171,\n                height: 80,\n                currencyWidth: 171,\n                currencyHeight: 15,\n                currencyLineOffset: 0,\n                currencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fontSize: 22,\n                    fill: '#C6C5C5',\n                }),\n                moneyWidth: 171,\n                moneyHeight: 16,\n                moneyLineOffset: 0,\n                moneyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    fontSize: 30,\n                    fill: '#FFD200',\n                }),\n                moneyTint: 0xffd200,\n\n                creditsWidth: 171,\n                creditsHeight: 28,\n                creditsLineOffset: 11,\n                creditsStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fontSize: 48,\n                    fill: '#FFFFFF',\n                }),\n\n                labelWidth: 171,\n                labelHeight: 20,\n                labelStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fontSize: 30,\n                    padding: 5,\n                    fill: '#FFD200',\n                }),\n                labelLineOffset: 37,\n            },\n            portrait: {\n                x: 554,\n                y: 721,\n                width: 201,\n                height: 90,\n                currencyLineOffset: 0,\n                currencyWidth: 201,\n                currencyHeight: 15,\n                currencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fontSize: 22,\n                    fill: '#C6C5C5',\n                }),\n                moneyWidth: 201,\n                moneyHeight: 19,\n                creditsWidth: 201,\n                creditsHeight: 34,\n                creditsLineOffset: 9,\n                labelWidth: 201,\n                labelHeight: 22,\n                labelLineOffset: 41,\n                labelStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fontSize: 33,\n                    padding: 5,\n                    fill: '#FFD200',\n                }),\n            },\n            landscape: {\n                width: 171,\n                currencyWidth: 171,\n                creditsWidth: 171,\n                creditsHeight: 30,\n                moneyWidth: 171,\n                labelWidth: 171,\n            },\n            desktop: {\n                width: 171,\n                currencyWidth: 171,\n                creditsWidth: 171,\n                creditsHeight: 30,\n                moneyWidth: 171,\n                labelWidth: 171,\n            },\n        })\n        public winContainerProperties: DynamicPositionObject<IMoneyFieldBlurred> & IMoneyFieldBlurred;\n    }\n    return UIMainPanelComponentConfigurationBlurredInternalClass;\n}\n","import Core from '@egt/core';\nimport { FeatureController, ISlotConfiguration, InitialSettings, RootStore, SpinAnalyzer } from '@egt/slot';\nimport { Sprite } from 'pixi.js';\nimport { inject, injectable } from 'tsyringe';\nimport UIMainPanelViewDefault from '../../default/views/UIMainPanelViewDefault';\nimport { IUIMainPanelComponentConfigurationBlurred } from '../interfaces/IUIMainPanelComponentConfigurationBlurred';\n\n@injectable()\nexport default class UIMainPanelViewBlurred extends UIMainPanelViewDefault {\n    protected balanceFade: Sprite;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected configuration: ISlotConfiguration,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('FeatureController') protected feature: FeatureController,\n        @inject('UIMainPanelComponentConfiguration')\n        protected componentConfiguration: IUIMainPanelComponentConfigurationBlurred,\n        @inject('SpinAnalyzer') protected spinAnalyzer: SpinAnalyzer,\n    ) {\n        super(rootStore, configuration, settings, feature, componentConfiguration, spinAnalyzer);\n\n        if (this.componentConfiguration.balanceFadeConfig.create) {\n            this.createBalanceFade();\n        }\n    }\n\n    private createBalanceFade(): void {\n        this.balanceFade = new Sprite(Core.assets.getTextureFromSpriteSheet('mainResources', 'balanceOverlay.png'));\n        this.balanceFade.x = this.componentConfiguration.balanceFadeConfig.x;\n        this.balanceFade.y = this.componentConfiguration.balanceFadeConfig.y;\n        this.balanceFade.visible = this.componentConfiguration.balanceFadeConfig.visible;\n        this.addChildAt(this.balanceFade, 0);\n    }\n\n    protected applyMainPanelPositions(): void {\n        super.applyMainPanelPositions();\n\n        if (this.balanceFade) {\n            this.balanceFade.x = this.componentConfiguration.balanceFadeConfig.x;\n            this.balanceFade.y = this.componentConfiguration.balanceFadeConfig.y;\n            this.balanceFade.visible = this.componentConfiguration.balanceFadeConfig.visible;\n        }\n    }\n}\n","import {\n    AddPriority,\n    AssetPriority,\n    AssetsCollection,\n    BaseComponentConfiguration,\n    DefaultAssets,\n    DefaultValue,\n    DynamicPositionObject,\n} from '@egt/core';\nimport { FooterBackgroundModes } from '@egt/footer-background';\nimport { SlotComponents } from '@egt/slot';\nimport { TextStyle } from 'pixi.js';\nimport {\n    IButtonPropsDefault,\n    IMoneyFieldDefault,\n    IUIMainPanelComponentConfigurationDefault,\n} from '../interfaces/IUIMainPanelComponentConfigurationDefault';\n\nexport default class UIMainPanelComponentConfigurationDefault extends BaseComponentConfiguration {}\nexport function UIMainPanelComponentConfigurationFactoryDefault(): any {\n    class UIMainPanelComponentConfigurationDefaultInternalClass\n        extends UIMainPanelComponentConfigurationDefault\n        implements IUIMainPanelComponentConfigurationDefault\n    {\n        public mainPanelHeight: number = 214;\n        public mainPanelWidth: number = 1360;\n        public winAndBalanceFieldsWidthBuffer = 10;\n\n        @DefaultAssets([\n            {\n                id: 'svgFullscreenExit',\n                url: '../assets/components/slot/ui-main-panel/default/ui-svg/exitFullscreen.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    desktop: { width: 32, height: 32 },\n                },\n            },\n            {\n                id: 'svgFullscreen',\n                url: '../assets/components/slot/ui-main-panel/default/ui-svg/fullscreen.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    desktop: { width: 32, height: 32 },\n                },\n            },\n            {\n                id: 'svgHelp',\n                url: '../assets/components/slot/ui-main-panel/default/ui-svg/help.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                hasDesktopVersion: true,\n                config: {\n                    desktop: { width: 32, height: 32 },\n                },\n            },\n            {\n                id: 'svgInfo',\n                url: '../assets/components/slot/ui-main-panel/default/ui-svg/info.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                hasDesktopVersion: true,\n                config: {\n                    mobile: { width: 76, height: 76 },\n                    desktop: { width: 32, height: 32 },\n                },\n            },\n            {\n                id: 'svgSettings',\n                url: '../assets/components/slot/ui-main-panel/default/ui-svg/settings.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                hasDesktopVersion: true,\n                config: {\n                    mobile: { width: 76, height: 76 },\n                    desktop: { width: 32, height: 32 },\n                },\n            },\n            {\n                id: 'svgSettingsClose',\n                url: '../assets/components/slot/ui-main-panel/default/ui-svg/settingsClose.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                // hasDesktopVersion: true,\n                config: {\n                    mobile: { width: 76, height: 76 },\n                    desktop: { width: 76, height: 76 },\n                },\n            },\n            {\n                id: 'svgSound',\n                url: '../assets/components/slot/ui-main-panel/default/ui-svg/speak.svg',\n                priority: AssetPriority.HIGHEST,\n                hasDesktopVersion: true,\n                type: 'svg',\n                config: {\n                    mobile: { width: 70, height: 70 },\n                    desktop: { width: 32, height: 32 },\n                },\n            },\n            {\n                id: 'svgSoundOff',\n                url: '../assets/components/slot/ui-main-panel/default/ui-svg/speakOff.svg',\n                priority: AssetPriority.HIGHEST,\n                hasDesktopVersion: true,\n                type: 'svg',\n                config: {\n                    mobile: { width: 70, height: 70 },\n                    desktop: { width: 32, height: 32 },\n                },\n            },\n        ])\n        public assets: AssetsCollection;\n\n        @AddPriority<IButtonPropsDefault>([\n            {\n                priorityType: { feature: SlotComponents.BACKGROUND_SOUND },\n                priority: 2,\n                value: {\n                    desktop: { x: 975, y: 747 },\n                },\n            },\n            {\n                priorityType: { feature: SlotComponents.FOOTER_BACKGROUND, mode: FooterBackgroundModes.BLURRED },\n                priority: 4,\n                value: {\n                    landscape: { x: 130, y: 732 },\n                    portrait: { x: 130, y: 1304 },\n                    desktop: { x: 130, y: 732 },\n                },\n            },\n        ])\n        @DefaultValue<IButtonPropsDefault>({\n            defaults: { x: 74, y: 617, scale: 1, visible: true, textures: ['svgInfo'] },\n            portrait: { x: 114, y: 1273 },\n            desktop: { x: 1043, y: 747 },\n        })\n        public paytableButtonPosition: DynamicPositionObject<IButtonPropsDefault> & IButtonPropsDefault;\n\n        @AddPriority<IButtonPropsDefault>([\n            {\n                priorityType: { feature: SlotComponents.FOOTER_BACKGROUND, mode: FooterBackgroundModes.BLURRED },\n                priority: 3,\n                value: {\n                    landscape: { x: 0, y: 0, visible: false },\n                    portrait: { x: 0, y: 0, visible: false },\n                    desktop: { x: 1252, y: 732, visible: true },\n                },\n            },\n        ])\n        @DefaultValue<IButtonPropsDefault>({\n            defaults: { x: 0, y: 0, scale: 1, visible: false, textures: ['svgFullscreenExit', 'svgFullscreen'] },\n            desktop: { x: 1240, y: 747, visible: true },\n        })\n        public fullScreenButton: DynamicPositionObject<IButtonPropsDefault> & IButtonPropsDefault;\n\n        @AddPriority<IButtonPropsDefault>([\n            {\n                priorityType: { feature: SlotComponents.BACKGROUND_SOUND },\n                priority: 2,\n                value: {\n                    landscape: { x: 1322 },\n                },\n            },\n            {\n                priorityType: { feature: SlotComponents.FOOTER_BACKGROUND, mode: FooterBackgroundModes.BLURRED },\n                priority: 4,\n                value: {\n                    landscape: { x: 1230, y: 732, visible: true },\n                    portrait: { x: 635, y: 1304, visible: true },\n                    desktop: { x: 1180, y: 732, visible: true },\n                },\n            },\n        ])\n        @DefaultValue<IButtonPropsDefault>({\n            defaults: { x: 1287, y: 617, scale: 1, visible: true, textures: ['svgSoundOff', 'svgSound'] },\n            portrait: { x: 636, y: 1272 },\n            desktop: { x: 1172, y: 747 },\n        })\n        public soundButton: DynamicPositionObject<IButtonPropsDefault> & IButtonPropsDefault;\n\n        @AddPriority<IButtonPropsDefault>([\n            {\n                priorityType: { feature: SlotComponents.BACKGROUND_SOUND },\n                priority: 2,\n                value: {\n                    desktop: { x: 1040 },\n                },\n            },\n            {\n                priorityType: { feature: SlotComponents.FOOTER_BACKGROUND, mode: FooterBackgroundModes.BLURRED },\n                priority: 4,\n                value: {\n                    landscape: { x: 224, y: 732, visible: true },\n                    portrait: { x: 224, y: 1304, visible: true },\n                    desktop: { x: 224, y: 732, visible: true },\n                },\n            },\n        ])\n        @DefaultValue<IButtonPropsDefault>({\n            defaults: { x: 0, y: 0, visible: false, scale: 1, textures: ['svgHelp'] },\n            desktop: { x: 1108, y: 747, visible: true },\n        })\n        public helpButton: DynamicPositionObject<IButtonPropsDefault> & IButtonPropsDefault;\n\n        @AddPriority<IButtonPropsDefault>([\n            {\n                priorityType: { feature: SlotComponents.FOOTER_BACKGROUND, mode: FooterBackgroundModes.BLURRED },\n                priority: 3,\n                value: {\n                    landscape: { x: 1324, y: 732 },\n                    portrait: { x: 729, y: 1304 },\n                    desktop: { x: 1324, y: 732 },\n                },\n            },\n        ])\n        @DefaultValue<IButtonPropsDefault>({\n            defaults: { x: 1286, y: 699, visible: true, scale: 1, textures: ['svgSettingsClose', 'svgSettings'] },\n            portrait: { x: 719, y: 1272 },\n            desktop: { x: 1308, y: 747, textures: ['svgSettings', 'svgSettings'] },\n        })\n        public settingsButtonProps: DynamicPositionObject<IButtonPropsDefault> & IButtonPropsDefault;\n\n        @DefaultValue<IMoneyFieldDefault>({\n            defaults: {\n                x: 152,\n                y: 673,\n                width: 171,\n                height: 80,\n                currencyWidth: 171,\n                currencyHeight: 15,\n                currencyLineOffset: 0,\n                currencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fontSize: 22,\n                    fill: '#C6C5C5',\n                }),\n                moneyWidth: 171,\n                moneyHeight: 16,\n                moneyLineOffset: 0,\n                moneyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    fontSize: 30,\n                    fill: '#FFD200',\n                }),\n                moneyTint: 0xffd200,\n\n                creditsWidth: 171,\n                creditsHeight: 28,\n                creditsLineOffset: 11,\n                creditsStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fontSize: 48,\n                    fill: '#FFFFFF',\n                }),\n\n                labelWidth: 171,\n                labelHeight: 20,\n                labelStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fontSize: 30,\n                    padding: 5,\n                    fill: '#FFD200',\n                }),\n                labelLineOffset: 37,\n            },\n            portrait: {\n                x: 10,\n                y: 721,\n                width: 201,\n                height: 90,\n                currencyLineOffset: 0,\n                currencyWidth: 201,\n                currencyHeight: 15,\n                currencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fontSize: 22,\n                    fill: '#C6C5C5',\n                }),\n                moneyWidth: 201,\n                moneyHeight: 19,\n                creditsWidth: 201,\n                creditsHeight: 34,\n                creditsLineOffset: 9,\n                labelWidth: 201,\n                labelHeight: 22,\n                labelLineOffset: 41,\n                labelStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fontSize: 33,\n                    padding: 5,\n                    fill: '#FFD200',\n                }),\n            },\n            landscape: {\n                width: 171,\n                currencyWidth: 171,\n                creditsWidth: 171,\n                creditsHeight: 30,\n                moneyWidth: 171,\n                labelWidth: 171,\n            },\n            desktop: {\n                width: 171,\n                currencyWidth: 171,\n                creditsWidth: 171,\n                creditsHeight: 30,\n                moneyWidth: 171,\n                labelWidth: 171,\n            },\n        })\n        public balanceContainerProperties: DynamicPositionObject<IMoneyFieldDefault> & IMoneyFieldDefault;\n\n        @DefaultValue<IMoneyFieldDefault>({\n            defaults: {\n                x: 1036,\n                y: 673,\n                width: 171,\n                height: 80,\n                currencyWidth: 171,\n                currencyHeight: 15,\n                currencyLineOffset: 0,\n                currencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fontSize: 22,\n                    fill: '#C6C5C5',\n                }),\n                moneyWidth: 171,\n                moneyHeight: 16,\n                moneyLineOffset: 0,\n                moneyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    fontSize: 30,\n                    fill: '#FFD200',\n                }),\n                moneyTint: 0xffd200,\n\n                creditsWidth: 171,\n                creditsHeight: 28,\n                creditsLineOffset: 11,\n                creditsStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fontSize: 48,\n                    fill: '#FFFFFF',\n                }),\n\n                labelWidth: 171,\n                labelHeight: 20,\n                labelStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fontSize: 30,\n                    padding: 5,\n                    fill: '#FFD200',\n                }),\n                labelLineOffset: 37,\n            },\n            portrait: {\n                x: 554,\n                y: 721,\n                width: 201,\n                height: 90,\n                currencyLineOffset: 0,\n                currencyWidth: 201,\n                currencyHeight: 15,\n                currencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fontSize: 22,\n                    fill: '#C6C5C5',\n                }),\n                moneyWidth: 201,\n                moneyHeight: 19,\n                creditsWidth: 201,\n                creditsHeight: 34,\n                creditsLineOffset: 9,\n                labelWidth: 201,\n                labelHeight: 22,\n                labelLineOffset: 41,\n                labelStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fontSize: 33,\n                    padding: 5,\n                    fill: '#FFD200',\n                }),\n            },\n            landscape: {\n                width: 171,\n                currencyWidth: 171,\n                creditsWidth: 171,\n                creditsHeight: 30,\n                moneyWidth: 171,\n                labelWidth: 171,\n            },\n            desktop: {\n                width: 171,\n                currencyWidth: 171,\n                creditsWidth: 171,\n                creditsHeight: 30,\n                moneyWidth: 171,\n                labelWidth: 171,\n            },\n        })\n        public winContainerProperties: DynamicPositionObject<IMoneyFieldDefault> & IMoneyFieldDefault;\n    }\n    return UIMainPanelComponentConfigurationDefaultInternalClass;\n}\n","import Core, {\n    AnalyticsDispatcher,\n    BaseController,\n    PostMessageDispatcher,\n    Timers,\n    UserActionType,\n    SessionMetricsCollector,\n} from '@egt/core';\nimport { SettingsTab } from '@egt/settings-popup';\nimport { FeatureController, RootStore, UIState } from '@egt/slot';\nimport { fromEvent } from 'rxjs';\nimport { filter, takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport UIMainPanelViewDefault from '../views/UIMainPanelViewDefault';\n\n@injectable()\nexport default class UIMainPanelControllerDefault extends BaseController {\n    // protected currentUIState: string | undefined = undefined;\n\n    constructor(\n        @inject('UIMainView') protected view: UIMainPanelViewDefault,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('FeatureController') protected featureController: FeatureController,\n    ) {\n        super(view);\n\n        this.attachEventListeners();\n    }\n\n    protected onSettingsToggled(selected: boolean): void {\n        PostMessageDispatcher.toggleMenu(selected);\n        this.rootStore.uiStore.SELECTED_SETTINGS_TAB.next(SettingsTab.GENERAL);\n        if (Core.isDesktopMode) {\n            // this.rootStore.uiStore.SELECTED_SETTINGS_TAB.next(SettingsTab.GENERAL);\n            this.rootStore.subjects.OPEN_SETTINGS_POPUP.next();\n            return;\n        }\n        this.view.enableUI(false);\n        if (selected && this.rootStore.subjects.SHOW_JP_STATS.value.type === -1) {\n            // this.currentUIState = this.rootStore.uiStore.STATE.value;\n            // this.rootStore.uiStore.STATE.next(UIState.DISABLED);\n            this.rootStore.uiStore.COLLECT_CHANGED.next();\n            this.rootStore.subjects.OPEN_SETTINGS_POPUP.next();\n            Core.sounds.play('showDenominationsSound');\n        } else {\n            this.rootStore.subjects.CLOSE_SETTINGS_POPUP.next();\n            // this.rootStore.uiStore.SHOW_SETTINGS.next(false);\n            // this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.next(0);\n            // if (this.settings.autoplayRestrictions.mandatory.length === 0) {\n            this.rootStore.subjects.RESET_AUTOPLAY_RESTRICTIONS.next();\n            // }\n            Core.sounds.play('hideDenominationsSound');\n        }\n    }\n\n    protected onSettingsBtnChildClicked(): void {\n        if (this.rootStore.subjects.KEY_DOWN.value) {\n            this.view.settingsButton.selected = !this.view.settingsButton.selected;\n        }\n    }\n\n    protected onPaytableClicked(): void {\n        if (this.view.paytableButton.enabled && !this.rootStore.subjects.DISABLE_MENU_BUTTONS.value) {\n            // if already open, close it\n            if (\n                this.rootStore.uiStore.SELECTED_SETTINGS_TAB.value === SettingsTab.INFO &&\n                this.rootStore.uiStore.SHOW_SETTINGS.value\n            ) {\n                this.onSettingsToggled(false);\n                return;\n            }\n\n            Core.sounds.play('paytableSound');\n            this.rootStore.uiStore.SELECTED_SETTINGS_TAB.next(SettingsTab.INFO);\n            this.view.find('settingsButton').selected = true;\n            if (!this.rootStore.uiStore.SHOW_SETTINGS.value) {\n                this.rootStore.subjects.OPEN_SETTINGS_POPUP.next();\n            }\n        }\n    }\n\n    protected attachEventListeners(): void {\n        this.view\n            .find('settingsButton')\n            .SWITCH.pipe(\n                filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.onSettingsToggled.bind(this));\n        this.view\n            .find('settingsButton')\n            .children[0].CLICK.pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onSettingsBtnChildClicked.bind(this));\n        this.view\n            .find('settingsButton')\n            .children[1].CLICK.pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onSettingsBtnChildClicked.bind(this));\n        this.view\n            .find('paytableButton')\n            .CLICK.pipe(\n                filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.onPaytableClicked.bind(this));\n\n        this.view.find('soundButton').SWITCH.pipe(takeUntil(this.DESTROY)).subscribe(this.onSoundToggled.bind(this));\n\n        this.view\n            .find('fullscreenButton')\n            ?.SWITCH.pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onFullScreenToggled.bind(this));\n        this.view\n            .find('helpButton')\n            ?.CLICK.pipe(\n                filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.onHelpClicked.bind(this));\n        fromEvent(document, 'fullscreenchange')\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onFullScreenToggledExternal.bind(this));\n        // this handle fullscreen in iframe\n        if (Core.isDesktopMode && (Core.environment.inIframe() || Core.environment.getBrowser().name === 'Safari')) {\n            Core.STAGE_RESIZE_END.pipe(takeUntil(this.DESTROY)).subscribe((_e) => {\n                // this is leave fullscreen mode in iframe\n                const isFullScreen = Math.abs(screen.width - window.innerWidth) < 2;\n                Core.FULL_SCREEN_ACTIVATED.next(isFullScreen);\n                this.view.find('fullscreenButton').selected = isFullScreen;\n                if (!isFullScreen) {\n                    this.rootStore.subjects.RESET_KEY_EVENTS.next();\n                }\n            });\n        }\n\n        this.rootStore.subjects.TOGGLE_BET_SETTINGS_POPUP.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onSettingsToggled.bind(this, true),\n        );\n\n        this.rootStore.subjects.SETTINGS_POPUP_CLOSED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onSettingsPopupClosed.bind(this),\n        );\n\n        this.rootStore.subjects.SETTINGS_POPUP_OPENED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onSettingsPopupOpened.bind(this),\n        );\n\n        this.rootStore.subjects.KEY_UP.pipe(takeUntil(this.DESTROY)).subscribe(this.onKeyReleased.bind(this));\n        this.rootStore.subjects.DISABLE_MENU_BUTTONS.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.view.find('settingsButton').enabled = !this.rootStore.subjects.DISABLE_MENU_BUTTONS.value;\n        });\n        // this.rootStore.subjects.MODAL_PRESSED.pipe(takeUntil(this.DESTROY)).subscribe(\n        //     this.clearBangupTweens.bind(this),\n        // );\n    }\n\n    protected onHelpClicked(): void {\n        if (this.view.helpButton.enabled && !this.rootStore.subjects.DISABLE_MENU_BUTTONS.value) {\n            // if already open, close it\n            if (\n                this.rootStore.uiStore.SELECTED_SETTINGS_TAB.value === SettingsTab.HELP &&\n                this.rootStore.uiStore.SHOW_SETTINGS.value\n            ) {\n                this.onSettingsToggled(false);\n                return;\n            }\n            Core.sounds.play('showDenominationsSound');\n            this.rootStore.uiStore.SELECTED_SETTINGS_TAB.next(SettingsTab.HELP);\n            this.rootStore.subjects.OPEN_SETTINGS_POPUP.next();\n        }\n    }\n\n    protected onFullScreenToggled(): void {\n        // some templates do not use anymore UIMainPanelControllerDesktop and in any reason Core.environment.isFullScreenSupported does not passed\n        // also we need to post message to parent window if needed as in UIMainPanelControllerDesktop\n        if (Core.environment.isFullScreenSupported()) {\n            Core.environment.fullScreenControl().toggle();\n        } else if (Core.isDesktopMode) {\n            const fullScreen = Core.environment.fullScreenControl().isFullscreen;\n            Core.FULL_SCREEN_ACTIVATED.next(fullScreen);\n            if (!fullScreen) {\n                PostMessageDispatcher.openFullScreen();\n            } else {\n                PostMessageDispatcher.closeFullScreen();\n            }\n        }\n    }\n\n    // this handler is used if fullscreen is done due F11 key\n    protected onFullScreenToggledExternal(): void {\n        if (Core.environment.isFullScreenSupported() && Core.isDesktopMode) {\n            this.view.find('fullscreenButton').selected = Core.environment.fullScreenControl().isFullscreen;\n            Core.FULL_SCREEN_ACTIVATED.next(Core.environment.fullScreenControl().isFullscreen);\n        }\n    }\n\n    protected onSoundToggled(selected: boolean): void {\n        Core.sounds.ON_SOUND_MUTED.next(selected);\n        // if(selected && !Core.sounds.ON_BACKGROUND_SOUNDS_MUTED.value){\n        //     Core.sounds.ON_BACKGROUND_SOUNDS_MUTED.next(true);\n        // }\n        PostMessageDispatcher.toggleSound(!selected);\n        SessionMetricsCollector.getInstance().incrementUserAction(UserActionType.SoundToggled);\n        if (!selected) {\n            Timers.setTimeout(() => {\n                Core.sounds.play('unmuteSound'); //! workaround. Solution until the real problem is found\n            }, 100);\n            // await Tone.start();\n        }\n    }\n\n    // protected onBackgroundSoundToggled(selected: boolean): void {\n    //     Core.sounds.ON_BACKGROUND_SOUNDS_MUTED.next(selected);\n    // }\n\n    protected showHideBetButtons(_show: boolean): void {\n        // if (show) {\n        //     this.view.showBetButtons();\n        // } else {\n        //     this.view.hideBetButtons();\n        // }\n    }\n\n    protected onSettingsPopupOpened(): void {\n        AnalyticsDispatcher.incrementUserAction(UserActionType.SettingsOpened);\n        AnalyticsDispatcher.settingsButtonClicked();\n        // if (this.currentUIState) {\n        //     this.rootStore.uiStore.STATE.next(this.currentUIState);\n        //     this.currentUIState = undefined;\n        // }\n        this.view.find('settingsButton').selected = true;\n        this.view.enableUI(true);\n    }\n\n    protected onSettingsPopupClosed(): void {\n        this.view.find('settingsButton').selected = false;\n\n        // this.rootStore.uiStore.SHOW_SETTINGS.next(false);\n        this.view.enableUI(true);\n    }\n\n    protected onKeyReleased(e: KeyboardEvent): void {\n        if (\n            e &&\n            this.rootStore.uiStore.SHOW_SETTINGS.value &&\n            ['KeyC', 'KeyV', 'KeyB', 'KeyN', 'KeyM'].indexOf(e.code) > -1\n        ) {\n            this.rootStore.subjects.CLOSE_SETTINGS_POPUP.next();\n\n            // this.rootStore.uiStore.SHOW_SETTINGS.next(false);\n            this.rootStore.subjects.TAB_OPENED.next(false);\n            return;\n        }\n\n        if (e === null || Core.UI_BLOCKER.value) {\n            return;\n        }\n        const currentUIState = this.rootStore.uiStore.STATE.value;\n\n        if ((e.code !== undefined && e.code === 'KeyC') || (e.keyCode !== undefined && e.keyCode === 67)) {\n            this.reactBasedOnState(currentUIState, 1);\n        }\n        if ((e.code !== undefined && e.code === 'KeyV') || (e.keyCode !== undefined && e.keyCode === 86)) {\n            this.reactBasedOnState(currentUIState, 2);\n        }\n        if ((e.code !== undefined && e.code === 'KeyB') || (e.keyCode !== undefined && e.keyCode === 66)) {\n            this.reactBasedOnState(currentUIState, 3);\n        }\n        if ((e.code !== undefined && e.code === 'KeyN') || (e.keyCode !== undefined && e.keyCode === 78)) {\n            this.reactBasedOnState(currentUIState, 4);\n        }\n        if ((e.code !== undefined && e.code === 'KeyM') || (e.keyCode !== undefined && e.keyCode === 77)) {\n            this.reactBasedOnState(currentUIState, 5);\n        }\n\n        if ((e.code !== undefined && e.code === 'KeyI') || (e.keyCode !== undefined && e.keyCode === 73)) {\n            this.onPaytableClicked();\n        }\n        if ((e.code !== undefined && e.code === 'KeyS') || (e.keyCode !== undefined && e.keyCode === 83)) {\n            if (this.rootStore.subjects.TAB_OPENED.value) {\n                this.rootStore.subjects.CLOSE_SETTINGS_POPUP.next();\n                this.rootStore.subjects.RESET_AUTOPLAY_RESTRICTIONS.next();\n                return;\n            }\n            this.onSoundToggled(!Core.sounds.ON_SOUND_MUTED.value);\n        }\n    }\n\n    private clearBangupTweens(): void {\n        if (this.view.winValueTween || this.view.balanceTween) {\n            // this.view.stopBangupTweens();\n            this.rootStore.uiStore.CLEAR_BANG_UP.next();\n        }\n    }\n\n    protected reactBasedOnState(state: string, _buttonValue: number): void {\n        // if (\n        //     this.view.betButtons[buttonValue - 1].enabled === false ||\n        //     this.view.betButtons[buttonValue - 1].interactive === false\n        // ) {\n        //     return;\n        // }\n        switch (state) {\n            // case UIState.IDLE:\n            // case UIState.WAITING_FOR_COLLECT:\n            //     this.onBetButtonKeyPressed(buttonValue);\n            //     break;\n            // case UIState.BONUS_IDLE:\n            //     if (buttonValue === 1) {\n            //         this.onBetButtonKeyPressed(buttonValue);\n            //     }\n            //     break;\n            case UIState.WAITING_FOR_RESPONSE:\n                if (this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value === 0) {\n                    this.rootStore.subjects.REELS_STOP_ALL.next();\n                }\n                break;\n            /*  case UIState.WAITING_FOR_RESPONSE_IN_GIFTSPINS:\n                if (buttonValue === 1) {\n                    this.rootStore.subjects.REELS_STOP_ALL.next();\n                }\n                    break; */\n        }\n    }\n}\n","import Core, { PostMessageDispatcher } from '@egt/core';\nimport { SettingsTab } from '@egt/settings-popup';\nimport { FeatureController, RootStore } from '@egt/slot';\nimport { inject, injectable } from 'tsyringe';\nimport UIMainPanelControllerDefault from './UIMainPanelControllerDefault';\nimport UIMainPanelViewDefault from '../views/UIMainPanelViewDefault';\n\n@injectable()\nexport default class UIMainPanelControllerDesktopDefault extends UIMainPanelControllerDefault {\n    constructor(\n        @inject('UIMainView') protected view: UIMainPanelViewDefault,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('FeatureController') protected featureController: FeatureController,\n    ) {\n        super(view, rootStore, featureController);\n    }\n\n    protected onSettingsToggled(selected: boolean): void {\n        PostMessageDispatcher.toggleMenu(selected);\n        this.rootStore.uiStore.SELECTED_SETTINGS_TAB.next(SettingsTab.GENERAL);\n        this.rootStore.subjects.OPEN_SETTINGS_POPUP.next();\n    }\n\n    protected onHelpClicked(): void {\n        this.rootStore.uiStore.SELECTED_SETTINGS_TAB.next(SettingsTab.HELP);\n        this.rootStore.subjects.OPEN_SETTINGS_POPUP.next();\n    }\n\n    protected onPaytableClicked(): void {\n        if (this.view.paytableButton.enabled && !this.rootStore.subjects.DISABLE_MENU_BUTTONS.value) {\n            if (this.rootStore.subjects.TAB_OPENED.value) {\n                this.rootStore.subjects.CLOSE_SETTINGS_POPUP.next();\n                this.rootStore.subjects.RESET_AUTOPLAY_RESTRICTIONS.next();\n                Core.sounds.play('hideDenominationsSound');\n                return;\n            }\n            // Core.sounds.play('paytableSound');\n            this.view.paytableButton.enabled = false;\n            this.rootStore.uiStore.SELECTED_SETTINGS_TAB.next(SettingsTab.INFO);\n            this.rootStore.subjects.OPEN_SETTINGS_POPUP.next();\n        }\n    }\n\n    protected onFullScreenToggled(): void {\n        if (Core.environment.isFullScreenSupported()) {\n            Core.environment.fullScreenControl().toggle();\n        }\n        Core.FULL_SCREEN_ACTIVATED.next(!Core.FULL_SCREEN_ACTIVATED.value);\n        this.view.find('fullscreenButton').selected = Core.FULL_SCREEN_ACTIVATED.value;\n        this.onFullScreenChanged();\n    }\n\n    // this handler is used if fullscreen is done due F11 key\n    protected onFullScreenToggledExternal(): void {\n        if (Core.environment.isFullScreenSupported() && Core.isDesktopMode) {\n            this.view.find('fullscreenButton').selected = Core.environment.fullScreenControl().isFullscreen;\n            Core.FULL_SCREEN_ACTIVATED.next(Core.environment.fullScreenControl().isFullscreen);\n            this.onFullScreenChanged();\n        }\n    }\n\n    private onFullScreenChanged(): void {\n        const isGoingFullScreen: boolean = this.view.find('fullscreenButton').selected;\n        if (isGoingFullScreen) {\n            PostMessageDispatcher.openFullScreen();\n        } else {\n            PostMessageDispatcher.closeFullScreen();\n        }\n    }\n}\n","import Core, { Timers } from '@egt/core';\nimport {\n    BangupActionConsts,\n    FeatureController,\n    Features,\n    ISlotConfiguration,\n    InitialSettings,\n    RootStore,\n    ServerState,\n    SlotComponents,\n    SpinAnalyzer,\n    UIState,\n} from '@egt/slot';\nimport { BetButton, Button, MoneyContainerGroup, ToggleButton, ViewContainer } from '@egt/ui-lib';\nimport { gsap } from 'gsap';\nimport { Container, DisplayObject, Graphics, Sprite, Ticker } from 'pixi.js';\nimport { asapScheduler, fromEvent } from 'rxjs';\nimport { distinctUntilChanged, observeOn, takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport IUIMainPanelView from '../../../IUIMainPanelView';\nimport { IUIMainPanelComponentConfigurationDefault } from '../interfaces/IUIMainPanelComponentConfigurationDefault';\nimport BaseFreeSpinsFeature from '@egt/base-free-spins';\n\n@injectable()\nexport default class UIMainPanelViewDefault extends ViewContainer implements IUIMainPanelView {\n    // Win and Balance value tweens\n    public balanceTween: any;\n    public winValueTween: any;\n\n    // this container is added to stage outside of this view because background of the UI should be with different z order\n    public mainPanelBackground: Container = new Container();\n    public settingsButton: ToggleButton;\n    public soundButton: ToggleButton;\n    public backgroundSoundButton: ToggleButton;\n    public soundButtonAnimation: Graphics;\n    public paytableButton: Button;\n    public helpButton: Button;\n    public winBangUpInterval: any;\n\n    protected betButtonsContainer: Sprite;\n    protected fakeBetButtonsCurrent: BetButton[] = [];\n    protected fakeBetButtonsNewLeft: BetButton[] = [];\n    protected fakeBetButtonsNewRight: BetButton[] = [];\n    protected fakeBetButtonsOffset: number = 0;\n    protected betButtonsSlidingStart: boolean = false;\n    protected slidBetButtonsHitArea: Graphics;\n\n    protected betButtonHeight: number = 90;\n    protected betButtonWidth: number = 113;\n    protected collectDuration: number = this.configuration.collectBangupDuration;\n    protected winThresholds: number[] = this.configuration.winThresholds;\n    protected winBangupDurations: number[] = this.configuration.winBangupDurations;\n    protected autoplayBangupDuration: number = this.configuration.autoplayBangupDuration;\n    protected freeSpinBangupDuration: number = this.configuration.freeSpinBangupDuration;\n    protected betButtonsContainerGroup: Sprite;\n    protected betBtnPieceLeft: Sprite;\n    protected betBtnPieceRight: Sprite;\n\n    // Orientation independent constants.\n    protected balanceAndWinButtonsWidth: number;\n    protected balanceAndWinButtonsHeight: number;\n\n    protected moneyContainerGroupHeight: number = 104;\n    protected mainPanelHeight: number = 214;\n    protected sidePanelGraphicsBottomOffset: number = -79;\n\n    // Landscape and portrait mode.\n    protected positions: any;\n\n    // UI Elements - top level.\n    protected mainPanel: ViewContainer;\n\n    // UI elements - main panel.\n    protected gradientFramePortrait: Sprite;\n    protected mainPanelGraphics: Graphics;\n    // protected denomChangeGraphics: Graphics;\n    protected fakeBetButtonsMask: Sprite;\n    protected mainPanelGraphicsLeft: Sprite;\n    protected mainPanelGraphicsRight: Sprite;\n    protected mainPanelGraphicsBackgroundSoundsRight: Sprite;\n\n    // UI elements - main panel, money group.\n    protected winContainer: MoneyContainerGroup;\n    protected balanceContainer: MoneyContainerGroup;\n\n    protected soundStopTween: any;\n    protected soundAnimationFn: any;\n\n    protected xDown: any;\n    protected yDown: any;\n    protected pointerId: number = -1;\n\n    protected slideType: 'slideLeft' | 'slideRight' | 'none' = 'none';\n\n    protected currentState: any;\n\n    protected fullscreenButton: ToggleButton;\n    // This is used for storing the context of handleTouchEnd function so it will\n    // be possible to remove the event listener\n    // private handleTouchEndFn: any;\n    protected priorGambleWin: number;\n\n    private elements: Map<string, ViewContainer | DisplayObject> = new Map<string, DisplayObject>();\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected configuration: ISlotConfiguration,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('FeatureController') protected feature: FeatureController,\n        @inject('UIMainPanelComponentConfiguration')\n        protected componentConfiguration: IUIMainPanelComponentConfigurationDefault,\n        @inject('SpinAnalyzer') protected spinAnalyzer: SpinAnalyzer,\n    ) {\n        super();\n\n        this.name = 'UIMainView';\n        // this.setBalanceAndWinSize();\n        this.createMainPanel();\n        this.interactive = false;\n        this.enableUI(true);\n        this.children.forEach((child) => {\n            this.elements.set(child.name, child);\n        });\n        // this.setMainMoneyIndicator();\n\n        this.rootStore.subjects.BEFORE_SPIN.pipe(takeUntil(this.DESTROY)).subscribe(this.onBeforeSpin.bind(this));\n\n        // Core.SELECTED_DENOMINATION.pipe(takeUntil(this.DESTROY)).subscribe(this.resizeBetButtonsFonts.bind(this));\n\n        this.rootStore.uiStore.CLEAR_BANG_UP.pipe(takeUntil(this.DESTROY)).subscribe(this.stopBangupTweens.bind(this));\n\n        this.rootStore.domainStore.COLLECT_RESPONSE.pipe(takeUntil(this.DESTROY)).subscribe(this.onCollect.bind(this));\n\n        this.rootStore.uiStore.COLLECT_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.stopBangupTweens.bind(this),\n        );\n\n        Core.SELECTED_DENOMINATION.pipe(distinctUntilChanged(), takeUntil(this.DESTROY)).subscribe(() => {\n            this.checkCollect();\n        });\n\n        this.rootStore.uiStore.SELECTED_BET.pipe(\n            distinctUntilChanged(),\n            observeOn(asapScheduler),\n            takeUntil(this.DESTROY),\n        ).subscribe(() => {\n            this.checkCollect();\n        });\n        this.rootStore.uiStore.BALANCE.pipe(takeUntil(this.DESTROY)).subscribe(this.onBalanceChanged.bind(this));\n\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.applyMainPanelPositions.bind(this));\n        this.rootStore.subjects.ACTIVE_FEATURE.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.applyMainPanelPositions.bind(this),\n        );\n        this.rootStore.subjects.ACTIVE_COMPONENT.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.applyMainPanelPositions.bind(this),\n        );\n\n        this.rootStore.uiStore.STATE.pipe(takeUntil(this.DESTROY)).subscribe(this.onStateChanged.bind(this));\n\n        this.rootStore.uiStore.WIN.pipe(takeUntil(this.DESTROY)).subscribe(this.onWinChanged.bind(this));\n\n        this.rootStore.subjects.SHOW_HIDE_MAIN_VIEW_COMPONENTS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.setProperties.bind(this),\n        );\n\n        // this.rootStore.uiStore.LINES.pipe(takeUntil(this.DESTROY)).subscribe(this.linesChanged.bind(this));\n\n        // rootStore.subjects.FEATURE_COMPLETE.pipe(\n        //     takeUntil(this.DESTROY),\n        //     filter(feat => feat === Features.COIN),\n        // ).subscribe(this.enableBackgroundSoundButton.bind(this));\n\n        this.rootStore.subjects.MODAL_PRESSED.pipe(takeUntil(this.DESTROY)).subscribe(this.stopBangupTweens.bind(this));\n\n        // this.rootStore.subjects.FACTOR_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(this.onFactorChanged.bind(this));\n\n        Core.MONEY_MODE_IN_CREDITS.pipe(takeUntil(Core.ON_GAME_UNLOADED)).subscribe(this.onMoneyModeChanged.bind(this));\n        Core.sounds.ON_SOUND_MUTED.pipe(takeUntil(this.DESTROY)).subscribe(this.onSoundMuted.bind(this));\n        // this.rootStore.subjects.BET_BUTTONS_LABLE_STATE.pipe(takeUntil(this.DESTROY)).subscribe(\n        //     this.setBetButtonsLable.bind(this),\n        // );\n\n        if (settings.state !== UIState.IDLE) {\n            // RESTORE\n            this.balanceContainer.moneyAnimatedText.money = this.rootStore.uiStore.BALANCE.value;\n            this.balanceContainer.creditsAnimatedText.money = this.rootStore.uiStore.BALANCE.value;\n        }\n    }\n\n    public destroy(): void {\n        this.removeChildren();\n        if (this.balanceTween) {\n            this.balanceTween.totalProgress(1);\n            this.balanceTween.kill();\n            this.balanceTween = null;\n        }\n        if (this.winValueTween) {\n            this.winValueTween.totalProgress(1);\n            this.winValueTween.kill();\n            this.winValueTween = null;\n        }\n        if (this.soundStopTween) {\n            this.soundStopTween.totalProgress(1);\n            this.soundStopTween.kill();\n            this.soundStopTween = null;\n        }\n\n        this.balanceContainer.destroy();\n        this.winContainer.destroy();\n        this.settingsButton.destroy();\n        this.soundButton.destroy();\n        // this.backgroundSoundButton.destroy();\n        this.paytableButton.destroy();\n        // this.betPortraitGraphics.destroy();\n        // this.mainPanelGraphics.destroy();\n        // this.mainPanelGraphicsLeft.destroy();\n        // this.mainPanelGraphicsRight.destroy();\n        // this.mainPanel.destroy();\n\n        // @ts-ignore\n        this.paytableButton = null;\n        // @ts-ignore\n        // this.betPortraitGraphics = null;\n        // @ts-ignore\n        this.mainPanelGraphics = null;\n        // @ts-ignore\n        this.mainPanelGraphicsLeft = null;\n        // @ts-ignore\n        this.mainPanelGraphicsRight = null;\n        // @ts-ignore\n        this.denomChangeGraphics = null;\n        // @ts-ignore\n        this.betbuttonsGraphics = null;\n        // @ts-ignore\n        this.mainPanel = null;\n\n        // @ts-ignore\n        this.winMoney = null;\n        // @ts-ignore\n        this.winCredits = null;\n        // @ts-ignore\n        this.balanceMoney = null;\n        // @ts-ignore\n        this.balanceCredits = null;\n        // @ts-ignore\n        this.winText = null;\n        // @ts-ignore\n        this.settingsButton = null;\n        // @ts-ignore\n        this.soundButton = null;\n        // @ts-ignore\n        // this.backgroundSoundButton = null;\n        // @ts-ignore\n        this.betButtonsSlidingStart = null;\n\n        // this.balanceContainerHitArea.destroy();\n        // @ts-ignore\n        this.balanceContainerHitArea = null;\n\n        // this.winContainerHitArea.destroy();\n        // @ts-ignore\n        this.winContainerHitArea = null;\n\n        Ticker.shared.remove(this.soundAnimationFn);\n        // Timers.clearTimeout(this.timerID);\n\n        // window.removeEventListener('pointerup', this.handleTouchEndFn);\n\n        // if (this.handleTouchEndFn) {\n        //     this.handleTouchEndFn = null;\n        // }\n\n        this.elements.clear();\n        // @ts-ignore\n        this.elements = null;\n\n        super.destroy({ children: true, texture: true, baseTexture: true });\n    }\n\n    public soundButtonAnimationStop(): void {\n        Ticker.shared.remove(this.soundAnimationFn);\n        this.mainPanel.removeChild(this.soundButtonAnimation);\n        this.soundButton.enabled = true;\n    }\n\n    public stopBangupTweens(forceCompleteBangup = false): void {\n        if (this.rootStore.uiStore.BANGUP_RUNNING.value) {\n            this.rootStore.uiStore.BANGUP_RUNNING.next(false);\n        }\n        if (this.winBangUpInterval || forceCompleteBangup) {\n            Timers.clearInterval(this.winBangUpInterval);\n            this.onBangupComplete(this.rootStore.uiStore.WIN.value.amount);\n        }\n        if (!this.winValueTween || this.winValueTween._act === 0) {\n            return;\n        }\n\n        if (this.winValueTween) {\n            this.winValueTween.totalProgress(1);\n            this.winValueTween.kill();\n            this.winValueTween = null;\n        }\n        if (this.balanceTween) {\n            this.balanceTween.totalProgress(1);\n            this.balanceTween.kill();\n            this.balanceTween = null;\n        }\n        Core.sounds.stop('collectSound');\n    }\n\n    public onBeforeSpin(): void {\n        this.rootStore.uiStore.CLEAR_BANG_UP.next();\n    }\n\n    public onCollect(response): void {\n        if (\n            this.rootStore.uiStore.STATE.value !== UIState.BONUS_IDLE &&\n            this.rootStore.uiStore.STATE.value !== UIState.BONUS_SUMMARY\n        ) {\n            this.priorGambleWin = this.rootStore.uiStore.WIN.value.amount;\n        }\n        this.rootStore.uiStore.CLEAR_BANG_UP.next();\n        const incrementValue: any = { money: 0 };\n        this.rootStore.uiStore.WIN.next({\n            amount: 0,\n            action: BangupActionConsts.COLLECT,\n            feature: Features.NONE,\n            duration: this.configuration.collectBangupDuration,\n        });\n        const currentBalance = this.balanceContainer.moneyAnimatedText.money;\n        let toBalance = currentBalance;\n        let onUpdate = () => {\n            //\n        };\n\n        if (\n            !this.feature.isInGiftSpins ||\n            (this.feature.isInGiftSpins &&\n                (!this.settings.gsFinalCollection ||\n                    this.rootStore.domainStore.SERVER_STATE.value === ServerState.BONUS_SUMMARY))\n        ) {\n            toBalance += Number(this.winContainer.moneyAnimatedText.money);\n            onUpdate = () => {\n                const newBalance = Math.floor(currentBalance + incrementValue.money);\n                if (toBalance !== response.balance) {\n                    this.balanceContainer.moneyAnimatedText.money = response.balance;\n                    this.balanceContainer.creditsAnimatedText.money = response.balance;\n                } else {\n                    this.updateBalanceFields(newBalance);\n                }\n            };\n        }\n        // if win value is 0 the tween may finish after the next bet and the balance will be broken - noticed with gs\n        const duration = this.winContainer.moneyAnimatedText.money === 0 ? 0 : this.collectDuration;\n        const prevWinAmount = this.rootStore.uiStore.WIN.prevValue.amount;\n        const lastWinAmount = this.rootStore.domainStore.betResponse?.result?.lastWinAmount;\n        const giftSpinsCondition = lastWinAmount > 0 && this.rootStore.uiStore.WIN.value.amount === 0;\n        this.balanceTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/ui-main-panel/src/egt/modes/default/views/UIMainPanelViewDefault.ts:359:29\",null]), gsap.to(incrementValue, {\n            duration,\n            money: this.winContainer.moneyAnimatedText.money,\n            ease: 'none',\n            onUpdate,\n            onComplete: () => {\n                this.rootStore.uiStore.BALANCE.next(response.balance);\n\n                if (!this.rootStore.uiStore) return;\n\n                const shouldUpdateWin = prevWinAmount > 0 || giftSpinsCondition;\n                if (shouldUpdateWin) {\n                    const moneyValue = giftSpinsCondition && !prevWinAmount ? lastWinAmount : prevWinAmount;\n                    this.winContainer.moneyAnimatedText.money = moneyValue;\n                    this.winContainer.creditsAnimatedText.money = moneyValue;\n                    this.winContainer.labelText.text = Core.translator.translate('LAST WIN');\n                    // }, 50);\n                }\n            },\n        }));\n    }\n\n    public enableUI(enableUI: boolean): void {\n        this.interactiveChildren = enableUI;\n    }\n\n    public enableSomeButtons(buttonsArr: string[], enabled: boolean): void {\n        buttonsArr.forEach((button) => {\n            if (this[button]) {\n                this[button].enabled = enabled;\n            }\n        });\n    }\n\n    public setPostionsBetButtons(): void {\n        // this.setOrientation(Core.ORIENTATION.value);\n    }\n\n    // public showBetButtons(): void {\n    // for (const betButton of this.betButtons) {\n    //     betButton.visible = true;\n    // }\n    // this.showBetButtonParts();\n    // }\n\n    public resizeBetButtonsFonts(): void {\n        // let defaultFontSize: number = 36;\n        // if (Core.isDesktopMode) {\n        //     defaultFontSize = 27;\n        // }\n        // this.applyFontSize(defaultFontSize);\n    }\n\n    public hideWinText(val: boolean): void {\n        this.winContainer.visible = val;\n    }\n\n    public hideBalanceText(val: boolean): void {\n        this.balanceContainer.visible = val;\n    }\n\n    public getBangupDuration(amount: number): number {\n        let bangupDuration: number = this.winBangupDurations[0];\n        const winAmount =\n            (amount === undefined ? this.rootStore.uiStore.WIN.value.amount : amount) *\n            Core.SELECTED_DENOMINATION.value;\n        if (this.winContainer.moneyAnimatedText.money > 0 && this.rootStore.uiStore.STATE.value === 'idle') {\n            bangupDuration = this.collectDuration;\n        } else if (this.rootStore.domainStore.SPIN_MODE.value === Features.AUTO_PLAY) {\n            bangupDuration = this.getAutoplayDurations();\n        } else if (this.rootStore.domainStore.SPIN_MODE.value === Features.FREE_SPINS) {\n            bangupDuration = this.freeSpinBangupDuration;\n        } else if (this.rootStore.domainStore.SPIN_MODE.value === Features.BL_JACKPOT) {\n            bangupDuration = this.configuration.bellLinkBangupDuration;\n        } else if (this.rootStore.uiStore.turboModeEnabled) {\n            bangupDuration = this.getAutoplayDurations();\n        } else {\n            for (let i = 0; i < this.winThresholds.length; i++) {\n                if (winAmount >= this.winThresholds[i]) {\n                    bangupDuration = this.winBangupDurations[i];\n                } else {\n                    break;\n                }\n            }\n        }\n        return bangupDuration;\n    }\n\n    // protected setBalanceAndWinSize(): void {\n    //     this.balanceAndWinButtonsWidth = 185;\n    //     this.balanceAndWinButtonsHeight = 100;\n    // }\n\n    protected createMainPanel(): void {\n        // const container: ViewContainer = new ViewContainer();\n\n        // Create buttons\n        this.settingsButton = new ToggleButton(\n            new Button([Core.assets.getAsset(this.componentConfiguration.settingsButtonProps.textures[0]).texture]),\n            new Button([Core.assets.getAsset(this.componentConfiguration.settingsButtonProps.textures[1]).texture]),\n        );\n        this.settingsButton.name = 'settingsButton';\n        this.settingsButton.pivot.set(this.settingsButton.width / 2, this.settingsButton.height / 2);\n\n        this.soundButton = new ToggleButton(\n            new Button([Core.assets.getAsset(this.componentConfiguration.soundButton.textures[0]).texture]),\n            new Button([Core.assets.getAsset(this.componentConfiguration.soundButton.textures[1]).texture]),\n        );\n        this.soundButton.name = 'soundButton';\n        this.soundButton.pivot.set(this.soundButton.width / 2, this.soundButton.height / 2);\n\n        this.paytableButton = new Button([\n            Core.assets.getAsset(this.componentConfiguration.paytableButtonPosition.textures[0]).texture,\n        ]);\n        this.paytableButton.name = 'paytableButton';\n        this.paytableButton.pivot.set(this.paytableButton.width / 2, this.paytableButton.height / 2);\n\n        this.addChild(this.settingsButton);\n        this.addChild(this.soundButton);\n\n        this.createBalanceContainer();\n        this.createWinContainer();\n\n        if (Core.allow_money_mode_change) {\n            Core.UI_BLOCKER.pipe(takeUntil(this.DESTROY)).subscribe((isUiBlocked) => {\n                this.balanceContainer.toggleInteractivity(!isUiBlocked);\n                this.winContainer.toggleInteractivity(!isUiBlocked);\n            });\n        }\n\n        this.addChild(this.paytableButton);\n        this.addChild(this.balanceContainer);\n        this.addChild(this.winContainer);\n\n        if (this.componentConfiguration.fullScreenButton.visible) {\n            this.fullscreenButton = new ToggleButton(\n                new Button([Core.assets.getAsset(this.componentConfiguration.fullScreenButton.textures[0]).texture]),\n                new Button([Core.assets.getAsset(this.componentConfiguration.fullScreenButton.textures[1]).texture]),\n            );\n            this.fullscreenButton.name = 'fullscreenButton';\n            this.fullscreenButton.interactive = true;\n            this.fullscreenButton.buttonMode = true;\n            this.fullscreenButton.selected = Core.environment.isFullScreen();\n            this.addChild(this.fullscreenButton);\n            if (Core.configuration.hideFullScreenButton) {\n                this.fullscreenButton.interactive = false;\n                this.fullscreenButton.enabled = false;\n                this.fullscreenButton.children.forEach((subButton: Button) => {\n                    (subButton.children[0] as Sprite).tint = 0x808080;\n                });\n            }\n\n            this.fullscreenButton.x = this.componentConfiguration.fullScreenButton.x;\n            this.fullscreenButton.y = this.componentConfiguration.fullScreenButton.y;\n            this.fullscreenButton.pivot.set(this.fullscreenButton.width / 2, this.fullscreenButton.height / 2);\n        }\n\n        if (this.componentConfiguration.helpButton.visible) {\n            this.helpButton = new Button([\n                Core.assets.getAsset(this.componentConfiguration.helpButton.textures[0]).texture,\n            ]);\n            this.helpButton.name = 'helpButton';\n            this.helpButton.interactive = true;\n            this.helpButton.buttonMode = true;\n            this.addChild(this.helpButton);\n\n            this.helpButton.x = this.componentConfiguration.helpButton.x;\n            this.helpButton.y = this.componentConfiguration.helpButton.y;\n            this.helpButton.pivot.set(this.helpButton.width / 2, this.helpButton.height / 2);\n            /* this.helpButton.scale.set(this.componentConfiguration.helpButton.scale) */\n        }\n\n        // return container;\n\n        this.applyMainPanelPositions();\n    }\n\n    protected applyMainPanelPositions(): void {\n        this.paytableButton.x = this.componentConfiguration.paytableButtonPosition.x;\n        this.paytableButton.y = this.componentConfiguration.paytableButtonPosition.y;\n\n        this.paytableButton.scale.set(this.componentConfiguration.paytableButtonPosition.scale);\n\n        this.settingsButton.x = this.componentConfiguration.settingsButtonProps.x;\n        this.settingsButton.y = this.componentConfiguration.settingsButtonProps.y;\n\n        this.settingsButton.scale.set(this.componentConfiguration.settingsButtonProps.scale);\n\n        this.winContainer.x = this.componentConfiguration.winContainerProperties.x;\n        this.winContainer.y = this.componentConfiguration.winContainerProperties.y;\n        this.balanceContainer.x = this.componentConfiguration.balanceContainerProperties.x;\n        this.balanceContainer.y = this.componentConfiguration.balanceContainerProperties.y;\n\n        this.soundButton.x = this.componentConfiguration.soundButton.x;\n        this.soundButton.y = this.componentConfiguration.soundButton.y;\n\n        this.soundButton.scale.set(this.componentConfiguration.soundButton.scale);\n\n        if (this.helpButton) {\n            this.helpButton.x = this.componentConfiguration.helpButton.x;\n            this.helpButton.y = this.componentConfiguration.helpButton.y;\n            this.helpButton.scale.set(this.componentConfiguration.helpButton.scale);\n        }\n\n        this.balanceContainer.setOrientation(\n            this.componentConfiguration.balanceContainerProperties.width,\n            this.componentConfiguration.balanceContainerProperties.height,\n            {\n                currency: {\n                    width: this.componentConfiguration.balanceContainerProperties.currencyWidth,\n                    height: this.componentConfiguration.balanceContainerProperties.currencyHeight,\n                    lineOffset: this.componentConfiguration.balanceContainerProperties.currencyLineOffset,\n                    style: this.componentConfiguration.balanceContainerProperties.currencyStyle,\n                },\n                money: {\n                    width: this.componentConfiguration.balanceContainerProperties.moneyWidth,\n                    height: this.componentConfiguration.balanceContainerProperties.moneyHeight,\n                    lineOffset: this.componentConfiguration.balanceContainerProperties.moneyLineOffset,\n                    style: this.componentConfiguration.balanceContainerProperties.moneyStyle,\n                },\n                credits: {\n                    width: this.componentConfiguration.balanceContainerProperties.creditsWidth,\n                    height: this.componentConfiguration.balanceContainerProperties.creditsHeight,\n                    lineOffset: this.componentConfiguration.balanceContainerProperties.creditsLineOffset,\n                    style: this.componentConfiguration.balanceContainerProperties.creditsStyle,\n                },\n                label: {\n                    width: this.componentConfiguration.balanceContainerProperties.labelWidth,\n                    height: this.componentConfiguration.balanceContainerProperties.labelHeight,\n                    lineOffset: this.componentConfiguration.balanceContainerProperties.labelLineOffset,\n                    style: this.componentConfiguration.balanceContainerProperties.labelStyle,\n                },\n            },\n        );\n        this.winContainer.setOrientation(\n            this.componentConfiguration.winContainerProperties.width,\n            this.componentConfiguration.winContainerProperties.height,\n            {\n                currency: {\n                    width: this.componentConfiguration.winContainerProperties.currencyWidth,\n                    height: this.componentConfiguration.winContainerProperties.currencyHeight,\n                    lineOffset: this.componentConfiguration.winContainerProperties.currencyLineOffset,\n                    style: this.componentConfiguration.winContainerProperties.currencyStyle,\n                },\n                money: {\n                    width: this.componentConfiguration.winContainerProperties.moneyWidth,\n                    height: this.componentConfiguration.winContainerProperties.moneyHeight,\n                    lineOffset: this.componentConfiguration.winContainerProperties.moneyLineOffset,\n                    style: this.componentConfiguration.winContainerProperties.moneyStyle,\n                },\n                credits: {\n                    width: this.componentConfiguration.winContainerProperties.creditsWidth,\n                    height: this.componentConfiguration.winContainerProperties.creditsHeight,\n                    lineOffset: this.componentConfiguration.winContainerProperties.creditsLineOffset,\n                    style: this.componentConfiguration.winContainerProperties.creditsStyle,\n                },\n                label: {\n                    width: this.componentConfiguration.winContainerProperties.labelWidth,\n                    height: this.componentConfiguration.winContainerProperties.labelHeight,\n                    lineOffset: this.componentConfiguration.winContainerProperties.labelLineOffset,\n                    style: this.componentConfiguration.winContainerProperties.labelStyle,\n                },\n            },\n        );\n    }\n\n    protected onStateChanged(): void {\n        switch (this.rootStore.uiStore.STATE.value) {\n            case UIState.IDLE:\n            case UIState.BONUS_IDLE:\n                this.paytableButton.enabled = true;\n                this.settingsButton.enabled = true;\n                this.helpButton?.setEnabled(true);\n                break;\n            case UIState.UNSET:\n            case UIState.WAITING_FOR_RESPONSE:\n                this.paytableButton.enabled = false;\n                this.settingsButton.enabled = false;\n                // this.backgroundSoundButton.enabled = false;\n                this.helpButton?.setEnabled(false);\n                break;\n            case UIState.WAITING_FOR_RESPONSE_IN_AUTOPLAY:\n                this.paytableButton.enabled = false;\n                this.settingsButton.enabled = false;\n                // this.backgroundSoundButton.enabled = true;\n                this.helpButton?.setEnabled(false);\n                break;\n            case UIState.WAITING_FOR_RESPONSE_IN_FREESPIN:\n                this.paytableButton.enabled = false;\n                this.settingsButton.enabled = false;\n                // this.backgroundSoundButton.enabled = true;\n                this.helpButton?.setEnabled(false);\n                break;\n            case UIState.WAITING_FOR_RESPONSE_IN_RESPIN:\n                this.helpButton?.setEnabled(false);\n                // this.backgroundSoundButton.enabled = true;\n                this.paytableButton.enabled = false;\n                this.settingsButton.enabled = false;\n                // this.backgroundSoundButton.enabled = true;\n                this.rootStore.subjects.ENABLE_ALL_BET_BUTTONS.next(false);\n                break;\n            case UIState.WIN:\n                this.paytableButton.enabled = false;\n                this.settingsButton.enabled = false;\n                // this.backgroundSoundButton.enabled = false;\n                this.helpButton?.setEnabled(false);\n                break;\n            case UIState.FREESPIN:\n                this.paytableButton.enabled = false;\n                this.settingsButton.enabled = false;\n                this.helpButton?.setEnabled(false);\n                break;\n            case UIState.RESPIN:\n            case UIState.EXIT_FREESPIN:\n            case UIState.BELL_LINK:\n            case UIState.CASH_HEAT:\n            case UIState.GODS_AND_KINGS_LINK:\n            case UIState.HIGH_CASH_FEATURE:\n            case UIState.BONUS_CHANCE:\n                this.paytableButton.enabled = false;\n                this.settingsButton.enabled = false;\n                this.helpButton?.setEnabled(false);\n                break;\n            case UIState.MYSTERY:\n                this.paytableButton.enabled = false;\n                this.settingsButton.enabled = false;\n                // this.backgroundSoundButton.enabled = true;\n                this.helpButton?.setEnabled(false);\n                break;\n            case UIState.PICK_ME_BONUS:\n                this.paytableButton.enabled = false;\n                this.settingsButton.enabled = false;\n                // this.backgroundSoundButton.enabled = false;\n                this.helpButton?.setEnabled(false);\n                break;\n            case UIState.GAMBLE:\n                this.paytableButton.enabled = false;\n                this.settingsButton.enabled = false;\n                // this.backgroundSoundButton.enabled = false;\n                this.helpButton?.setEnabled(false);\n                break;\n            case UIState.LAST_GAMBLE_WIN:\n                this.helpButton?.setEnabled(false);\n                break;\n            case UIState.WAITING_FOR_COLLECT:\n                const noBangUpRunning = !this.rootStore.uiStore.BANGUP_RUNNING.value;\n                const lastGiftSpin =\n                    this.feature.isInGiftSpins && this.rootStore.domainStore.betResponse?.bonus?.remaining === 0;\n                this.helpButton?.setEnabled(noBangUpRunning && !lastGiftSpin);\n                this.settingsButton.enabled = noBangUpRunning && !lastGiftSpin;\n                this.paytableButton.enabled = noBangUpRunning && !lastGiftSpin;\n                break;\n            case UIState.WAITING_FOR_COLLECT_IN_AUTOPLAY:\n                this.helpButton?.setEnabled(false);\n                if (\n                    this.rootStore.domainStore.betResponse?.bonusGamesTotalWinAmount ===\n                        this.rootStore.domainStore.betResponse?.totalWinAmount ||\n                    this.rootStore.domainStore.betResponse?.totalWinAmount === undefined\n                    // this.rootStore.domainStore.betResponse.totalWin\n                ) {\n                    this.settingsButton.enabled = false;\n                    this.paytableButton.enabled = false;\n                }\n                break;\n            case UIState.SLIDING_BETS:\n            case UIState.DISABLED:\n                this.helpButton?.setEnabled(false);\n                this.paytableButton.enabled = false;\n                this.settingsButton.enabled = false;\n                break;\n        }\n\n        this.setWinLastWinLabel();\n    }\n\n    protected onMoneyModeChanged(): void {\n        this.balanceContainer.onMoneyModeChanged();\n        this.winContainer.onMoneyModeChanged();\n    }\n\n    protected onBangupComplete(winAmount): void {\n        if (this.rootStore.uiStore) {\n            if (this.rootStore.uiStore.BANGUP_RUNNING.value) {\n                this.rootStore.uiStore.BANGUP_RUNNING.next(false);\n            }\n\n            const moneyEndSound: string =\n                this.spinAnalyzer.inFreeSpins() && Core.sounds.hasSound('fsMoneyAnimationEndSound')\n                    ? 'fsMoneyAnimationEndSound'\n                    : 'moneyAnimationEndSound';\n            const creditSound: string =\n                this.spinAnalyzer.inFreeSpins() && Core.sounds.hasSound('fsCreditAnimationSound')\n                    ? 'fsCreditAnimationSound'\n                    : 'creditAnimationSound';\n\n            if (Core.sounds.isPlaying(creditSound) && Core.hasFeature(Features.LINES)) {\n                if (Core.hasComponent(SlotComponents.BACKGROUND_SOUND)) {\n                    const shouldSeek = Core.sounds.getBGSoundConfiguration().syncCreditSoundWithBgSound;\n\n                    // Get the current win/line sound\n                    const winSound = this.spinAnalyzer.getHighestPayingSymbolSound(\n                        this.rootStore.domainStore.betResponse.entries,\n                    );\n                    // Get the creditAnimationSound Config so we can properly fadeOut the sound\n                    const config = Core.sounds.getBGSoundConfiguration().creditAnimationSound;\n                    const soundConfig = config[winSound] ? config[winSound] : config.default;\n\n                    Core.sounds.fadeOutAndStop(creditSound, soundConfig.fadeOut.duration);\n                    Core.sounds.fadeOutAndStop(\n                        this.rootStore.uiStore.creditLineSoundPlaying,\n                        soundConfig.fadeOut.duration,\n                    );\n                    if (shouldSeek) {\n                        // the bangup is over so there is no need for sync between bg and credit sounds anymore\n                        this.rootStore.uiStore.SYNC_BACKGROUND_AND_CREDIT_SOUNDS.next(false);\n                    }\n                } else {\n                    // For games which don't support SlotComponents.BACKGROUND_SOUND\n                    Core.sounds.stop(creditSound);\n                    Core.sounds.stop(this.rootStore.uiStore.creditLineSoundPlaying);\n                }\n\n                Core.sounds.play(moneyEndSound);\n\n                if (this.rootStore.uiStore.winSoundPlaying === creditSound) {\n                    this.rootStore.uiStore.winSoundPlaying = '';\n                }\n            }\n            if (\n                this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT ||\n                this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT_IN_AUTOPLAY\n            ) {\n                const lastGiftSpin =\n                    this.feature.isInGiftSpins && this.rootStore.domainStore.betResponse?.bonus?.remaining === 0;\n                this.helpButton?.setEnabled(!lastGiftSpin);\n                this.paytableButton.enabled = !lastGiftSpin;\n                this.settingsButton.enabled = !lastGiftSpin;\n            }\n            if (this.rootStore.uiStore.STATE.value === UIState.WIN) {\n                if (this.rootStore.domainStore.SPIN_MODE.value !== Features.AUTO_PLAY) {\n                    this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_COLLECT);\n                } else {\n                    this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_COLLECT_IN_AUTOPLAY);\n                }\n            }\n            this.winBangUpInterval = null;\n            if (this.rootStore.uiStore.WIN.value.feature !== Features.MAX_WIN_LIMIT) {\n                this.rootStore.uiStore.CLEAR_BANG_UP.next();\n            }\n            this.updateMoneyFields(winAmount);\n        }\n\n        if (Core.sounds.isPlaying('freeSpinsCollect')) {\n            Core.sounds.stop('freeSpinsCollect');\n            Core.sounds.play('freeSpinsCollectEnd');\n            if (this.rootStore.uiStore.winSoundPlaying === 'freeSpinsCollect') {\n                this.rootStore.uiStore.winSoundPlaying = '';\n            }\n        }\n    }\n\n    protected getCurrentDenominationLevel(): number {\n        let currentLevel: number = 0;\n        for (let i: number = 0; i < this.rootStore.uiStore.denominations.length; i++) {\n            if (this.rootStore.uiStore.denominations[i] === Core.SELECTED_DENOMINATION.value) {\n                currentLevel = i;\n            }\n        }\n        return currentLevel + 1;\n    }\n\n    protected checkCollect(): void {\n        if (\n            (this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT ||\n                (this.rootStore.uiStore.STATE.value === UIState.SLIDING_BETS &&\n                    this.rootStore.domainStore.SERVER_STATE.value === ServerState.WIN)) &&\n            !this.feature.isInGiftSpins\n        ) {\n            if (\n                this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value ||\n                !this.rootStore.subjects.IS_ONE_DENOMINATION.value\n            ) {\n                this.rootStore.uiStore.STATE.next(UIState.DISABLED);\n            }\n\n            this.rootStore.domainStore.collect();\n            this.rootStore.uiStore.COLLECT_CHANGED.next();\n        }\n    }\n\n    protected createBalanceContainer(): void {\n        this.balanceContainer = new MoneyContainerGroup(\n            'balance',\n            Core.translator.translate('BALANCE'),\n            this.componentConfiguration.balanceContainerProperties.width,\n            this.componentConfiguration.balanceContainerProperties.height,\n            {\n                currency: {\n                    width: this.componentConfiguration.balanceContainerProperties.currencyWidth,\n                    height: this.componentConfiguration.balanceContainerProperties.currencyHeight,\n                    lineOffset: this.componentConfiguration.balanceContainerProperties.currencyLineOffset,\n                    style: this.componentConfiguration.balanceContainerProperties.currencyStyle,\n                },\n                money: {\n                    width: this.componentConfiguration.balanceContainerProperties.moneyWidth,\n                    height: this.componentConfiguration.balanceContainerProperties.moneyHeight,\n                    lineOffset: this.componentConfiguration.balanceContainerProperties.moneyLineOffset,\n                    style: this.componentConfiguration.balanceContainerProperties.moneyStyle,\n                },\n                credits: {\n                    width: this.componentConfiguration.balanceContainerProperties.creditsWidth,\n                    height: this.componentConfiguration.balanceContainerProperties.creditsHeight,\n                    lineOffset: this.componentConfiguration.balanceContainerProperties.creditsLineOffset,\n                    style: this.componentConfiguration.balanceContainerProperties.creditsStyle,\n                },\n                label: {\n                    width: this.componentConfiguration.balanceContainerProperties.labelWidth,\n                    height: this.componentConfiguration.balanceContainerProperties.labelHeight,\n                    lineOffset: this.componentConfiguration.balanceContainerProperties.labelLineOffset,\n                    style: this.componentConfiguration.balanceContainerProperties.labelStyle,\n                },\n            },\n            {\n                currencyStyle: this.componentConfiguration.balanceContainerProperties.currencyStyle,\n                moneyStyle: this.componentConfiguration.balanceContainerProperties.moneyStyle,\n                moneyTint: this.componentConfiguration.balanceContainerProperties.moneyTint,\n                creditsStyle: this.componentConfiguration.balanceContainerProperties.creditsStyle,\n                labelStyle: this.componentConfiguration.balanceContainerProperties.labelStyle,\n            },\n            this.rootStore.uiStore.currency,\n            this.rootStore.uiStore.units,\n        );\n\n        if (Core.allow_money_mode_change) {\n            this.balanceContainer.toggleInteractivity(true);\n            (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/ui-main-panel/src/egt/modes/default/views/UIMainPanelViewDefault.ts:894:13\",(this.balanceContainer.groupHitArea),\"pointertap\"]), fromEvent(this.balanceContainer.groupHitArea, 'pointertap'))\n                .pipe(takeUntil(this.DESTROY))\n                .subscribe(() => {\n                    if (Core.UI_BLOCKER.value) {\n                        return;\n                    }\n                    Core.sounds.play(!Core.MONEY_MODE_IN_CREDITS.value ? 'creditSound' : 'currencySound');\n                    Core.MONEY_MODE_IN_CREDITS.next(!Core.MONEY_MODE_IN_CREDITS.value);\n                });\n        }\n    }\n\n    protected createWinContainer(): void {\n        // Create Win Money Text\n\n        this.winContainer = new MoneyContainerGroup(\n            'win',\n            Core.translator.translate('WIN'),\n            this.componentConfiguration.winContainerProperties.width,\n            this.componentConfiguration.winContainerProperties.height,\n            {\n                currency: {\n                    width: this.componentConfiguration.winContainerProperties.currencyWidth,\n                    height: this.componentConfiguration.winContainerProperties.currencyHeight,\n                    lineOffset: this.componentConfiguration.winContainerProperties.currencyLineOffset,\n                    style: this.componentConfiguration.winContainerProperties.currencyStyle,\n                },\n                money: {\n                    width: this.componentConfiguration.winContainerProperties.moneyWidth,\n                    height: this.componentConfiguration.winContainerProperties.moneyHeight,\n                    lineOffset: this.componentConfiguration.winContainerProperties.moneyLineOffset,\n                    style: this.componentConfiguration.winContainerProperties.moneyStyle,\n                },\n                credits: {\n                    width: this.componentConfiguration.winContainerProperties.creditsWidth,\n                    height: this.componentConfiguration.winContainerProperties.creditsHeight,\n                    lineOffset: this.componentConfiguration.balanceContainerProperties.creditsLineOffset,\n                    style: this.componentConfiguration.winContainerProperties.creditsStyle,\n                },\n                label: {\n                    width: this.componentConfiguration.winContainerProperties.labelWidth,\n                    height: this.componentConfiguration.winContainerProperties.labelHeight,\n                    lineOffset: this.componentConfiguration.winContainerProperties.labelLineOffset,\n                    style: this.componentConfiguration.winContainerProperties.labelStyle,\n                },\n            },\n            {\n                currencyStyle: this.componentConfiguration.winContainerProperties.currencyStyle,\n                moneyStyle: this.componentConfiguration.winContainerProperties.moneyStyle,\n                moneyTint: this.componentConfiguration.winContainerProperties.moneyTint,\n                creditsStyle: this.componentConfiguration.winContainerProperties.creditsStyle,\n                labelStyle: this.componentConfiguration.winContainerProperties.labelStyle,\n            },\n            this.rootStore.uiStore.currency,\n            this.rootStore.uiStore.units,\n        );\n\n        if (Core.allow_money_mode_change) {\n            this.winContainer.toggleInteractivity(true);\n            (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/ui-main-panel/src/egt/modes/default/views/UIMainPanelViewDefault.ts:953:13\",(this.winContainer.groupHitArea),\"pointertap\"]), fromEvent(this.winContainer.groupHitArea, 'pointertap'))\n                .pipe(takeUntil(this.DESTROY))\n                .subscribe(() => {\n                    if (Core.UI_BLOCKER.value) {\n                        return;\n                    }\n                    Core.sounds.play(!Core.MONEY_MODE_IN_CREDITS.value ? 'creditSound' : 'currencySound');\n                    Core.MONEY_MODE_IN_CREDITS.next(!Core.MONEY_MODE_IN_CREDITS.value);\n                });\n        }\n    }\n\n    private getAutoplayDurations(): number {\n        let time: number = this.configuration.autoplayWinTime / 1000;\n        if (this.rootStore.uiStore.turboModeEnabled) {\n            time = this.configuration.autoplayWinTurboTime / 1000;\n        } else if (this.rootStore.uiStore.quickSpinEnabled) {\n            time = this.configuration.autoplayWinQuickTime / 1000;\n        }\n\n        const betResponse = this.rootStore.domainStore.betResponse;\n        if (betResponse) {\n            if (this.rootStore.isGreatWin) {\n                time = this.configuration.autoplayWinCoinFeatureTime / 1000;\n            }\n        }\n        return time;\n    }\n\n    private updateBalanceFields(winValue: number): void {\n        const ceiledValue = Math.floor(winValue);\n        this.balanceContainer.moneyAnimatedText.money = ceiledValue;\n        this.balanceContainer.creditsAnimatedText.money = ceiledValue;\n    }\n\n    private onBalanceChanged(): void {\n        this.balanceContainer.moneyAnimatedText.money = this.rootStore.uiStore.BALANCE.value;\n        this.balanceContainer.creditsAnimatedText.money = this.rootStore.uiStore.BALANCE.value;\n    }\n\n    private updateMoneyFields(winValue: number): void {\n        const ceiledValue = Math.ceil(winValue);\n        this.winContainer.moneyAnimatedText.money = ceiledValue;\n        this.winContainer.creditsAnimatedText.money = ceiledValue;\n    }\n\n    protected onWinChanged(): void {\n        const winAmount = this.rootStore.uiStore.WIN.value.amount;\n        switch (this.rootStore.uiStore.WIN.value.action) {\n            case BangupActionConsts.RESTORE:\n                const lastWinAmount = this.settings.lastWinAmount || this.rootStore.uiStore.WIN.prevValue.amount;\n                const restoreInFeatureWithoutFeatureWin =\n                    (this.rootStore.uiStore.STATE.value === UIState.FREESPIN ||\n                        this.rootStore.uiStore.STATE.value === UIState.BELL_LINK ||\n                        this.rootStore.uiStore.STATE.value === ServerState.HOLDSPIN ||\n                        this.rootStore.uiStore.STATE.value === ServerState.RESPIN ||\n                        this.rootStore.uiStore.STATE.value === ServerState.FREERESPIN ||\n                        this.rootStore.uiStore.STATE.value === ServerState.PICK ||\n                        this.rootStore.uiStore.STATE.value === UIState.GODS_AND_KINGS_LINK) &&\n                    this.settings.winAmount === 0;\n\n                this.winContainer.moneyAnimatedText.money = lastWinAmount;\n                this.winContainer.creditsAnimatedText.money = lastWinAmount;\n                this.priorGambleWin = lastWinAmount;\n                if (\n                    lastWinAmount > 0 &&\n                    (this.rootStore.uiStore.STATE.value === UIState.IDLE ||\n                        this.rootStore.uiStore.STATE.value === UIState.BONUS_IDLE ||\n                        restoreInFeatureWithoutFeatureWin)\n                ) {\n                    this.winContainer.labelText.text = Core.translator.translate('LAST WIN');\n                } else {\n                    this.rootStore.uiStore.WIN.next({\n                        amount: this.rootStore.uiStore.WIN.prevValue.amount,\n                        action: BangupActionConsts.SET,\n                        feature: this.rootStore.uiStore.WIN.value.feature,\n                    });\n                    this.winContainer.labelText.text = Core.translator.translate('WIN');\n                }\n                break;\n            case BangupActionConsts.SET:\n                this.stopBangupTweens();\n                if (\n                    this.rootStore.uiStore.WIN.prevValue.amount > 0 &&\n                    this.rootStore.uiStore.STATE.value === UIState.IDLE\n                ) {\n                    this.winContainer.labelText.text = Core.translator.translate('LAST WIN');\n                } else {\n                    if (winAmount > 0) {\n                        this.winContainer.labelText.text = Core.translator.translate('WIN');\n                        this.winContainer.moneyAnimatedText.money = winAmount;\n                        this.winContainer.creditsAnimatedText.money = winAmount;\n                    }\n\n                    if (winAmount === 0) {\n                        this.winContainer.moneyAnimatedText.money = Number(this.priorGambleWin);\n                        this.winContainer.creditsAnimatedText.money = Number(this.priorGambleWin);\n                        if (this.priorGambleWin > 0) {\n                            this.winContainer.labelText.text = Core.translator.translate('LAST WIN');\n                        } else {\n                            this.winContainer.labelText.text = Core.translator.translate('WIN');\n                        }\n                    }\n                }\n                break;\n            case BangupActionConsts.COLLECT:\n            case BangupActionConsts.ADD:\n            case BangupActionConsts.WIN:\n            case BangupActionConsts.BANGUP:\n                this.winContainer.labelText.text = Core.translator.translate('WIN');\n                this.rootStore.uiStore.BANGUP_RUNNING.next(true);\n                if (this.winValueTween) {\n                    this.winValueTween.totalProgress(1);\n                    this.winValueTween.kill();\n                    this.winValueTween = null;\n                }\n                if (this.rootStore.uiStore.WIN.prevValue.amount !== winAmount) {\n                    const startValue = this.rootStore.uiStore.WIN.prevValue.amount || 0;\n\n                    if (\n                        winAmount > startValue &&\n                        !this.rootStore.uiStore.fastSpinMode &&\n                        this.rootStore.domainStore.SPIN_MODE.value !== Features.AUTO_PLAY &&\n                        !this.rootStore.uiStore.WIN.value.duration\n                    ) {\n                        this.updateMoneyValue(\n                            winAmount / Core.SELECTED_DENOMINATION.value,\n                            startValue / Core.SELECTED_DENOMINATION.value,\n                            winAmount,\n                        );\n                    } else {\n                        // no backward bangup\n                        const duration = this.rootStore.uiStore.WIN.value.duration;\n                        this.createBangUpMoneyTween(winAmount, startValue, duration);\n                    }\n                } else {\n                    if (this.rootStore.uiStore.BANGUP_RUNNING.value) {\n                        this.rootStore.uiStore.BANGUP_RUNNING.next(false);\n                    }\n                    this.winContainer.moneyAnimatedText.money = winAmount;\n                    this.winContainer.creditsAnimatedText.money = winAmount;\n                }\n        }\n    }\n\n    protected createBangUpMoneyTween(winAmount: number, startValue: number, duration?: number): void {\n        if (winAmount < startValue && this.rootStore.uiStore.WIN.value.action === BangupActionConsts.BANGUP) {\n            duration = 0.01;\n        }\n        this.winValueTween = this.createMoneyTween(\n            { money: this.rootStore.uiStore.WIN.prevValue.amount },\n            winAmount,\n            this.rootStore.uiStore.WIN.prevValue.amount,\n            duration,\n        );\n    }\n\n    protected updateMoneyValue(winAmount: number, prevValueAmount: number, winAmountInCents: number): void {\n        let newValue: number = prevValueAmount;\n        this.updateMoneyFields(newValue * Core.SELECTED_DENOMINATION.value);\n        this.winBangUpInterval = Timers.setInterval(() => {\n            const left = Number(winAmount) - newValue;\n            const step = Math.ceil(left / 10);\n            newValue = newValue + step;\n            if (winAmount <= newValue) {\n                Timers.clearInterval(this.winBangUpInterval);\n                this.onBangupComplete(winAmountInCents);\n                return;\n            }\n            this.updateMoneyFields(newValue * Core.SELECTED_DENOMINATION.value);\n        }, 150);\n    }\n\n    private createMoneyTween(currentWin: any, winAmount: number, startValue: number, duration?: number): any {\n        if (winAmount === undefined) {\n            return;\n        }\n\n        if (currentWin.money > winAmount) {\n            const hasExtraFreeSpinComponent: boolean = (\n                Core.getGameFeatures().find((feature) => {\n                    return feature.configurationName === 'BaseFreeSpinsFeature';\n                }) as BaseFreeSpinsFeature\n            )?.hasExtraFreeSpinComponent;\n\n            if (!hasExtraFreeSpinComponent) {\n                Core.sounds.play('collectSound');\n            } else {\n                const freespinRound = this.rootStore.domainStore.betResponse?.rounds?.filter(\n                    (round) => round.type === 'FREESPIN',\n                )[0];\n                const isInFreeSpins: boolean =\n                    freespinRound?.remain > 0 && freespinRound.count !== freespinRound.remain;\n\n                if (!isInFreeSpins) {\n                    Core.sounds.play('collectSound');\n                }\n            }\n        }\n\n        if (!startValue) {\n            startValue = 0;\n        }\n\n        if (!duration) {\n            duration = this.getBangupDuration(Math.abs(winAmount - (startValue || 0)));\n        }\n\n        return (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/ui-main-panel/src/egt/modes/default/views/UIMainPanelViewDefault.ts:1161:16\",null]), gsap.to(currentWin, {\n            duration,\n            money: winAmount,\n            ease: 'none',\n            snap: {\n                money: Core.SELECTED_DENOMINATION.value,\n            },\n            onUpdate: () => {\n                this.updateMoneyFields(currentWin.money);\n            },\n            onComplete: () => {\n                this.onBangupComplete(winAmount);\n            },\n        }));\n    }\n\n    // show win / last win. LAST WIN only if is not ine feature (mode is auto / manual) and state is waiting\n    private setWinLastWinLabel(): void {\n        const win = this.rootStore.uiStore.WIN.value.amount;\n        if (\n            [Features.MANUAL_SPIN, Features.AUTO_PLAY].indexOf(this.rootStore.domainStore.SPIN_MODE.value as Features) >\n            -1\n        ) {\n            if (\n                [\n                    UIState.WAITING_FOR_RESPONSE,\n                    UIState.WAITING_FOR_RESPONSE_IN_AUTOPLAY,\n                    UIState.BONUS_IDLE,\n                    UIState.IDLE,\n                    // UIState.RESPIN,\n                ].indexOf(this.rootStore.uiStore.STATE.value as UIState) > -1 ||\n                (this.rootStore.uiStore.STATE.value === UIState.IDLE && this.settings.bonusSummary) // in case of GS finished and showing only complete popup at load game\n            ) {\n                if (win > 0) {\n                    this.rootStore.uiStore.WIN.prevValue.amount = this.rootStore.uiStore.WIN.value.amount;\n                    this.rootStore.uiStore.WIN.value.amount = 0;\n                    this.rootStore.uiStore.turboModeLastWin = this.rootStore.uiStore.fastSpinMode\n                        ? this.rootStore.uiStore.WIN.prevValue.amount\n                        : 0;\n                    this.winContainer.labelText.text = Core.translator.translate('LAST WIN');\n                    this.priorGambleWin = this.rootStore.uiStore.WIN.prevValue.amount; // Setting the prior win\n                } else if (win === undefined) {\n                    this.priorGambleWin = 0;\n                }\n            } else {\n                if (this.rootStore.uiStore.SHOW_SETTINGS.value) {\n                    this.winContainer.labelText.text = Core.translator.translate('WIN');\n                }\n            }\n        }\n    }\n\n    private onSoundMuted(): void {\n        this.soundButton.selected = Core.sounds.ON_SOUND_MUTED.value;\n    }\n\n    private setProperties(val): void {\n        const found = this.elements.get(val.name);\n        if (found) {\n            if (Array.isArray(val.actions)) {\n                let i = 0;\n                val.actions.forEach((action) => {\n                    found[action] =\n                        val.values[i] !== undefined\n                            ? val.values[i]\n                            : Array.isArray(val.values)\n                              ? val.values[0]\n                              : val.values;\n                    i++;\n                });\n            } else {\n                found[val.actions] = val.values;\n            }\n        }\n    }\n}\n","import {\n    AddPriority,\n    AssetPriority,\n    AssetsCollection,\n    BaseComponentConfiguration,\n    DefaultAssets,\n    DefaultValue,\n    DynamicPositionObject,\n} from '@egt/core';\nimport { FooterBackgroundModes } from '@egt/footer-background';\nimport { SlotComponents } from '@egt/slot';\nimport { TextStyle } from 'pixi.js';\nimport {\n    IButtonPropsSided,\n    IMoneyFieldSided,\n    IUIMainPanelComponentConfigurationSided,\n} from '../interfaces/IUIMainPanelComponentConfigurationSided';\n\nexport default class UIMainPanelComponentConfigurationSided extends BaseComponentConfiguration {}\nexport function UIMainPanelComponentConfigurationFactorySided(): any {\n    class UIMainPanelComponentConfigurationSidedInternalClass\n        extends UIMainPanelComponentConfigurationSided\n        implements IUIMainPanelComponentConfigurationSided\n    {\n        public mainPanelHeight: number = 214;\n        public mainPanelWidth: number = 1360;\n        public winAndBalanceFieldsWidthBuffer = 10;\n\n        @DefaultAssets([\n            {\n                id: 'svgFullscreenExit',\n                url: '../assets/components/slot/ui-main-panel/sided/ui-svg/exitFullscreen.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 65, height: 65 },\n                    desktop: { width: 50, height: 50 },\n                },\n            },\n            {\n                id: 'svgFullscreen',\n                url: '../assets/components/slot/ui-main-panel/sided/ui-svg/fullscreen.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 65, height: 65 },\n                    desktop: { width: 50, height: 50 },\n                },\n            },\n            {\n                id: 'svgHelp',\n                url: '../assets/components/slot/ui-main-panel/sided/ui-svg/help.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 65, height: 65 },\n                    desktop: { width: 60, height: 60 },\n                },\n            },\n            {\n                id: 'svgInfo',\n                url: '../assets/components/slot/ui-main-panel/sided/ui-svg/info.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 65, height: 65 },\n                    desktop: { width: 60, height: 60 },\n                },\n            },\n            {\n                id: 'svgSettings',\n                url: '../assets/components/slot/ui-main-panel/sided/ui-svg/settings.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 65, height: 65 },\n                    desktop: { width: 60, height: 60 },\n                },\n            },\n            {\n                id: 'svgSettingsClose',\n                url: '../assets/components/slot/ui-main-panel/sided/ui-svg/settingsClose.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 65, height: 65 },\n                    desktop: { width: 60, height: 60 },\n                },\n            },\n            {\n                id: 'svgSound',\n                url: '../assets/components/slot/ui-main-panel/sided/ui-svg/speak.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 65, height: 65 },\n                    desktop: { width: 60, height: 60 },\n                },\n            },\n            {\n                id: 'svgSoundOff',\n                url: '../assets/components/slot/ui-main-panel/sided/ui-svg/speakOff.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 65, height: 65 },\n                    desktop: { width: 60, height: 60 },\n                },\n            },\n        ])\n        public assets: AssetsCollection;\n\n        @AddPriority<IButtonPropsSided>([\n            {\n                priorityType: { feature: SlotComponents.BACKGROUND_SOUND },\n                priority: 2,\n                value: {\n                    desktop: { x: 975, y: 747 },\n                },\n            },\n            {\n                priorityType: { feature: SlotComponents.FOOTER_BACKGROUND, mode: FooterBackgroundModes.BLURRED },\n                priority: 4,\n                value: {\n                    landscape: { x: 130, y: 732 },\n                    portrait: { x: 130, y: 1304 },\n                    desktop: { x: 130, y: 732 },\n                },\n            },\n        ])\n        @DefaultValue<IButtonPropsSided>({\n            defaults: { x: 74, y: 617, scale: 1, visible: true, textures: ['svgInfo'] },\n            portrait: { x: 114, y: 1273 },\n            desktop: { x: 1043, y: 747 },\n        })\n        public paytableButtonPosition: DynamicPositionObject<IButtonPropsSided> & IButtonPropsSided;\n\n        @AddPriority<IButtonPropsSided>([\n            {\n                priorityType: { feature: SlotComponents.FOOTER_BACKGROUND, mode: FooterBackgroundModes.BLURRED },\n                priority: 3,\n                value: {\n                    landscape: { x: 0, y: 0, visible: false },\n                    portrait: { x: 0, y: 0, visible: false },\n                    desktop: { x: 1252, y: 732, visible: true },\n                },\n            },\n        ])\n        @DefaultValue<IButtonPropsSided>({\n            defaults: { x: 0, y: 0, scale: 1, visible: false, textures: ['svgFullscreenExit', 'svgFullscreen'] },\n            desktop: { x: 1240, y: 747, visible: true },\n        })\n        public fullScreenButton: DynamicPositionObject<IButtonPropsSided> & IButtonPropsSided;\n\n        @AddPriority<IButtonPropsSided>([\n            {\n                priorityType: { feature: SlotComponents.BACKGROUND_SOUND },\n                priority: 2,\n                value: {\n                    landscape: { x: 1322 },\n                },\n            },\n            {\n                priorityType: { feature: SlotComponents.FOOTER_BACKGROUND, mode: FooterBackgroundModes.BLURRED },\n                priority: 4,\n                value: {\n                    landscape: { x: 1230, y: 732, visible: true },\n                    portrait: { x: 635, y: 1304, visible: true },\n                    desktop: { x: 1180, y: 732, visible: true },\n                },\n            },\n        ])\n        @DefaultValue<IButtonPropsSided>({\n            defaults: { x: 1287, y: 617, scale: 1, visible: true, textures: ['svgSoundOff', 'svgSound'] },\n            portrait: { x: 636, y: 1272 },\n            desktop: { x: 1172, y: 747 },\n        })\n        public soundButton: DynamicPositionObject<IButtonPropsSided> & IButtonPropsSided;\n\n        @AddPriority<IButtonPropsSided>([\n            {\n                priorityType: { feature: SlotComponents.BACKGROUND_SOUND },\n                priority: 2,\n                value: {\n                    desktop: { x: 1040 },\n                },\n            },\n            {\n                priorityType: { feature: SlotComponents.FOOTER_BACKGROUND, mode: FooterBackgroundModes.BLURRED },\n                priority: 4,\n                value: {\n                    landscape: { x: 224, y: 732, visible: true },\n                    portrait: { x: 224, y: 1304, visible: true },\n                    desktop: { x: 224, y: 732, visible: true },\n                },\n            },\n        ])\n        @DefaultValue<IButtonPropsSided>({\n            defaults: { x: 0, y: 0, visible: false, scale: 1, textures: ['svgHelp'] },\n            desktop: { x: 1108, y: 747, visible: true },\n        })\n        public helpButton: DynamicPositionObject<IButtonPropsSided> & IButtonPropsSided;\n\n        @AddPriority<IButtonPropsSided>([\n            {\n                priorityType: { feature: SlotComponents.FOOTER_BACKGROUND, mode: FooterBackgroundModes.BLURRED },\n                priority: 3,\n                value: {\n                    landscape: { x: 1324, y: 732 },\n                    portrait: { x: 729, y: 1304 },\n                    desktop: { x: 1324, y: 732 },\n                },\n            },\n        ])\n        @DefaultValue<IButtonPropsSided>({\n            defaults: { x: 1286, y: 699, visible: true, scale: 1, textures: ['svgSettingsClose', 'svgSettings'] },\n            portrait: { x: 719, y: 1272 },\n            desktop: { x: 1308, y: 747, textures: ['svgSettings', 'svgSettings'] },\n        })\n        public settingsButtonProps: DynamicPositionObject<IButtonPropsSided> & IButtonPropsSided;\n\n        @DefaultValue<IMoneyFieldSided>({\n            defaults: {\n                x: 152,\n                y: 673,\n                width: 171,\n                height: 80,\n                currencyWidth: 171,\n                currencyHeight: 15,\n                currencyLineOffset: 0,\n                currencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fontSize: 22,\n                    fill: '#C6C5C5',\n                }),\n                moneyWidth: 171,\n                moneyHeight: 16,\n                moneyLineOffset: 0,\n                moneyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    fontSize: 30,\n                    fill: '#FFD200',\n                }),\n                moneyTint: 0xffd200,\n\n                creditsWidth: 171,\n                creditsHeight: 28,\n                creditsLineOffset: 11,\n                creditsStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fontSize: 48,\n                    fill: '#FFFFFF',\n                }),\n\n                labelWidth: 171,\n                labelHeight: 20,\n                labelStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fontSize: 30,\n                    padding: 5,\n                    fill: '#FFD200',\n                }),\n                labelLineOffset: 37,\n            },\n            portrait: {\n                x: 10,\n                y: 721,\n                width: 201,\n                height: 90,\n                currencyLineOffset: 0,\n                currencyWidth: 201,\n                currencyHeight: 15,\n                currencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fontSize: 22,\n                    fill: '#C6C5C5',\n                }),\n                moneyWidth: 201,\n                moneyHeight: 19,\n                creditsWidth: 201,\n                creditsHeight: 34,\n                creditsLineOffset: 9,\n                labelWidth: 201,\n                labelHeight: 22,\n                labelLineOffset: 41,\n                labelStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fontSize: 33,\n                    padding: 5,\n                    fill: '#FFD200',\n                }),\n            },\n            landscape: {\n                width: 171,\n                currencyWidth: 171,\n                creditsWidth: 171,\n                creditsHeight: 30,\n                moneyWidth: 171,\n                labelWidth: 171,\n            },\n            desktop: {\n                width: 171,\n                currencyWidth: 171,\n                creditsWidth: 171,\n                creditsHeight: 30,\n                moneyWidth: 171,\n                labelWidth: 171,\n            },\n        })\n        public balanceContainerProperties: DynamicPositionObject<IMoneyFieldSided> & IMoneyFieldSided;\n\n        @DefaultValue<IMoneyFieldSided>({\n            defaults: {\n                x: 1036,\n                y: 673,\n                width: 171,\n                height: 80,\n                currencyWidth: 171,\n                currencyHeight: 15,\n                currencyLineOffset: 0,\n                currencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fontSize: 22,\n                    fill: '#C6C5C5',\n                }),\n                moneyWidth: 171,\n                moneyHeight: 16,\n                moneyLineOffset: 0,\n                moneyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    fontSize: 30,\n                    fill: '#FFD200',\n                }),\n                moneyTint: 0xffd200,\n\n                creditsWidth: 171,\n                creditsHeight: 28,\n                creditsLineOffset: 11,\n                creditsStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fontSize: 48,\n                    fill: '#FFFFFF',\n                }),\n\n                labelWidth: 171,\n                labelHeight: 20,\n                labelStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fontSize: 30,\n                    padding: 5,\n                    fill: '#FFD200',\n                }),\n                labelLineOffset: 37,\n            },\n            portrait: {\n                x: 554,\n                y: 721,\n                width: 201,\n                height: 90,\n                currencyLineOffset: 0,\n                currencyWidth: 201,\n                currencyHeight: 15,\n                currencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fontSize: 22,\n                    fill: '#C6C5C5',\n                }),\n                moneyWidth: 201,\n                moneyHeight: 19,\n                creditsWidth: 201,\n                creditsHeight: 34,\n                creditsLineOffset: 9,\n                labelWidth: 201,\n                labelHeight: 22,\n                labelLineOffset: 41,\n                labelStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fontSize: 33,\n                    padding: 5,\n                    fill: '#FFD200',\n                }),\n            },\n            landscape: {\n                width: 171,\n                currencyWidth: 171,\n                creditsWidth: 171,\n                creditsHeight: 30,\n                moneyWidth: 171,\n                labelWidth: 171,\n            },\n            desktop: {\n                width: 171,\n                currencyWidth: 171,\n                creditsWidth: 171,\n                creditsHeight: 30,\n                moneyWidth: 171,\n                labelWidth: 171,\n            },\n        })\n        public winContainerProperties: DynamicPositionObject<IMoneyFieldSided> & IMoneyFieldSided;\n    }\n    return UIMainPanelComponentConfigurationSidedInternalClass;\n}\n","import Core, { BaseComponent, IModeConfig, Log } from '@egt/core';\nimport { InitialSettings, RootStore, SlotComponents, ZOrders } from '@egt/slot';\nimport { Lifecycle } from 'tsyringe';\nimport { IUIView } from './IUIView';\nimport { UIViewComponentConfigurationFactoryDefault } from './modes/default/configuration/UIViewComponentConfigurationDefault';\nimport UIAutoPlayController from './modes/default/controllers/UIViewAutoPlayControllerDefault';\nimport UIManualController from './modes/default/controllers/UIViewManualControllerDefault';\nimport { UIViewComponentConfigurationFactoryTurtle } from './modes/turtle/configuration/UIViewComponentConfigurationTurtle';\nimport UIViewModesConfigurations, { UIViewModes } from './UIViewFactory';\n\nexport default class UIViewComponent extends BaseComponent {\n    public static configurationName = 'UIViewComponent';\n\n    public uiView: IUIView;\n    public uiManualController: UIManualController;\n    public uiAutoController: UIAutoPlayController;\n    public componentType = SlotComponents.UI_VIEW;\n    public configuration: any;\n    public rootView;\n\n    constructor(modeConfig: IModeConfig) {\n        super();\n        const baseConfigs = {\n            [UIViewModes.DEFAULT]: UIViewComponentConfigurationFactoryDefault,\n            [UIViewModes.TURTLE]: UIViewComponentConfigurationFactoryTurtle,\n        };\n\n        this.modeFactory = this.initMode<UIViewModesConfigurations>(modeConfig, {\n            defaultModeType: UIViewModes.DEFAULT,\n            baseConfigs,\n            defaultFactory: UIViewModesConfigurations,\n        });\n    }\n\n    public destroy(): void {\n        this.uiManualController.destroy();\n        // @ts-ignore\n        this.uiManualController = null;\n\n        this.uiAutoController.destroy();\n        // @ts-ignore\n        this.uiAutoController = null;\n\n        this.configuration.destroy();\n        // @ts-ignore\n        this.configuration = null;\n        // @ts-ignore\n        this.rootView = null;\n        // @ts-ignore\n        this.uiView = null;\n\n        // @ts-ignore\n        this.config = null;\n\n        super.destroy();\n    }\n\n    public onAfterGameConfigurationCreated(): void {\n        super.onAfterGameConfigurationCreated();\n        // const slotConfig: ISlotConfiguration = this.dependencyContainer.resolve('ISlotConfiguration');\n        this.configuration = this.dependencyContainer.resolve('UIViewComponentConfiguration');\n        const rootStore: RootStore = this.dependencyContainer.resolve('RootStore');\n        const settings: InitialSettings = this.dependencyContainer.resolve('InitialSettings');\n        // if (slotConfig.componentsConfiguration.hasOwnProperty(UIViewComponent.configurationName)) {\n        //     Object.keys(slotConfig.componentsConfiguration[UIViewComponent.configurationName]).forEach(key => {\n        //         config[key] = slotConfig.componentsConfiguration[UIViewComponent.configurationName][key];\n        //     });\n        // }\n\n        if (settings.minimumSpinTime > 0) {\n            rootStore.subjects.REELS_MINIMUM_SPIN_TIME.next(settings.minimumSpinTime);\n            const allReelsDelay =\n                settings.minimumSpinTime -\n                rootStore.subjects.NUMBER_OF_REELS.value * rootStore.subjects.GAME_BETWEEN_REELS_DELAY.value;\n            const reelExtraDelay =\n                ((allReelsDelay / rootStore.subjects.NUMBER_OF_REELS.value) *\n                    rootStore.subjects.MIN_TIME_REELS_PERCENT_DELAY.value) /\n                100;\n\n            rootStore.subjects.GAME_BETWEEN_REELS_DELAY.next(\n                rootStore.subjects.GAME_BETWEEN_REELS_DELAY.value + reelExtraDelay,\n            );\n        }\n    }\n\n    public onRegisterDependencies(container: any): void {\n        super.onRegisterDependencies(container);\n        // if (!this.dependencyContainer.isRegistered('UIView')) {\n        this.dependencyContainer.register('UIView', { useClass: this.mode.view }, { lifecycle: Lifecycle.Singleton });\n        // }\n\n        if (!this.dependencyContainer.isRegistered('UIManualController')) {\n            this.dependencyContainer.register(\n                'UIManualController',\n                { useClass: this.mode.controller },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n\n        if (!this.dependencyContainer.isRegistered('UIAutoPlayController')) {\n            this.dependencyContainer.register(\n                'UIAutoPlayController',\n                { useClass: this.mode.secondController },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n\n        this.dependencyContainer.register(\n            'UIViewComponentConfiguration',\n            { useClass: this.mode.configuration },\n            { lifecycle: Lifecycle.Singleton },\n        );\n    }\n\n    public onRegisterDesktopDependencies(container: any): void {\n        super.onRegisterDesktopDependencies(container);\n        // the common phase always registers this.mode.controller, so a desktop-specific\n        // controller must override it instead of being guarded by isRegistered\n        if (this.mode.desktopController) {\n            this.dependencyContainer.register(\n                'UIManualController',\n                { useClass: this.mode.desktopController },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n    }\n\n    // public onRegisterMobileDependencies(container: any): void {\n    //     super.onRegisterMobileDependencies(container);\n    //     if (!this.dependencyContainer.isRegistered('UIManualController')) {\n    //         this.dependencyContainer.register(\n    //             'UIManualController',\n    //             { useClass: this.mode.controller },\n    //             { lifecycle: Lifecycle.Singleton },\n    //         );\n    //     }\n    // }\n\n    public onPrepareResources(_container: any): void {\n        // if (this.modeConfig.modeType !== UIViewModes.TURTLE) {\n        const settings: InitialSettings = this.dependencyContainer.resolve('InitialSettings');\n        if (settings.minimumSpinTime <= 0) {\n            this.configuration.assets.remove(['progressSpinTime']);\n        }\n        Core.assets.addAssets(this.configuration?.assets?.toArray() || []);\n        // }\n    }\n\n    public onResolveDependencies(container: any): void {\n        super.onResolveDependencies(container);\n\n        this.rootView = this.dependencyContainer.resolve('RootView');\n        this.uiView = this.dependencyContainer.resolve('UIView');\n        this.uiManualController = this.dependencyContainer.resolve('UIManualController');\n        this.uiAutoController = this.dependencyContainer.resolve('UIAutoPlayController');\n        this.uiView.zIndex = ZOrders.SPIN_BUTTONS_LEVEL;\n        this.rootView.addChild(this.uiView);\n\n        if (Core?.devTools) {\n            const scalerInstance = this.dependencyContainer.resolve('CustomScaler');\n            switch (this.modeFactory.modeType) {\n                case UIViewModes.TURTLE:\n                    import('./modes/turtle/configuration/UIViewScalerConfigInitializer')\n                        .then((initializerImport) => initializerImport.default(scalerInstance))\n                        .catch((err) => Log.debug('error loading scaler config file: ', err));\n                    break;\n                default:\n                    import('./modes/default/configuration/UIViewScalerConfigInitializer')\n                        .then((initializerImport) => initializerImport.default(scalerInstance))\n                        .catch((err) => Log.debug('error loading scaler config file: ', err));\n                    break;\n            }\n        }\n    }\n}\n","import { BaseModesConfigurations, IForceSetConfig, IModes } from '@egt/core';\nimport UIViewDefault from './modes/default/views/UIViewDefault';\nimport UIViewManualControllerDefault from './modes/default/controllers/UIViewManualControllerDefault';\nimport UIViewTurtle from './modes/turtle/views/UIViewTurtle';\nimport { UIViewComponentConfigurationFactoryTurtle } from './modes/turtle/configuration/UIViewComponentConfigurationTurtle';\nimport UIViewAutoPlayControllerDefault from './modes/default/controllers/UIViewAutoPlayControllerDefault';\nimport UIViewManualControllerTurtle from './modes/turtle/controllers/UIViewManualControllerTurtle';\nimport UIViewAutoPlayControllerTurtle from './modes/turtle/controllers/UIViewAutoPlayControllerTurtle';\nimport { UIViewComponentConfigurationFactoryDefault } from './modes/default/configuration/UIViewComponentConfigurationDefault';\n\nexport default class UIViewModesConfigurations extends BaseModesConfigurations<UIViewModes> {\n    constructor(modeType: UIViewModes, forceSetConfig?: IForceSetConfig) {\n        super(modeType, forceSetConfig);\n    }\n\n    protected createBaseModesConfig(modeType: UIViewModes): IModes {\n        switch (modeType) {\n            case UIViewModes.TURTLE:\n                return {\n                    controller: UIViewManualControllerTurtle,\n                    secondController: UIViewAutoPlayControllerTurtle,\n                    view: UIViewTurtle,\n                    configuration: UIViewComponentConfigurationFactoryTurtle(),\n                };\n            default:\n                return {\n                    controller: UIViewManualControllerDefault,\n                    secondController: UIViewAutoPlayControllerDefault,\n                    view: UIViewDefault,\n                    configuration: UIViewComponentConfigurationFactoryDefault(),\n                };\n        }\n    }\n}\n\nexport enum UIViewModes {\n    DEFAULT = 'default',\n    TURTLE = 'turtle',\n}\n","import { IButtonInterface } from '@egt/gamble';\nimport { IUIViewComponentConfigurationDefault } from './modes/default/configuration/IUIViewComponentConfigurationDefault';\nimport UIAutoPlayController from './modes/default/controllers/UIViewAutoPlayControllerDefault';\nimport UIManualController from './modes/default/controllers/UIViewManualControllerDefault';\nimport {\n    IButtonInterfaceDefault,\n    IButtonInterfaceSpecialDefault,\n} from './modes/default/interfaces/IButtonInterfaceDefault';\nimport { IDenominationTextInterfaceDefault } from './modes/default/interfaces/IDenominationTextInterfaceDefault';\nimport { IRopeTextInterfaceDefault } from './modes/default/interfaces/IRopeTextInterfaceDefault';\nimport { ISpinBtnBonusTextInterfaceDefault } from './modes/default/interfaces/ISpinBtnBonusTextInterfaceDefault';\nimport { ITextInterfaceDefault } from './modes/default/interfaces/ITextInterfaceDefault';\nimport UIViewDefault from './modes/default/views/UIViewDefault';\nimport UIViewComponent from './UIViewComponent';\nimport UIViewModesConfigurations, { UIViewModes } from './UIViewFactory';\nimport UIViewComponentConfigurationDefault from './modes/default/configuration/UIViewComponentConfigurationDefault';\nimport { ITextInterfaceTurtle } from './modes/turtle/interfaces/ITextInterfaceTurtle';\nimport UIViewComponentConfigurationTurtle from './modes/turtle/configuration/UIViewComponentConfigurationTurtle';\nimport {\n    IButtonInterfaceSpecialTurtle,\n    IButtonInterfaceTurtle,\n} from './modes/turtle/interfaces/IButtonInterfaceTurtle';\nimport { IRopeTextInterfaceTurtle } from './modes/turtle/interfaces/IRopeTextInterfaceTurtle';\nimport { IBetUiGuardsConfigurationTurtle } from './modes/turtle/interfaces/IBetUiGuardsConfigurationTurtle';\nimport CascadeUIViewTurtle from './modes/turtle/views/CascadeUIViewTurtle';\nimport UIViewManualControllerTurtle from './modes/turtle/controllers/UIViewManualControllerTurtle';\nimport UIViewAutoPlayControllerTurtle from './modes/turtle/controllers/UIViewAutoPlayControllerTurtle';\nimport { IUIViewComponentConfigurationTurtle } from './modes/turtle/configuration/IUIViewComponentConfigurationTurtle';\nimport UIViewTurtle from './modes/turtle/views/UIViewTurtle';\nimport { IMoveUIViewButtonsInFreeSpinsTurtle } from './modes/turtle/interfaces/IMoveSpinButtonInFreeSpinsTurtle';\n\nexport {\n    UIManualController,\n    UIViewDefault,\n    CascadeUIViewTurtle,\n    IUIViewComponentConfigurationDefault,\n    UIViewComponentConfigurationDefault,\n    UIAutoPlayController,\n    IRopeTextInterfaceDefault,\n    ITextInterfaceDefault,\n    IDenominationTextInterfaceDefault,\n    IButtonInterface,\n    IButtonInterfaceSpecialDefault,\n    ISpinBtnBonusTextInterfaceDefault,\n    UIViewModes,\n    UIViewModesConfigurations,\n    IButtonInterfaceDefault,\n    UIViewComponentConfigurationTurtle,\n    IButtonInterfaceSpecialTurtle,\n    IButtonInterfaceTurtle,\n    IRopeTextInterfaceTurtle,\n    ITextInterfaceTurtle,\n    IBetUiGuardsConfigurationTurtle,\n    IMoveUIViewButtonsInFreeSpinsTurtle,\n    UIViewManualControllerTurtle,\n    IUIViewComponentConfigurationTurtle,\n    UIViewTurtle,\n    UIViewAutoPlayControllerTurtle,\n};\nexport default UIViewComponent;\n","import {\n    AssetPriority,\n    AssetsCollection,\n    BaseComponentConfiguration,\n    DefaultAssets,\n    DefaultValue,\n    DynamicPositionObject,\n    IPositionPoint,\n} from '@egt/core';\nimport { TextStyle } from 'pixi.js';\nimport { IButtonInterfaceDefault, IButtonInterfaceSpecialDefault } from '../interfaces/IButtonInterfaceDefault';\nimport { IDenominationTextInterfaceDefault } from '../interfaces/IDenominationTextInterfaceDefault';\nimport { IRopeTextInterfaceDefault } from '../interfaces/IRopeTextInterfaceDefault';\nimport { ISpinBtnBonusTextInterfaceDefault } from '../interfaces/ISpinBtnBonusTextInterfaceDefault';\nimport { ITextInterfaceDefault } from '../interfaces/ITextInterfaceDefault';\nimport { IUIViewComponentConfigurationDefault } from './IUIViewComponentConfigurationDefault';\n\nexport default class UIViewComponentConfigurationDefault extends BaseComponentConfiguration {}\n\nexport function UIViewComponentConfigurationFactoryDefault(\n    ClassType: typeof UIViewComponentConfigurationDefault = UIViewComponentConfigurationDefault,\n): typeof UIViewComponentConfigurationDefault {\n    class InternalUIViewComponentConfigurationDefault\n        extends ClassType\n        implements IUIViewComponentConfigurationDefault\n    {\n        public x: number = 0;\n        public y: number = 0;\n\n        @DefaultAssets([\n            {\n                id: 'svgAutoPlay',\n                url: '../assets/components/slot/ui-view/default/ui-svg/autoplayButton.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 132, height: 132 },\n                    desktop: { width: 99, height: 99 },\n                },\n            },\n            {\n                id: 'svgAutoPlayInactive',\n                url: '../assets/components/slot/ui-view/default/ui-svg/autoplayButtonDisabled.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 132, height: 132 },\n                    desktop: { width: 99, height: 99 },\n                },\n            },\n            {\n                id: 'svgAutoPlayStop',\n                url: '../assets/components/slot/ui-view/default/ui-svg/autoplayStopButton.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 219, height: 219 },\n                    desktop: { width: 150, height: 150 },\n                },\n            },\n            {\n                id: 'svgChooseBet',\n                url: '../assets/components/slot/ui-view/default/ui-svg/chooseBetButton.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 132, height: 132 },\n                    desktop: { width: 99, height: 99 },\n                },\n            },\n            {\n                id: 'svgChooseBetInactive',\n                url: '../assets/components/slot/ui-view/default/ui-svg/chooseBetButtonDisabled.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 132, height: 132 },\n                    desktop: { width: 99, height: 99 },\n                },\n            },\n            {\n                id: 'svgCollectSmall',\n                url: '../assets/components/slot/ui-view/default/ui-svg/collectSmallButton.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 132, height: 132 },\n                    desktop: { width: 99, height: 99 },\n                },\n            },\n            {\n                id: 'svgCollectSmallDisabled',\n                url: '../assets/components/slot/ui-view/default/ui-svg/collectSmallButtonDisabled.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 132, height: 132 },\n                    desktop: { width: 99, height: 99 },\n                },\n            },\n            {\n                id: 'svgDisabledSpeed',\n                url: '../assets/components/slot/ui-view/default/ui-svg/speedButtonDisabled.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 132, height: 64 },\n                    desktop: { width: 99, height: 48 },\n                },\n            },\n            {\n                id: 'svgNormalSpeed',\n                url: '../assets/components/slot/ui-view/default/ui-svg/normalSpeedButton.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 132, height: 64 },\n                    desktop: { width: 99, height: 48 },\n                },\n            },\n            {\n                id: 'svgQuickSpeed',\n                url: '../assets/components/slot/ui-view/default/ui-svg/quickSpeedButton.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 132, height: 64 },\n                    desktop: { width: 99, height: 48 },\n                },\n            },\n            {\n                id: 'svgTurboSpeed',\n                url: '../assets/components/slot/ui-view/default/ui-svg/turboSpeedButton.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 132, height: 64 },\n                    desktop: { width: 99, height: 48 },\n                },\n            },\n            {\n                id: 'svgSpin',\n                url: '../assets/components/slot/ui-view/default/ui-svg/spinButton.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 219, height: 219 },\n                    desktop: { width: 150, height: 150 },\n                },\n            },\n            {\n                id: 'svgSpinDisabled',\n                url: '../assets/components/slot/ui-view/default/ui-svg/spinButtonDisabled.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 219, height: 219 },\n                    desktop: { width: 150, height: 150 },\n                },\n            },\n            {\n                id: 'svgSpinSkipAnimation',\n                url: '../assets/components/slot/ui-view/default/ui-svg/spinSkipAnimationButton.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 219, height: 219 },\n                    desktop: { width: 150, height: 150 },\n                },\n            },\n            {\n                id: 'svgAutoPlayInfinity',\n                url: '../assets/components/slot/ui-view/default/ui-svg/autoInfinityIcon.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 40, height: 21 },\n                    desktop: { width: 40, height: 21 },\n                },\n            },\n            {\n                id: 'progressSpinTime',\n                url: '../assets/commons/images/ui/spinSpeedIndicator/default/progressBarLoading.json',\n                priority: AssetPriority.HIGHEST,\n                type: 'spineAnimation',\n            },\n        ])\n        public assets: AssetsCollection;\n\n        @DefaultValue<IPositionPoint>({\n            defaults: {\n                x: 0,\n                y: 0, //1000\n                width: 90,\n                height: 30,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n                scale: 1,\n                visible: true,\n            },\n            landscape: { x: 0, y: 0, leftHandX: 0 }, //x: 1200, y:0, leftHandX: -10\n            desktop: { x: 0, y: 0 }, //x: 1215, y: 25\n        })\n        public uiViewPosition: DynamicPositionObject<IPositionPoint> & IPositionPoint;\n\n        @DefaultValue<IButtonInterfaceDefault>({\n            defaults: {\n                x: 187,\n                y: 1061,\n                width: 0,\n                height: 0,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n                scale: 1,\n                visible: true,\n                textures: ['svgAutoPlay', 'svgAutoPlay', 'svgAutoPlay', 'svgAutoPlayInactive'],\n            },\n            landscape: { x: 1285, y: 101, leftHandX: 75 },\n            desktop: { x: 1272.5, y: 198.5 },\n        })\n        public autoPlayButtonPosition: DynamicPositionObject<IButtonInterfaceDefault> & IButtonInterfaceDefault;\n\n        @DefaultValue<IButtonInterfaceDefault>({\n            defaults: {\n                x: 578,\n                y: 1061,\n                width: 0,\n                height: 0,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n                scale: 1,\n                visible: true,\n                textures: ['svgChooseBet', 'svgChooseBet', 'svgChooseBet', 'svgChooseBetInactive'],\n            },\n            landscape: { x: 1285, y: 502, leftHandX: 75 },\n            desktop: { x: 1272, y: 522 },\n        })\n        public denominationButtonPosition: DynamicPositionObject<IButtonInterfaceDefault> & IButtonInterfaceDefault;\n\n        @DefaultValue<IButtonInterfaceDefault>({\n            defaults: {\n                x: 578,\n                y: 1061,\n                width: 0,\n                height: 0,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n                scale: 1,\n                visible: true,\n                textures: ['svgCollectSmall', 'svgCollectSmall', 'svgCollectSmall', 'svgCollectSmallDisabled'],\n            },\n            landscape: { x: 1285, y: 502, leftHandX: 75 },\n            desktop: { x: 1272, y: 522 },\n        })\n        public collectSmallButtonPosition: DynamicPositionObject<IButtonInterfaceDefault> & IButtonInterfaceDefault;\n\n        @DefaultValue<IPositionPoint>({\n            defaults: {\n                x: 382.5,\n                y: 1190,\n                width: 0,\n                height: 0,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n                scale: 1,\n                visible: true,\n            },\n            landscape: { x: 1285, y: 396, leftHandX: 75 },\n            desktop: { x: 1272, y: 430 },\n        })\n        public spinSpeedButtonPosition: DynamicPositionObject<IPositionPoint> & IPositionPoint;\n\n        @DefaultValue<IPositionPoint>({\n            defaults: {\n                x: 382.5,\n                y: 1190,\n                width: 0,\n                height: 0,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n                scale: 1,\n                visible: true,\n            },\n            landscape: { x: 1270, y: 396, leftHandX: 75 },\n            desktop: { x: 1272, y: 430 },\n        })\n        public blitzPlayButtonPosition: DynamicPositionObject<IPositionPoint> & IPositionPoint;\n\n        @DefaultValue<IPositionPoint>({\n            defaults: {\n                x: 384.5,\n                y: 1191,\n                width: 0,\n                height: 0,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n                scale: 1,\n                visible: true,\n            },\n            landscape: { x: 1287, y: 397, leftHandX: 75 },\n            desktop: { x: 1273.5, y: 431, scale: 0.75 },\n        })\n        public minSpinTimeButtonPosition: DynamicPositionObject<IPositionPoint> & IPositionPoint;\n\n        @DefaultValue<IButtonInterfaceSpecialDefault>({\n            defaults: {\n                x: 382.5,\n                y: 1060.5,\n                width: 0,\n                height: 0,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n                scale: 1,\n                visible: true,\n                textures: ['svgSpin', 'svgSpinDisabled', 'svgSpin', 'svgSpinDisabled'],\n                useBackgroundTexture: false,\n                backgroundTexture: 'svgSpinButtonBackground',\n                texturesSpecial: [\n                    'svgSpinSpecial',\n                    'svgSpinDisabledSpecial',\n                    'svgSpinSpecial',\n                    'svgSpinDisabledSpecial',\n                ],\n                backgroundTextureSpecial: 'svgSpinButtonBackgroundSpecial',\n            },\n            landscape: { x: 1241.5, y: 277.5, leftHandX: 119 },\n            desktop: { x: 1272, y: 342 },\n        })\n        public spinButtonPosition: DynamicPositionObject<IButtonInterfaceSpecialDefault> &\n            IButtonInterfaceSpecialDefault;\n\n        @DefaultValue<IButtonInterfaceSpecialDefault>({\n            defaults: {\n                x: 382.5,\n                y: 1060.5,\n                width: 0,\n                height: 0,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n                scale: 1,\n                visible: true,\n                textures: ['svgAutoPlayStop'],\n                useBackgroundTexture: false,\n                backgroundTexture: 'svgSpinButtonBackground',\n                texturesSpecial: [\n                    'svgAutoPlayStopSpecial',\n                    'svgAutoPlayStopSpecial',\n                    'svgAutoPlayStopSpecial',\n                    'svgAutoPlayStopSpecial',\n                ],\n                backgroundTextureSpecial: 'svgSpinButtonBackgroundSpecial',\n            },\n            landscape: { x: 1241.5, y: 277.5, leftHandX: 119 },\n            desktop: { x: 1272, y: 342 },\n        })\n        public stopButtonPosition: DynamicPositionObject<IButtonInterfaceSpecialDefault> &\n            IButtonInterfaceSpecialDefault;\n\n        @DefaultValue<ITextInterfaceDefault>({\n            defaults: {\n                style: new TextStyle({\n                    fontSize: 19,\n                    padding: 5,\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fill: 'white',\n                }),\n                x: 22,\n                y: 46.5,\n                width: 90,\n                height: 30,\n                display: true,\n                alpha: 1,\n            },\n            desktop: {\n                style: new TextStyle({\n                    fontSize: 17,\n                    padding: 5,\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fill: 'white',\n                    lineHeight: 16,\n                }),\n                x: 18,\n                y: 33.5,\n                width: 66,\n                height: 22,\n            },\n        })\n        public spinSpeedTextProperties: DynamicPositionObject<ITextInterfaceDefault> & ITextInterfaceDefault;\n\n        @DefaultValue<ITextInterfaceDefault>({\n            defaults: {\n                style: new TextStyle({\n                    fontSize: 19,\n                    padding: 5,\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fill: '#999999',\n                }),\n                x: 22,\n                y: 46.5,\n                width: 90,\n                height: 30,\n                display: true,\n                alpha: 1,\n            },\n            desktop: {\n                style: new TextStyle({\n                    fontSize: 17,\n                    padding: 5,\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fill: '#999999',\n                    lineHeight: 16,\n                }),\n                x: 18,\n                y: 33.5,\n                width: 66,\n                height: 22,\n            },\n        })\n        public spinSpeedTextDisabledProperties: DynamicPositionObject<ITextInterfaceDefault> & ITextInterfaceDefault;\n\n        @DefaultValue<ITextInterfaceDefault>({\n            defaults: {\n                style: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    align: 'center',\n                    fontSize: 30,\n                    fill: 0x000000,\n                }),\n                x: 110,\n                y: 110,\n                width: 220,\n                height: 220,\n                display: true,\n                alpha: 1,\n            },\n            desktop: {\n                style: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    align: 'center',\n                    fontSize: 24,\n                    fill: 0x000000,\n                }),\n                x: 75,\n                y: 75,\n                width: 150,\n                height: 150,\n            },\n        })\n        public autoplayTextProperties: DynamicPositionObject<ITextInterfaceDefault> & ITextInterfaceDefault;\n\n        @DefaultValue<IRopeTextInterfaceDefault>({\n            defaults: {\n                style: new TextStyle({\n                    fontSize: 22,\n                    padding: 5,\n                    fill: '#FFFFFF',\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                }),\n                activeBuyBonusColor: '#FFFFFF',\n                x: 109,\n                y: 111,\n                radius: 90,\n                maxRopePoints: 1400,\n                resolution: 1,\n                visible: true,\n            },\n            desktop: {\n                style: new TextStyle({\n                    fontSize: 16,\n                    padding: 5,\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fill: '#FFFFFF',\n                }),\n                activeBuyBonusColor: '#FFFFFF',\n                x: 75,\n                y: 75,\n                radius: 62,\n                resolution: 1,\n                maxRopePoints: 1000,\n                visible: true,\n            },\n        })\n        public ropeTextProperties: DynamicPositionObject<IRopeTextInterfaceDefault> & IRopeTextInterfaceDefault;\n\n        @DefaultValue<ISpinBtnBonusTextInterfaceDefault>({\n            defaults: {\n                style: new TextStyle({\n                    fontSize: 30,\n                    fill: '#FFFFFF',\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    lineHeight: 30,\n                    align: 'center',\n                    wordWrap: true,\n                    wordWrapWidth: 130,\n                }),\n                x: 97,\n                y: 97,\n                display: true,\n            },\n        })\n        public spinBtnBonusTextStyle: DynamicPositionObject<ISpinBtnBonusTextInterfaceDefault> &\n            ISpinBtnBonusTextInterfaceDefault;\n\n        @DefaultValue<IDenominationTextInterfaceDefault>({\n            defaults: {\n                denominationTitleTextStyles: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fill: '#FFFFFF',\n                    fontSize: 19,\n                    align: 'center',\n                    lineHeight: 19,\n                }),\n                denominationTextStyles: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fill: '#FFD200',\n                    fontSize: 28,\n                    lineHeight: 31,\n                }),\n                textures: [],\n                denominationTitleTextFontOffset: 20,\n                denominationTextHorizontalOffset: -1,\n                denominationTextVerticalOffset: 0.5,\n                denominationTitleTextVerticalOffset: -1.5,\n                haveText: true,\n            },\n            desktop: {\n                denominationTitleTextStyles: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fill: '#FFFFFF',\n                    align: 'center',\n                    fontSize: 15,\n                    lineHeight: 16,\n                }),\n                denominationTextStyles: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fill: '#FFD200',\n                    fontSize: 25,\n                }),\n                denominationTitleTextFontOffset: 10,\n                denominationTitleTextVerticalOffset: -1,\n                denominationTextHorizontalOffset: -18.5,\n                denominationTextVerticalOffset: -24.5,\n            },\n        })\n        public denominationOptionProperties: DynamicPositionObject<IDenominationTextInterfaceDefault> &\n            IDenominationTextInterfaceDefault;\n    }\n    return InternalUIViewComponentConfigurationDefault;\n}\n","import Core, {\n    AnalyticsDispatcher,\n    BaseController,\n    ErrorTypes,\n    IErrorData,\n    Log,\n    PostMessageDispatcher,\n    Timers,\n} from '@egt/core';\nimport { SettingsTab } from '@egt/settings-popup';\nimport {\n    AnalyticsState,\n    BangupActionConsts,\n    BetResponse,\n    FeatureController,\n    Features,\n    ISlotConfiguration,\n    InitialSettings,\n    MessBarTypes,\n    RootStore,\n    SlotComponents,\n    UIState,\n} from '@egt/slot';\nimport { ButtonStates } from '@egt/ui-lib';\nimport { Subject } from 'rxjs';\nimport { filter, takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport UIViewDefault from '../views/UIViewDefault';\nimport { AutoplayPopupModes } from '@egt/autoplay-popup';\n\n@injectable()\nexport default class UIViewAutoPlayControllerDefault extends BaseController {\n    // biome-ignore lint/correctness/noUndeclaredVariables: <explanation>\n    protected timeoutId: gsap.core.Tween;\n    protected fastStopRequested: boolean = false;\n    private stopFromOutside: any;\n    protected reelsStopped: boolean = true;\n    protected waitingBeforeNexSpin: boolean = false;\n\n    private GREAT_WINFINISHED = new Subject();\n\n    constructor(\n        @inject('UIView') protected view: UIViewDefault,\n        @inject('ISlotConfiguration') protected config: ISlotConfiguration,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('FeatureController') protected featureController: FeatureController,\n    ) {\n        super(undefined);\n        this.stopFromOutside = this.stopAutoplayFromOutside.bind(this);\n        window.addEventListener('message', this.stopFromOutside);\n        this.attachEventListeners();\n    }\n\n    public destroy(): void {\n        window.removeEventListener('message', this.stopFromOutside);\n        // @ts-ignore\n        this.view = null;\n        if (this.rootStore) {\n            // @ts-ignore\n            this.rootStore = null;\n        }\n        if (this.featureController) {\n            // @ts-ignore\n            this.featureController = null;\n        }\n        if (this.config) {\n            // @ts-ignore\n            this.config = null;\n        }\n        if (this.stopFromOutside) {\n            this.stopFromOutside = null;\n        }\n        super.destroy();\n    }\n\n    protected onAutoPlayClicked(): void {\n        if (\n            !this.view.autoPlayButton.enabled &&\n            this.rootStore.uiStore.SELECTED_SETTINGS_TAB.value !== SettingsTab.AUTOPLAY\n        ) {\n            return;\n        }\n        this.rootStore.uiStore.CLEAR_BANG_UP.next();\n        if (\n            this.settings.autoplayRestrictions.mandatory.length === 0 ||\n            !Core.hasComponent(SlotComponents.AUTOPLAY_POPUP, AutoplayPopupModes.DEFAULT)\n        ) {\n            if (!this.settings.autoplayRestrictions.infinityByDefault) {\n                this.rootStore.subjects.TOGGLE_AUTOPLAY_POPUP.next();\n            } else {\n                this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.next(-1);\n                this.rootStore.subjects.CLOSE_AUTOPLAY_POPUP.next();\n                this.rootStore.subjects.START_AUTOPLAY.next(-1);\n            }\n        } else {\n            this.rootStore.uiStore.SELECTED_SETTINGS_TAB.next(SettingsTab.AUTOPLAY);\n            this.rootStore.subjects.OPEN_SETTINGS_POPUP.next();\n            Core.sounds.play('showDenominationsSound');\n        }\n        AnalyticsDispatcher.incrementUserAction('autoplayUsed');\n    }\n\n    protected attachEventListeners(): void {\n        this.view.autoPlayButton.CLICK.pipe(\n            filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n            takeUntil(this.DESTROY),\n        ).subscribe(this.onAutoPlayClicked.bind(this));\n\n        /*   this.view.autoPlayButton.VALUE_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe((e) => {\n            this.rootStore.subjects.GET_UI_VIEW_COMPONENT_STATE.next({\n                name: 'autoPlayButton',\n                property: e.property,\n                value: e.value,\n            });\n        }); */\n\n        this.view.stopButton.CLICK.pipe(\n            filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n            takeUntil(this.DESTROY),\n        ).subscribe(this.onStopClicked.bind(this));\n        this.rootStore.uiStore.COLLECT_CLICKED.chainSubscribe(Features.AUTO_PLAY, this.onCollectClicked.bind(this));\n        this.rootStore.subjects.REELS_STOPPED.chainSubscribe(Features.AUTO_PLAY, this.onReelsStopped.bind(this));\n        this.rootStore.subjects.REELS_STOPPED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.sendAnalyticsData.bind(this),\n        );\n        this.rootStore.subjects.START_AUTOPLAY.pipe(takeUntil(this.DESTROY)).subscribe(this.onAutoPlayStart.bind(this));\n        this.rootStore.subjects.REELS_STOP_ALL.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.fastStopRequested = true;\n        });\n        this.rootStore.subjects.STOP_AUTOPLAY.pipe(takeUntil(this.DESTROY)).subscribe(this.stopAutoplay.bind(this));\n        // this.rootStore.domainStore.BET.pipe(takeUntil(this.DESTROY)).subscribe(this.onBetResponse.bind(this));\n        this.rootStore.subjects.KEY_UP.pipe(takeUntil(this.DESTROY)).subscribe(this.onKeyReleased.bind(this));\n        Core.SHOW_ERROR.pipe(takeUntil(this.DESTROY)).subscribe(this.onShowError.bind(this));\n    }\n\n    protected onReelsStopped(): void {\n        this.reelsStopped = true;\n        const betResponse: BetResponse = this.rootStore.domainStore.betResponse;\n\n        const win = betResponse.bonusGamesTotalWinAmount || betResponse.totalWinAmount;\n        const bet = this.rootStore.getBetAmount();\n        this.rootStore.uiStore.WIN.next({\n            amount: win,\n            action: win > 0 ? BangupActionConsts.BANGUP : BangupActionConsts.SET,\n            feature: Features.AUTO_PLAY,\n        });\n\n        if (this.rootStore.uiStore.turboModeEnabled) {\n            this.rootStore.uiStore.WIN.prevValue.amount = win > 0 ? win : this.rootStore.uiStore.turboModeLastWin;\n        }\n        this.rootStore.uiStore.STATE.next(betResponse.state);\n\n        this.rootStore.uiStore.BALANCE.next(betResponse.balance);\n\n        if (bet > win) {\n            this.rootStore.uiStore.currentTotalLoss += bet - win;\n        }\n\n        this.autoplay();\n\n        this.handleUiStateTransition();\n    }\n\n    protected handleUiStateTransition(): void {\n        if (\n            this.rootStore.domainStore.SPIN_MODE.value === Features.MANUAL_SPIN &&\n            this.rootStore.domainStore.SPIN_MODE.prevValue === Features.MANUAL_SPIN &&\n            this.rootStore.uiStore.STATE.value === UIState.WIN\n        ) {\n            this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_COLLECT);\n        }\n    }\n\n    protected sendAnalyticsData(): void {\n        if (this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value !== 0) {\n            AnalyticsDispatcher.reelsStoppedAnalyticsEvent(\n                Core.configuration.gameKey,\n                AnalyticsState[this.rootStore.domainStore.SERVER_STATE.value],\n                Core.isDesktopMode,\n                Core.configuration.demo,\n                Core.ORIENTATION.value.orientation.toLowerCase(),\n                Core.configuration.mode,\n                Boolean(this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value),\n                this.fastStopRequested,\n                Core.environment.isFullScreen(), // full screen value is not correct when website is zoomed.\n                Core.LEFT_HAND_MODE.value,\n                this.rootStore.subjects.TOGGLE_QUICK_SPIN.value,\n                this.rootStore.subjects.TOGGLE_TURBO_SPIN.value,\n                this.rootStore.domainStore.SPIN_MODE.value,\n                Core.sounds.ON_SOUND_MUTED.value,\n                Core.BATTERY_SAVE_MODE.value,\n                false,\n                this.rootStore.uiStore.SELECTED_BET.value,\n                Core.SELECTED_DENOMINATION.value,\n                Core.PLAYER_BALANCE.value.currency,\n                this.rootStore.settings.factor,\n                Core.hasComponent(SlotComponents.BACKGROUND_SOUND)\n                    ? Core.sounds.ON_BACKGROUND_SOUNDS_MUTED.value || Core.sounds.ON_SOUND_MUTED.value\n                    : undefined,\n            );\n        }\n    }\n\n    protected stopAutoplay(clicked: boolean = false): void {\n        Timers.clearTimeout(this.timeoutId);\n        this.rootStore.subjects.RESET_AUTOPLAY_RESTRICTIONS.next();\n        this.resetAutoState();\n        if (\n            this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_RESPONSE_IN_AUTOPLAY &&\n            !this.rootStore.domainStore.betResponse?.totalWinAmount\n        ) {\n            this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_RESPONSE);\n        }\n\n        if (clicked) {\n            this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_RESPONSE);\n        }\n\n        if (this.waitingBeforeNexSpin && this.reelsStopped && !this.rootStore.domainStore.betResponse?.totalWinAmount) {\n            this.rootStore.uiStore.STATE.next(UIState.IDLE);\n        }\n\n        if (this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value > 0) {\n            this.view.stopButton.state = ButtonStates.Normal;\n        }\n        // set to MANUAL only if no other feature got the SPIN_MODE already\n        if (this.rootStore.domainStore.SPIN_MODE.value === Features.AUTO_PLAY) {\n            if (\n                this.featureController.isInGiftSpins &&\n                this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_RESPONSE_IN_AUTOPLAY\n            ) {\n                return;\n            }\n            this.rootStore.domainStore.SPIN_MODE.next(Features.MANUAL_SPIN);\n            this.rootStore.domainStore.SPIN_MODE.prevValue = Features.MANUAL_SPIN;\n        }\n        // this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(false);\n        ////////////////////////// JP STATS ENABLE DISABLE ///////////////////////////////////////////////////////////////////////////\n        /*   const hasWin = this.rootStore.domainStore.betResponse?.totalWinAmount;\n        if (hasWin > 0) {\n            if (this.rootStore.isGreatWin) {\n                //&& this.rootStore.uiStore.WIN.value.amount === 0 || this.rootStore.uiStore.WIN.value.amount === undefined\n                this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(true);\n                this.rootStore.subjects.FEATURE_COMPLETE.pipe(takeUntil(this.GREAT_WINFINISHED)).subscribe((e) => {\n                    if (\n                        e === Features.COIN ||\n                        e === Features.BIG_WIN ||\n                        e === Features.MAX_WIN ||\n                        e === Features.HIGH_CASH_COIN\n                    ) {\n                        this.GREAT_WINFINISHED.next();\n                        if (this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT) {\n                            this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(false);\n                        }\n                    }\n                });\n            } else {\n                this.rootStore.uiStore.STATE.pipe(take(2)).subscribe(() => {\n                    if (this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT) {\n                        this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(false);\n                    }\n                });\n            }\n        } else {\n            this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(false);\n        } */\n        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    }\n\n    protected autoplay(): void {\n        if (this.shouldStopAutoplay()) {\n            this.stopAutoplay();\n            this.rootStore.uiStore.STATE.next(this.rootStore.uiStore.STATE.value);\n            return;\n        }\n\n        if (this.rootStore.subjects.MAX_WIN_LIMIT_HIT.value) {\n            this.rootStore.subjects.MAX_WIN_LIMIT_MESSAGE.next('MAX_WIN.LIMIT_HIT');\n        }\n\n        const delay = this.rootStore.domainStore.betResponse.totalWinAmount\n            ? this.getAutoplayTime()\n            : this.getDelayOnNonWiningSpin();\n        if (!this.rootStore.domainStore.betResponse.totalWinAmount) {\n            this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_RESPONSE_IN_AUTOPLAY);\n            this.rootStore.subjects.BET_BUTTONS_LABLE_STATE.next('STOP');\n        }\n        if (this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value === -1) {\n            this.view.infinitySign.visible = true;\n        }\n        this.waitingBeforeNexSpin = true;\n        this.timeoutId = Timers.setTimeout(() => {\n            this.waitingBeforeNexSpin = false;\n            this.spin();\n        }, delay);\n    }\n\n    protected getDelayOnNonWiningSpin(): number {\n        return this.config.autoplayDelayOnNonWiningSpin;\n    }\n\n    protected getWinAmount(): number {\n        return this.rootStore.uiStore.WIN.value.amount ? this.rootStore.uiStore.WIN.value.amount : 0;\n    }\n\n    protected spin(): void {\n        this.reelsStopped = false;\n        this.view.killRopeTextTween();\n        if (this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value === 0) {\n            return;\n        }\n        if (\n            this.rootStore.getBetAmount() > this.rootStore.uiStore.BALANCE.value + this.getWinAmount() &&\n            !this.featureController.isInGiftSpins\n        ) {\n            this.rootStore.subjects.SHOW_DIRECT_MESSAGEBAR_TEXT.next([\n                MessBarTypes.INSUFFICIENT,\n                Core.translator.translate('4813').toUpperCase().replace('. (##ERROR_CODE##)', ''),\n            ]);\n            PostMessageDispatcher.balanceTooLow();\n\n            this.rootStore.subjects.CLOSE_AUTOPLAY_POPUP.next();\n            this.rootStore.subjects.STOP_AUTOPLAY.next(false);\n            if (this.getWinAmount() > 0) {\n                this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_COLLECT);\n            } else {\n                this.rootStore.uiStore.STATE.next(UIState.IDLE);\n            }\n            return;\n        }\n        if (this.rootStore.subjects.SHOW_DIRECT_MESSAGEBAR_TEXT.value) {\n            this.rootStore.subjects.SHOW_DIRECT_MESSAGEBAR_TEXT.next(false);\n        }\n        if (\n            this.rootStore.domainStore.SPIN_MODE.value === Features.AUTO_PLAY &&\n            this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value > 0\n        ) {\n            this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.next(this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value - 1);\n        }\n\n        this.rootStore.uiStore.turboModeEnabled = this.rootStore.subjects.TOGGLE_TURBO_SPIN.value;\n\n        this.rootStore.uiStore.quickSpinEnabled = this.rootStore.subjects.TOGGLE_QUICK_SPIN.value;\n\n        this.rootStore.subjects.CLOSE_ALL_POPUPS.next();\n        this.rootStore.subjects.BEFORE_SPIN.next();\n        this.rootStore.subjects.SPIN_STARTED.next();\n        // metrics: mark spin start for session aggregation\n        AnalyticsDispatcher.onSpinStarted({\n            orientation: Core.ORIENTATION.value.orientation,\n            desktop: Core.isDesktopMode,\n            spinMode: this.rootStore.domainStore.SPIN_MODE.value,\n            spinSpeed: this.rootStore.subjects.SPIN_SPEED?.value,\n        });\n\n        if (\n            !this.featureController.isInGiftSpins &&\n            (this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT_IN_AUTOPLAY ||\n                this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT ||\n                this.rootStore.uiStore.STATE.value === UIState.WIN)\n        ) {\n            this.rootStore.uiStore.BALANCE.next(\n                this.rootStore.uiStore.BALANCE.value -\n                    this.rootStore.getBetAmount() +\n                    this.rootStore.uiStore.WIN.value.amount,\n            );\n        } else if (!this.featureController.isInGiftSpins) {\n            this.rootStore.uiStore.BALANCE.next(this.rootStore.uiStore.BALANCE.value - this.rootStore.getBetAmount());\n        }\n\n        this.rootStore.domainStore.bet();\n        this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_RESPONSE_IN_AUTOPLAY);\n        Core.sounds.play('spinSound');\n    }\n\n    protected getAutoplayTime(): number {\n        let time: number = this.config.autoplayWinTime;\n\n        if (this.rootStore.uiStore.turboModeEnabled) {\n            time = this.config.autoplayWinTurboTime;\n        } else if (this.rootStore.uiStore.quickSpinEnabled) {\n            time = this.config.autoplayWinQuickTime;\n        }\n\n        const betResponse = this.rootStore.domainStore.betResponse;\n        if (betResponse) {\n            if (this.rootStore.isGreatWin) {\n                if (Core.hasFeature(Features.BIG_WIN)) {\n                    time = this.config.autoplayWinBigWinTime;\n                } else {\n                    time = this.config.autoplayWinCoinFeatureTime;\n                }\n            }\n        }\n        return time;\n    }\n\n    protected resetAutoState(): void {\n        this.rootStore.uiStore.autoPlayFromSettings = false;\n        this.view.infinitySign.visible = false;\n    }\n\n    protected onStopClicked(): void {\n        if (this.featureController.isFeatureMode || this.rootStore.domainStore.SPIN_MODE.value !== Features.AUTO_PLAY) {\n            this.resetAutoState();\n            return;\n        }\n        Core.sounds.play('stopAutoplaySound');\n        this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.next(0);\n        switch (this.rootStore.uiStore.STATE.value) {\n            case UIState.WAITING_FOR_RESPONSE_IN_AUTOPLAY:\n                if (this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value === 0) {\n                    this.rootStore.subjects.REELS_STOP_ALL.next();\n                }\n                break;\n            case UIState.WAITING_FOR_COLLECT_IN_AUTOPLAY:\n                this.rootStore.uiStore.CLEAR_BANG_UP.next();\n                this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_COLLECT);\n                break;\n            case UIState.WIN:\n                this.rootStore.uiStore.CLEAR_BANG_UP.next();\n                this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_COLLECT);\n                break;\n            default:\n        }\n        this.stopAutoplay(false);\n    }\n\n    /*\n     * In perfect case, we should just check for empty ACTIVE_FEATURE array, but\n     * but in reality, we have some features that do not get cleared from the array,\n     * so a quicker solution is to check for some specific features.\n     * */\n    protected isFeaturePreventingAutoplayToStart(): boolean {\n        let hasFeature = false;\n        const featuresToAvoid = [\n            Features.MYSTERY_JACKPOT,\n            Features.FREE_SPINS,\n            Features.FREE_SPINS_PICK,\n            Features.RESPIN,\n            Features.HOLD_RESPIN,\n            Features.BL_JACKPOT,\n            Features.GAKL_JACKPOT_V1,\n            Features.GAKL_JACKPOT_BASE,\n        ];\n        for (const feat of featuresToAvoid) {\n            hasFeature = this.rootStore.subjects.ACTIVE_FEATURE.value.includes(feat);\n            if (hasFeature) {\n                break;\n            }\n        }\n        return hasFeature;\n    }\n\n    protected onKeyReleased(e: KeyboardEvent): void {\n        if (\n            e !== null &&\n            e.code !== undefined &&\n            e.code === 'KeyA' &&\n            Core.configuration.mode === 'kiosk' &&\n            !this.isFeaturePreventingAutoplayToStart()\n        ) {\n            if (\n                this.rootStore.domainStore.SPIN_MODE.value !== Features.AUTO_PLAY &&\n                [UIState.IDLE, UIState.BONUS_IDLE, UIState.WAITING_FOR_COLLECT].includes(\n                    this.rootStore.uiStore.STATE.value as UIState,\n                )\n            ) {\n                this.onAutoPlayClicked();\n                return;\n            } else if (this.rootStore.domainStore.SPIN_MODE.value === Features.AUTO_PLAY) {\n                this.onStopClicked();\n                return;\n            }\n        }\n\n        if (e === null || this.rootStore.domainStore.SPIN_MODE.value !== Features.AUTO_PLAY) {\n            return;\n        }\n        if (\n            (e.code !== undefined && (e.code === 'Space' || e.code === 'Enter' || e.code === 'NumpadEnter')) ||\n            (e.keyCode !== undefined && (e.keyCode === 32 || e.keyCode === 13))\n        ) {\n            switch (this.rootStore.uiStore.STATE.value) {\n                case UIState.WAITING_FOR_RESPONSE_IN_AUTOPLAY:\n                    if (this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value === 0) {\n                        this.rootStore.subjects.REELS_STOP_ALL.next();\n                    }\n                    break;\n                case UIState.WIN:\n                    if (this.rootStore.uiStore.BANGUP_RUNNING.value) {\n                        this.rootStore.uiStore.CLEAR_BANG_UP.next();\n                    }\n                    break;\n            }\n        }\n    }\n\n    private stopAutoplayFromOutside(event): void {\n        if (event.data.command === 'stopAutoplay' && Core.configuration.gameKey !== '') {\n            this.stopAutoplay();\n            Log.debug('AUTOPLAY STOPPED', this.constructor.name);\n        }\n    }\n\n    private onAutoPlayStart(numberOfBets): void {\n        // Core.NO_SLEEP_ACTIVE.next(true);\n        // Log.debug('onAutoPlayStart NO SLEEP JS is :', Core.NO_SLEEP_ACTIVE.value);\n        Core.sounds.play('startAutoplaySound');\n        this.startAutoplay(numberOfBets);\n        PostMessageDispatcher.autoPlayStarted(numberOfBets);\n        Log.debug('AUTOPLAY STARTED', this.constructor.name);\n        this.rootStore.uiStore.BACKGROUND_SOUND_PLAY.next({ sound: 'backgroundMusic', ms: 800 });\n    }\n\n    private onCollectClicked(): void {\n        Timers.clearTimeout(this.timeoutId);\n        this.spin();\n    }\n\n    private onShowError(err: IErrorData): void {\n        if (err.type !== ErrorTypes.CONNECTION_ERROR && err.type !== ErrorTypes.CONFIRMATION) {\n            this.stopAutoplay();\n        }\n    }\n\n    private startAutoplay(numberOfBets: number): void {\n        this.rootStore.uiStore.currentTotalLoss = 0;\n        if (this.rootStore.uiStore.allRestrictionsApplied) {\n            this.rootStore.uiStore.balanceStartValue = this.rootStore.uiStore.BALANCE.value + this.getWinAmount();\n        }\n        if (numberOfBets === -1) {\n            this.view.infinitySign.visible = true;\n        }\n        if (this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value > 0) {\n            this.view.stopButton.state = ButtonStates.Disabled;\n        }\n        // this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(true);\n        this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.next(numberOfBets);\n        this.rootStore.domainStore.SPIN_MODE.next(Features.AUTO_PLAY);\n        this.rootStore.domainStore.SPIN_MODE.prevValue = Features.AUTO_PLAY;\n        this.spin();\n    }\n\n    // AUTOPLAY STOP CONDITIONS\n    protected isBalanceDecreasedEnough(): boolean {\n        return (\n            this.rootStore.uiStore.balanceDecreaseValue > 0 &&\n            this.rootStore.uiStore.BALANCE.value + this.rootStore.uiStore.WIN.value.amount <=\n                this.rootStore.uiStore.balanceDecreaseValue &&\n            !this.featureController.isInGiftSpins\n        );\n    }\n\n    protected isBalanceIncreasedEnough(): boolean {\n        return (\n            this.rootStore.uiStore.balanceIncreaseValue > 0 &&\n            this.rootStore.uiStore.BALANCE.value + this.rootStore.uiStore.WIN.value.amount >\n                this.rootStore.uiStore.balanceIncreaseValue\n        );\n    }\n\n    protected isWinLimitReached(): boolean {\n        return (\n            !!this.rootStore.domainStore.betResponse.totalWinAmount &&\n            this.rootStore.uiStore.winLimitValue > 0 &&\n            this.getWinAmount() >= this.rootStore.uiStore.winLimitValue\n        );\n    }\n\n    protected isMaxLossReached(): boolean {\n        const maxLoss = this.rootStore.uiStore.maxTotalLossLimit;\n        const nextLoss =\n            this.rootStore.uiStore.currentTotalLoss +\n            this.rootStore.uiStore.SELECTED_BET.value * Core.SELECTED_DENOMINATION.value * this.rootStore.factor;\n        if (!maxLoss || maxLoss <= 0) {\n            return false;\n        }\n        return nextLoss > maxLoss;\n    }\n\n    protected isAutoPlaySpinsDepleted(): boolean {\n        return this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value === 0;\n    }\n\n    protected shouldStopAutoplay(): boolean {\n        return (\n            this.isBalanceDecreasedEnough() ||\n            this.isBalanceIncreasedEnough() ||\n            this.isWinLimitReached() ||\n            this.isAutoPlaySpinsDepleted() ||\n            this.isMaxLossReached()\n        );\n    }\n}\n","import { BackgroundMusic } from '@egt/background-sound';\nimport Core, {\n    AnalyticsDispatcher,\n    BaseController,\n    IErrorData,\n    PostMessageDispatcher,\n    Timers,\n    UserActionType,\n} from '@egt/core';\nimport { DenominationPopupModes } from '@egt/denomination-popup';\nimport { SettingsTab } from '@egt/settings-popup';\nimport {\n    AnalyticsState,\n    BangupActionConsts,\n    BetResponse,\n    FeatureController,\n    Features,\n    ISlotConfiguration,\n    InitialSettings,\n    MessBarTypes,\n    RootStore,\n    ServerState,\n    SlotComponents,\n    UIState,\n} from '@egt/slot';\nimport { ButtonStates } from '@egt/ui-lib';\nimport { fromEvent } from 'rxjs';\nimport { filter, takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport UIViewDefault from '../views/UIViewDefault';\n\n@injectable()\nexport default class UIViewManualControllerDefault extends BaseController {\n    protected gameCanvasContainer: HTMLCanvasElement;\n    // protected noActivityTimeoutId: NodeJS.Timeout;\n    // protected spinTimeoutId: NodeJS.Timeout;\n    // protected spinButton: Button;\n    // protected skipButton: Button;\n    // protected spinSpeedButton: Sprite;\n    // protected stopButton: Button;\n    // protected ropeTextTween: any;\n    // protected spinButtonTween: any;\n    // protected skipButtonTween: any;\n    // protected stopButtonTween: any;\n    // protected spinButtonWidth: number;\n    // protected spinButtonHeight: number;\n    // protected skipButtonWidth: number;\n    // protected skipButtonHeight: number;\n    // protected stopButtonSizeWidth: number;\n    // protected stopButtonSizeHeight: number;\n    // private turboModeActiveTimer: boolean = false;\n\n    protected fastPlayNextSpin: any;\n    protected fastStopRequested: boolean = false;\n    protected settingsOpened: boolean = false;\n    protected spinButtonOut = false;\n\n    constructor(\n        @inject('UIView') protected view: UIViewDefault,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected config: ISlotConfiguration,\n        @inject('FeatureController') protected featureController: FeatureController,\n        @inject('InitialSettings') protected settings: InitialSettings,\n    ) {\n        super(view);\n        this.gameCanvasContainer = document.getElementById('app-root') as HTMLCanvasElement;\n        this.attachEventListeners();\n    }\n\n    public destroy(): void {\n        super.destroy.apply(this, arguments);\n    }\n\n    public pulseSpin(value: boolean): void {\n        if (value) {\n            this.view.pulseSpin();\n        } else {\n            this.view.stopSpinPulsation();\n        }\n    }\n\n    protected onDenominationClicked(): void {\n        if (\n            Core.configuration.mode !== 'mobile' &&\n            Core.hasComponent(SlotComponents.DENOMINATION_POPUP, DenominationPopupModes.DEFAULT)\n        ) {\n            this.rootStore.uiStore.CLEAR_BANG_UP.next();\n            this.rootStore.uiStore.SELECTED_SETTINGS_TAB.next(SettingsTab.BET);\n            this.rootStore.subjects.OPEN_SETTINGS_POPUP.next();\n            return;\n        }\n        if (\n            this.rootStore.uiStore.denominations.length > 1 ||\n            !Core.hasComponent(SlotComponents.DENOMINATION_POPUP, DenominationPopupModes.DEFAULT)\n        ) {\n            this.rootStore.uiStore.CLEAR_BANG_UP.next();\n            this.rootStore.subjects.TOGGLE_DENOMINATION_POPUP.next();\n        } else {\n            this.rootStore.uiStore.CLEAR_BANG_UP.next();\n            this.rootStore.subjects.TOGGLE_BET_SETTINGS_POPUP.next();\n            this.rootStore.uiStore.SELECTED_SETTINGS_TAB.next(SettingsTab.BET);\n            // this.rootStore.subjects.OPEN_SETTINGS_POPUP.next();\n        }\n    }\n\n    protected onSpinClicked(): void {\n        if (\n            this.featureController.isFeatureMode ||\n            this.rootStore.domainStore.SPIN_MODE.value !== Features.MANUAL_SPIN ||\n            this.spinButtonOut\n        ) {\n            return;\n        }\n        this.resetSpinBtnSize();\n\n        switch (this.rootStore.uiStore.STATE.value) {\n            case UIState.IDLE:\n            case UIState.BONUS_IDLE:\n            case UIState.WAITING_FOR_COLLECT:\n                this.rootStore.uiStore.CLEAR_BANG_UP.next();\n                Timers.clearTimeout(this.view.spinTimeoutId);\n                this.spin();\n                break;\n        }\n    }\n\n    protected onStopButtonDown(): void {\n        this.view.onStopButtonDown();\n    }\n\n    protected onStopButtonUp(): void {\n        this.view.onStopButtonUp();\n    }\n\n    protected onSpinButtonDown(): void {\n        this.spinButtonOut = false;\n        this.setPopUpSpinBut();\n\n        if (\n            this.featureController.isFeatureMode ||\n            this.rootStore.domainStore.SPIN_MODE.value !== Features.MANUAL_SPIN\n        ) {\n            return;\n        }\n\n        this.resetStopBtnSize();\n        // this.rootStore.uiStore.turboModeDeactivated = false;\n        this.rootStore.subjects.CLOSE_ALL_POPUPS.next();\n        this.rootStore.subjects.CLOSE_BUY_BONUS_POPUP.next();\n\n        if (\n            !this.view.spinButton.enabled ||\n            (this.rootStore.uiStore.STATE.value !== UIState.IDLE &&\n                this.rootStore.uiStore.STATE.value !== UIState.BONUS_IDLE &&\n                this.rootStore.uiStore.STATE.value !== UIState.WAITING_FOR_COLLECT)\n        ) {\n            // this.destroySpinButtonAnimations();\n            this.deactivateTurboMode();\n            return;\n        }\n\n        this.view.onSpinButtonDown();\n\n        // this.rootStore.subjects.JACKPOT_STATS_POINTER.next(false);\n    }\n\n    protected setSpinButtonOutEvent(event): void {\n        const pos = event.data.global;\n        const safeBounds = this.view.spinButton.getBounds();\n        if (!safeBounds.contains(pos.x, pos.y)) {\n            this.setSpinButtonOut(event);\n        }\n    }\n\n    protected setSpinButtonOut(_event): void {\n        this.spinButtonOut = true;\n        this.onSpinButtonUp();\n    }\n\n    protected onSpinButtonUp(): void {\n        if (this.rootStore.subjects.KEY_DOWN.value !== null) {\n            return;\n        }\n        //console.log('BUTTON UP');\n        if (this.view.spinButtonTween) {\n            this.view.spinButtonTween.kill();\n        }\n        this.resetStopBtnSize();\n        this.view.destroyTimers();\n        this.setPopDownSpinBut();\n        this.deactivateTurboMode();\n        this.view.onSpinButtonUp();\n\n        // this.rootStore.subjects.JACKPOT_STATS_POINTER.next(true);\n    }\n\n    protected resetStopBtnSize(): void {\n        this.view.resetStopBtnSize();\n    }\n\n    protected resetSpinBtnSize(): void {\n        this.view.resetSpinBtnSize();\n    }\n\n    // protected resetSkipBtnSize(): void {\n    //     this.view.resetSkipBtnSize();\n    // }\n\n    protected setPopDownSpinBut(): void {\n        this.view.setPopDownSpinBut();\n    }\n\n    protected setPopDownSkipBut(): void {\n        this.view.setPopDownSkipBut();\n    }\n\n    protected destroyTimers(): void {\n        Timers.clearTimeout(this.view.spinTimeoutId);\n    }\n\n    protected onSpinButtonPopAnimComplete(): void {\n        if (\n            this.rootStore.uiStore.STATE.value === UIState.IDLE ||\n            this.rootStore.uiStore.STATE.value === UIState.BONUS_IDLE ||\n            this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT\n        ) {\n            this.rootStore.uiStore.fastSpinMode = true;\n            this.rootStore.uiStore.turboModeLastWin = 0;\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'spinSpeedButton',\n                actions: 'visible',\n                values: false,\n            });\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'spinSpeedButtonDisabled',\n                actions: 'visible',\n                values: true,\n            });\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'instaSpinsButton',\n\n                actions: 'enabled',\n\n                values: false,\n            });\n            // this.view.spinSpeedButton.visible = false;\n            // this.view.spinSpeedButtonDisabled.visible = true;\n            this.onSpinClicked();\n        }\n    }\n\n    protected deactivateTurboMode(): void {\n        // if (this.rootStore.uiStore.turboModeEnabled) {\n        //     this.rootStore.uiStore.turboModeDeactivated = this.rootStore.uiStore.WIN.value.amount > 0 ? false : true;\n        // }\n        this.rootStore.uiStore.turboModeEnabled = false;\n        this.rootStore.uiStore.fastSpinMode = false;\n        this.rootStore.uiStore.turboModeLastWin = 0;\n    }\n\n    protected setPopUpSpinBut(): void {\n        this.view.setPopUpSpinBut();\n    }\n\n    protected setPopUpSkipBut(): void {\n        this.view.setPopUpSkipBut();\n    }\n\n    protected killTurboTextTween(): void {\n        this.view.killRopeTextTween();\n    }\n\n    protected onStopClicked(): void {\n        if (\n            (this.featureController.isFeatureMode ||\n                this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value > 0 ||\n                this.rootStore.domainStore.SPIN_MODE.value !== Features.MANUAL_SPIN) &&\n            this.rootStore.domainStore.SERVER_STATE.value !== ServerState.MYSTERY\n        ) {\n            return;\n        }\n        switch (this.rootStore.uiStore.STATE.value) {\n            case UIState.WAITING_FOR_RESPONSE:\n                this.rootStore.subjects.REELS_STOP_ALL.next();\n                // this.rootStore.subjects.MODAL_PRESSED.next();\n                // this.view.stopButton.visible = true;\n                this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                    name: 'spinButton',\n                    actions: 'visible',\n                    values: false,\n                });\n                // this.view.spinButton.visible = false;\n                break;\n            case UIState.WAITING_FOR_COLLECT:\n                this.rootStore.uiStore.CLEAR_BANG_UP.next();\n                // this.rootStore.uiStore.STATE.next(UIState.IDLE);\n                break;\n        }\n    }\n\n    protected onSpinSpeedClicked(): void {\n        const currentSpeed = this.rootStore.subjects.SPIN_SPEED.value;\n        switch (currentSpeed) {\n            case 0:\n                Core.sounds.play('turboQuickOn');\n                this.rootStore.subjects.SPIN_SPEED.next(1);\n                this.rootStore.subjects.TOGGLE_QUICK_SPIN.next(true);\n                PostMessageDispatcher.fastPlayChange('Speed - 2');\n                AnalyticsDispatcher.incrementUserAction(UserActionType.SpeedModeUsed);\n                break;\n            case 1:\n                Core.sounds.play('turboQuickOn2');\n                this.rootStore.subjects.SPIN_SPEED.next(2);\n                this.rootStore.subjects.TOGGLE_QUICK_SPIN.next(false);\n                this.rootStore.uiStore.quickSpinEnabled = false;\n                this.rootStore.subjects.TOGGLE_TURBO_SPIN.next(true);\n                PostMessageDispatcher.fastPlayChange('Speed - 3');\n                AnalyticsDispatcher.incrementUserAction(UserActionType.SpeedModeUsed);\n\n                break;\n            case 2:\n                Core.sounds.play('turboQuickOff');\n                this.rootStore.subjects.SPIN_SPEED.next(0);\n                this.rootStore.subjects.TOGGLE_TURBO_SPIN.next(false);\n                this.rootStore.uiStore.turboModeLastWin = 0;\n                PostMessageDispatcher.fastPlayChange('Speed - 1');\n                AnalyticsDispatcher.incrementUserAction(UserActionType.SpeedModeUsed);\n                break;\n        }\n    }\n\n    protected onSpinSpeedChanged(speed: number): void {\n        this.view.onSpinSpeedChanged(speed);\n    }\n\n    protected attachEventListeners(): void {\n        // this.spinButton = this.view.spinButton;\n        // this.skipButton = this.view.skipButton;\n        // this.spinSpeedButton = this.view.spinSpeedButton;\n        // this.stopButton = this.view.stopButton;\n        // this.spinButtonWidth = this.spinButton.width;\n        // this.spinButtonHeight = this.spinButton.height;\n        // this.skipButtonWidth = this.skipButton.width;\n        // this.skipButtonHeight = this.skipButton.height;\n        // this.stopButtonSizeWidth = this.stopButton.width;\n        // this.stopButtonSizeHeight = this.stopButton.height;\n\n        this.view.stopButton.CLICK.pipe(\n            filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n            takeUntil(this.DESTROY),\n        ).subscribe(this.onStopClicked.bind(this));\n\n        this.view.spinButton.CLICK.pipe(\n            filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n            takeUntil(this.DESTROY),\n        ).subscribe(this.onSpinClicked.bind(this));\n\n        /*  this.view.spinButton.VALUE_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe((e) => {\n            this.rootStore.subjects.GET_UI_VIEW_COMPONENT_STATE.next({\n                name: 'spinButton',\n                property: e.property,\n                value: e.value,\n            });\n        }); */\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/ui-view/src/egt/modes/default/controllers/UIViewManualControllerDefault.ts:366:9\",(this.view.spinSpeedButton),\"pointertap\"]), fromEvent(this.view.spinSpeedButton, 'pointertap'))\n            .pipe(\n                filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.onSpinSpeedClicked.bind(this));\n\n        if (this.view.instaSpinsButton) {\n            (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/ui-view/src/egt/modes/default/controllers/UIViewManualControllerDefault.ts:374:13\",(this.view.instaSpinsButton),\"pointertap\"]), fromEvent(this.view.instaSpinsButton, 'pointertap'))\n\n                .pipe(\n                    filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n\n                    takeUntil(this.DESTROY),\n                )\n                .subscribe(this.onInstaSpinsClicked.bind(this));\n        }\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/ui-view/src/egt/modes/default/controllers/UIViewManualControllerDefault.ts:384:9\",(this.view.spinButton),\"pointerdown\"]), fromEvent(this.view.spinButton, 'pointerdown'))\n            .pipe(\n                filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.onSpinButtonDown.bind(this));\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/ui-view/src/egt/modes/default/controllers/UIViewManualControllerDefault.ts:390:9\",(this.view.spinButton),\"pointerup\"]), fromEvent(this.view.spinButton, 'pointerup'))\n            .pipe(\n                filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.onSpinButtonUp.bind(this));\n        fromEvent(this.view.spinButton, 'pointerout')\n            .pipe(\n                filter(\n                    (_x) =>\n                        !this.rootStore.subjects.KEY_DOWN.value &&\n                        (this.rootStore.uiStore.fastSpinMode || this.view.spinButtonTween !== null),\n                ),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.setSpinButtonOut.bind(this));\n\n        fromEvent(this.view.spinButton, 'pointermove')\n            .pipe(\n                filter(\n                    (_x) =>\n                        Core.configuration.mode === 'mobile' &&\n                        this.view.spinButton.state === ButtonStates.Pressed &&\n                        (this.rootStore.uiStore.fastSpinMode || this.view.spinButtonTween !== null),\n                ),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.setSpinButtonOutEvent.bind(this));\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/ui-view/src/egt/modes/default/controllers/UIViewManualControllerDefault.ts:418:9\",(this.view.spinButton),\"pointerupoutside\"]), fromEvent(this.view.spinButton, 'pointerupoutside'))\n            .pipe(\n                filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.setSpinButtonOut.bind(this));\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/ui-view/src/egt/modes/default/controllers/UIViewManualControllerDefault.ts:424:9\",(this.gameCanvasContainer),\"touchend\"]), fromEvent(this.gameCanvasContainer, 'touchend'))\n            .pipe(\n                filter((_x) => this.rootStore.uiStore.fastSpinMode),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.onSpinButtonUp.bind(this));\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/ui-view/src/egt/modes/default/controllers/UIViewManualControllerDefault.ts:430:9\",(this.view.stopButton),\"pointerdown\"]), fromEvent(this.view.stopButton, 'pointerdown'))\n            .pipe(\n                filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.onStopButtonDown.bind(this));\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/ui-view/src/egt/modes/default/controllers/UIViewManualControllerDefault.ts:436:9\",(this.view.stopButton),\"pointerup\"]), fromEvent(this.view.stopButton, 'pointerup'))\n            .pipe(\n                filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.onStopButtonUp.bind(this));\n        fromEvent(this.view.stopButton, 'pointerout')\n            .pipe(\n                filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.onStopButtonUp.bind(this));\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/ui-view/src/egt/modes/default/controllers/UIViewManualControllerDefault.ts:448:9\",(this.view.stopButton),\"pointerupoutside\"]), fromEvent(this.view.stopButton, 'pointerupoutside'))\n            .pipe(\n                filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.onStopButtonUp.bind(this));\n        fromEvent(window, 'blur')\n            .pipe(\n                filter((_x) => this.rootStore.uiStore.fastSpinMode),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.onSpinButtonUp.bind(this));\n\n        this.view.denominationButton.CLICK.pipe(\n            filter(\n                (_x) =>\n                    !this.rootStore.subjects.KEY_DOWN.value && this.rootStore.subjects.SHOW_JP_STATS.value.type === -1,\n            ),\n            takeUntil(this.DESTROY),\n        ).subscribe(this.onDenominationClicked.bind(this));\n\n        this.rootStore.uiStore.COLLECT_CLICKED.chainSubscribe(Features.MANUAL_SPIN, this.onCollectClicked.bind(this));\n\n        this.view.collectSmallButton.CLICK.pipe(\n            filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n            takeUntil(this.DESTROY),\n        ).subscribe(this.onCollectClicked.bind(this));\n\n        this.view.ON_SPIN_BUTTON_POP_ANIM_COMPLETE.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onSpinButtonPopAnimComplete.bind(this),\n        );\n\n        this.rootStore.subjects.REELS_STOPPED.chainSubscribe(Features.MANUAL_SPIN, this.onReelsStopped.bind(this));\n        this.rootStore.subjects.REELS_STOPPED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.sendAnalyticsData.bind(this),\n        );\n\n        this.rootStore.subjects.SEND_DEMO_CHOICE.pipe(takeUntil(this.DESTROY)).subscribe(this.spin.bind(this));\n\n        this.rootStore.subjects.REELS_STOP_ALL.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.fastStopRequested = true;\n        });\n        this.rootStore.subjects.START_MANUAL_SPIN.pipe(takeUntil(this.DESTROY)).subscribe(this.spin.bind(this));\n\n        this.rootStore.subjects.PULSATE_SPIN_BTN.pipe(takeUntil(this.DESTROY)).subscribe(this.pulseSpin.bind(this));\n\n        this.rootStore.subjects.STOP_PULSATE_SPIN_BTN.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.destroyTimers.bind(this),\n            this.view.destroyIntervals.bind(this),\n        );\n\n        this.rootStore.domainStore.BET.pipe(takeUntil(this.DESTROY)).subscribe(this.onBetResponse.bind(this));\n\n        this.rootStore.uiStore.STATE.pipe(takeUntil(this.DESTROY)).subscribe(this.onStateChanged.bind(this));\n        Core.TOUCH_CANCEL.pipe(takeUntil(this.DESTROY)).subscribe(this.onSpinButtonUp.bind(this));\n        this.rootStore.subjects.SPIN_SPEED.pipe(takeUntil(this.DESTROY)).subscribe(this.onSpinSpeedChanged.bind(this));\n        this.rootStore.subjects.STOP_FAST_PLAY.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onFastPlayStopped.bind(this),\n        );\n        this.rootStore.subjects.SPIN_SPEED_EXTERNAL.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onSpinSpeedClicked.bind(this),\n        );\n        this.rootStore.subjects.SETTINGS_POPUP_CLOSED.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.settingsOpened = false;\n        });\n\n        this.rootStore.subjects.SETTINGS_POPUP_OPENED.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.settingsOpened = true;\n        });\n\n        // for desktop - after exit fullscreen all pressed keys are lost (for chrome)\n        // https://jira.egt-digital.com/browse/ON-5392\n        if (Core.configuration.mode !== 'mobile') {\n            this.rootStore.subjects.KEY_UP.pipe(takeUntil(this.DESTROY)).subscribe(this.onKeyReleased.bind(this));\n\n            this.rootStore.subjects.KEY_DOWN.pipe(takeUntil(this.DESTROY)).subscribe(this.onKeyPressed.bind(this));\n\n            Core.SHOW_ERROR.pipe(takeUntil(this.DESTROY)).subscribe(this.onErrorWithInsifitionsFunds.bind(this));\n\n            // when we are in iframe document fullscreenchange is not fired\n            // then we check resize event and size of the window / screen\n            if (Core.environment.inIframe()) {\n                Core.STAGE_RESIZE_END.pipe(\n                    filter((_x) => this.rootStore.uiStore.fastSpinMode),\n                    takeUntil(this.DESTROY),\n                ).subscribe((_e) => {\n                    // sometimes there are difference with 1px between screen.width and window.innerWidth in FS\n                    const isFullScreen = Math.abs(screen.width - window.innerWidth) < 2;\n                    // this is leave fullscrren mode in iframe\n                    if (!isFullScreen) {\n                        this.forceStopFastSpinMode();\n                    }\n                });\n            }\n\n            fromEvent(document, 'fullscreenchange')\n                .pipe(\n                    filter((_x) => this.rootStore.uiStore.fastSpinMode),\n                    takeUntil(this.DESTROY),\n                )\n                .subscribe((_e) => {\n                    if (!Core.environment.isFullScreen()) {\n                        this.forceStopFastSpinMode();\n                    }\n                });\n        } else {\n            Core.ORIENTATION.pipe(\n                filter((_x) => this.rootStore.uiStore.fastSpinMode),\n                takeUntil(this.DESTROY),\n            ).subscribe((_e) => {\n                this.onSpinButtonUp();\n                this.onFastPlayStopped();\n                const te = new TouchEvent('touchend');\n                window.dispatchEvent(te);\n            });\n        }\n        //  this.rootStore.uiStore.BANGUP_RUNNING.pipe(takeUntil(this.DESTROY)).subscribe(this.onBangupRunning.bind(this));\n    }\n\n    // WHY DO WE NEED THIS TO GAIN CONTROL OVER THE SPIN MODE - WE MAY BE IN FEATURE AND IT MAY BE STILL NOT FINISHED\n    // NEED REWORK\n    protected onBetResponse(): void {\n        this.fastStopRequested = false;\n        const betResponse: BetResponse = this.rootStore.domainStore.betResponse;\n        if (betResponse.state === ServerState.WIN || betResponse.state === ServerState.IDLE) {\n            if (\n                this.rootStore.domainStore.SPIN_MODE.prevValue === Features.MANUAL_SPIN &&\n                this.rootStore.domainStore.SPIN_MODE.value !== Features.FREE_SPINS &&\n                this.rootStore.domainStore.SPIN_MODE.value !== Features.RESPIN &&\n                this.rootStore.domainStore.SPIN_MODE.value !== Features.HIGH_CASH_FREE_SPINS &&\n                this.rootStore.domainStore.SPIN_MODE.value !== Features.BASE_FREE_SPINS &&\n                this.rootStore.domainStore.SPIN_MODE.value !== Features.GAKL_FEATURE_CHANCE\n            ) {\n                // Check if SPINMODE is Freespin because when you restore on last freespin round not to gain the SPIN_MODE\n                this.rootStore.domainStore.SPIN_MODE.next(Features.MANUAL_SPIN);\n            }\n        }\n    }\n\n    protected onCollectClicked(): void {\n        this.view.destroyTimers();\n        this.rootStore.uiStore.STATE.next(UIState.DISABLED);\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'collectSmallButton',\n            actions: 'enabled',\n            values: false,\n        });\n        // this.view.find('collectSmallButton').enabled = false;\n        this.rootStore.domainStore.collect();\n        this.rootStore.uiStore.COLLECT_CHANGED.next();\n    }\n    protected onInstaSpinsClicked(): void {\n        if (this.view.instaSpinsButton.enabled) {\n            Core.sounds.play('bpEnterBlitzPlay');\n\n            Core.BLITZ_PLAY_OPEN.next(true);\n        }\n    }\n\n    protected spin(): void {\n        if (this.fastPlayNextSpin) {\n            Timers.clearTimeout(this.fastPlayNextSpin);\n        }\n        this.view.killRopeTextTween();\n        this.fastStopRequested = false;\n        // this.rootStore.uiStore.SHOW_SETTINGS.next(false);\n        this.rootStore.subjects.CLOSE_ALL_POPUPS.next();\n        this.rootStore.subjects.CLOSE_BUY_BONUS_POPUP.next();\n        this.rootStore.uiStore.turboModeEnabled =\n            this.rootStore.subjects.TOGGLE_TURBO_SPIN.value || this.rootStore.uiStore.fastSpinMode;\n        this.rootStore.uiStore.quickSpinEnabled =\n            this.rootStore.subjects.TOGGLE_QUICK_SPIN.value && !this.rootStore.uiStore.fastSpinMode;\n        if (\n            this.rootStore.getBetAmount() > this.rootStore.uiStore.BALANCE.value + this.getWinAmount() &&\n            !this.featureController.isInGiftSpins\n        ) {\n            if (\n                this.rootStore.uiStore.WIN.value.amount === 0 ||\n                this.rootStore.uiStore.WIN.value.amount === undefined\n            ) {\n                this.rootStore.uiStore.STATE.next(UIState.IDLE);\n            } else {\n                this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_COLLECT);\n            }\n            this.rootStore.subjects.RESET_KEY_EVENTS.next();\n            this.setPopDownSpinBut();\n            this.deactivateTurboMode();\n\n            // this.rootStore.uiStore.STATE.next(UIState.BONUS_IDLE);\n            this.rootStore.subjects.SHOW_DIRECT_MESSAGEBAR_TEXT.next([\n                MessBarTypes.INSUFFICIENT,\n                Core.translator.translate('4813').toUpperCase().replace('. (##ERROR_CODE##)', ''),\n            ]);\n            PostMessageDispatcher.balanceTooLow();\n            if (this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT) {\n                this.onCollectClicked();\n            }\n\n            return;\n        }\n        if (this.rootStore.subjects.SHOW_DIRECT_MESSAGEBAR_TEXT.value) {\n            this.rootStore.subjects.SHOW_DIRECT_MESSAGEBAR_TEXT.next(false);\n        }\n        this.rootStore.subjects.BEFORE_SPIN.next();\n        this.rootStore.subjects.SPIN_STARTED.next();\n        // metrics: mark spin start for session aggregation\n        AnalyticsDispatcher.onSpinStarted({\n            orientation: Core.ORIENTATION.value.orientation,\n            desktop: Core.isDesktopMode,\n            spinMode: this.rootStore.domainStore.SPIN_MODE.value,\n            spinSpeed: this.rootStore.subjects.SPIN_SPEED?.value,\n        });\n        if (!this.featureController.isInGiftSpins) {\n            this.setBalance();\n        }\n        this.rootStore.domainStore.bet();\n        this.setSpinState();\n        Core.sounds.play('spinSound');\n        // Core.sounds.play(\n        //     Core.sounds.hasSound('fastSpinSound') && this.rootStore.uiStore.turboModeEnabled\n        //         ? 'fastSpinSound'\n        //         : 'spinSound',\n        // );\n        this.killTurboTextTween();\n\n        if (Core.hasComponent(SlotComponents.MULTILAYERED_BG_SOUND)) {\n            if (\n                Core.sounds.getAllSounds().some((sound) => sound.id === 'backgroundSounds') &&\n                Core.sounds.getNowPlayingSounds().includes('backgroundMusic')\n            ) {\n                const currentBackgroundSound: BackgroundMusic = this.rootStore.subjects.BG_SOUND_LAYER.value;\n                this.rootStore.uiStore.BACKGROUND_SOUND_PLAY.next({ sound: currentBackgroundSound, ms: 800 });\n            }\n        } else {\n            this.rootStore.uiStore.BACKGROUND_SOUND_PLAY.next({ sound: 'backgroundMusic', ms: 800 });\n        }\n    }\n\n    protected onReelsStopped(): void {\n        const betResponse: BetResponse = this.rootStore.domainStore.betResponse;\n        const win = this.calculateWin(betResponse);\n\n        if (this.rootStore.uiStore.fastSpinMode) {\n            this.handleFastSpinMode(win, betResponse);\n        } else {\n            this.handleNormalSpinMode(win, betResponse);\n        }\n    }\n\n    protected calculateWin(betResponse: BetResponse): number {\n        return betResponse.bonusGamesTotalWinAmount || betResponse.totalWinAmount;\n    }\n\n    protected handleFastSpinMode(win: number, betResponse: BetResponse): void {\n        if (this.rootStore.subjects.MAX_WIN_LIMIT_HIT.value) {\n            this.rootStore.subjects.MAX_WIN_LIMIT_MESSAGE.next('MAX_WIN.LIMIT_HIT');\n        }\n\n        this.updateWinState(win, Features.MANUAL_SPIN);\n\n        if (betResponse.entries.length > 0) {\n            this.activateTurboMode(betResponse);\n        } else {\n            this.spin();\n            this.updateBalance(betResponse.balance);\n        }\n    }\n\n    protected activateTurboMode(betResponse: BetResponse): void {\n        this.view.turboModeActiveTimer = true;\n        this.fastPlayNextSpin = Timers.setTimeout(() => {\n            this.view.turboModeActiveTimer = false;\n            if (this.rootStore.uiStore.fastSpinMode) {\n                this.spin();\n                this.updateBalance(betResponse.balance);\n            }\n        }, this.getFastSpinTime());\n    }\n\n    protected handleNormalSpinMode(win: number, betResponse: BetResponse): void {\n        this.updateWinState(win, Features.MANUAL_SPIN);\n\n        if (win > 0 && !this.rootStore.isUnfinishedCampaign) {\n            this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_COLLECT);\n        } else {\n            this.rootStore.uiStore.STATE.next(betResponse.state);\n        }\n    }\n\n    protected updateWinState(win: number, feature: Features): void {\n        const action = win > 0 ? BangupActionConsts.BANGUP : BangupActionConsts.SET;\n        this.rootStore.uiStore.WIN.next({ amount: win, action, feature });\n    }\n\n    protected updateBalance(balance: number): void {\n        this.rootStore.uiStore.BALANCE.next(balance);\n    }\n\n    protected sendAnalyticsData(): void {\n        if (this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value === 0) {\n            AnalyticsDispatcher.reelsStoppedAnalyticsEvent(\n                Core.configuration.gameKey,\n                AnalyticsState[this.rootStore.domainStore.SERVER_STATE.value],\n                Core.isDesktopMode,\n                Core.configuration.demo,\n                Core.ORIENTATION.value.orientation.toLowerCase(),\n                Core.configuration.mode,\n                Boolean(this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value),\n                this.fastStopRequested,\n                Core.environment.isFullScreen(), // full screen value is not correct when website is zoomed.\n                Core.LEFT_HAND_MODE.value,\n                this.rootStore.subjects.TOGGLE_QUICK_SPIN.value,\n                this.rootStore.subjects.TOGGLE_TURBO_SPIN.value,\n                this.rootStore.domainStore.SPIN_MODE.value,\n                Core.sounds.ON_SOUND_MUTED.value,\n                Core.BATTERY_SAVE_MODE.value,\n                false,\n                this.rootStore.uiStore.SELECTED_BET.value,\n                Core.SELECTED_DENOMINATION.value,\n                Core.PLAYER_BALANCE.value.currency,\n                this.rootStore.settings.factor,\n                Core.hasComponent(SlotComponents.BACKGROUND_SOUND)\n                    ? Core.sounds.ON_BACKGROUND_SOUNDS_MUTED.value || Core.sounds.ON_SOUND_MUTED.value\n                    : undefined,\n            );\n        }\n    }\n\n    /*  private onBangupRunning(): void {\n        if (\n            this.featureController.isFeatureMode ||\n            this.rootStore.domainStore.SPIN_MODE.value !== Features.MANUAL_SPIN\n        ) {\n            return;\n        }\n\n        if (!this.rootStore.uiStore.BANGUP_RUNNING.value) {\n            this.view.stopButton.visible = false;\n            this.spinButton.visible = true;\n            this.spinButton.enabled = true;\n            this.spinButton.state = ButtonStates.Normal;\n        }\n    } */\n\n    protected onStateChanged(): void {\n        this.killTurboTextTween();\n        this.resetSpinBtnSize();\n        this.resetStopBtnSize();\n        if (\n            (this.rootStore.uiStore.STATE.value === UIState.IDLE ||\n                this.rootStore.uiStore.STATE.value === UIState.BONUS_IDLE ||\n                this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT) &&\n            this.view.spinButton.enabled\n        ) {\n            this.view.createRopeTextTween();\n        }\n\n        /*  if ( // IT SEEMS THAT THIS IS CHANGED AND ALREADY IS DOING NOTHING\n            this.featureController.isFeatureMode ||\n            this.rootStore.domainStore.SPIN_MODE.value !== Features.MANUAL_SPIN\n        ) {\n            return;\n        } */\n    }\n\n    /*   private destroySpinButtonAnimations(): void { // NOT IN USE\n        this.destroyTimers();\n        if (this.spinButtonTween) {\n            this.spinButtonTween.kill();\n        }\n        if (this.stopButtonTween) {\n            this.stopButtonTween.kill();\n        }\n        this.setPopDownSpinBut();\n    } */\n\n    protected onFastPlayStopped(): void {\n        this.deactivateTurboMode();\n        if (this.rootStore.domainStore.SPIN_MODE.value === Features.MANUAL_SPIN) {\n            this.view.spinButton.state = ButtonStates.Normal;\n        }\n        this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(false);\n    }\n\n    protected onKeyPressed(e: KeyboardEvent): void {\n        if (\n            e &&\n            this.rootStore.uiStore.SHOW_SETTINGS.value &&\n            ['Space', 'Enter', 'NumpadEnter', 'KeyC', 'KeyV', 'KeyB', 'KeyN', 'KeyM'].indexOf(e.code) > -1\n        ) {\n            if (this.rootStore.subjects.SETTINGS_POPUP_OPENED) {\n                this.rootStore.subjects.CLOSE_SETTINGS_POPUP.next();\n                this.rootStore.subjects.RESET_AUTOPLAY_RESTRICTIONS.next();\n                Core.sounds.play('hideDenominationsSound');\n            }\n            return;\n        }\n\n        if (\n            e === null ||\n            Core.UI_BLOCKER.value ||\n            this.rootStore.subjects.TAB_OPENED.value ||\n            this.rootStore.domainStore.SPIN_MODE.value === Features.AUTO_PLAY\n        ) {\n            return;\n        }\n        if (this.view.skipButton.visible && this.view.skipButton.enabled) {\n            this.view.skipButton.onPointerDown();\n            this.setPopUpSkipBut();\n        }\n        if (\n            (e.code !== undefined && (e.code === 'Space' || e.code === 'Enter' || e.code === 'NumpadEnter')) ||\n            (e.keyCode !== undefined && (e.keyCode === 32 || e.keyCode === 13))\n        ) {\n            if (e.repeat) {\n                return;\n            }\n            if (this.view.spinButton.visible && this.view.spinButton.enabled) {\n                this.view.spinButton.onPointerDown();\n                this.onSpinButtonDown();\n                this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(true);\n            } else if (this.view.stopButton.visible) {\n                this.view.stopButton.onPointerDown();\n                this.onStopButtonDown();\n            }\n        }\n    }\n\n    protected onKeyReleased(e: KeyboardEvent): void {\n        if (\n            e &&\n            this.rootStore.uiStore.SHOW_SETTINGS.value &&\n            ['Space', 'Enter', 'NumpadEnter', 'KeyC', 'KeyV', 'KeyB', 'KeyN', 'KeyM'].indexOf(e.code) > -1\n        ) {\n            this.rootStore.subjects.CLOSE_SETTINGS_POPUP.next();\n            // this.rootStore.uiStore.SHOW_SETTINGS.next(false);\n            this.rootStore.subjects.TAB_OPENED.next(false);\n            return;\n        }\n\n        if (e === null || Core.UI_BLOCKER.value) {\n            return;\n        }\n        if (\n            ['Space', 'Enter', 'NumpadEnter'].indexOf(e.code) > -1 ||\n            (e.keyCode !== undefined && (e.keyCode === 32 || e.keyCode === 13))\n        ) {\n            if (this.rootStore.uiStore.fastSpinMode) {\n                this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                    name: 'stopButton',\n                    actions: 'enabled',\n                    values: true,\n                });\n                // this.view.spinButton.enabled = true;\n            }\n            if (this.view.spinButton.visible && this.view.spinButton.enabled) {\n                this.view.spinButton.onPointerOut();\n                if (this.rootStore.subjects.TAB_OPENED.value) {\n                    this.rootStore.subjects.CLOSE_SETTINGS_POPUP.next();\n                    this.rootStore.subjects.RESET_AUTOPLAY_RESTRICTIONS.next();\n                    return;\n                }\n                if (this.rootStore.uiStore.fastSpinMode) {\n                    this.onSpinButtonUp();\n                    this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(false);\n                    return;\n                }\n                if (this.rootStore.domainStore.SPIN_MODE.value === Features.MANUAL_SPIN) {\n                    this.onSpinClicked();\n                    this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(false);\n                }\n            } else if (this.view.stopButton.visible) {\n                this.view.stopButton.onPointerOut();\n                this.onStopButtonUp();\n                this.onStopClicked();\n            } else if (this.view.skipButton.visible && this.view.skipButton.enabled) {\n                this.view.skipButton.onPointerOut();\n                this.setPopDownSkipBut();\n            }\n        }\n\n        if (['KeyC', 'KeyV', 'KeyB', 'KeyN', 'KeyM'].indexOf(e.code) > -1) {\n            if (this.view.stopButton.visible) {\n                this.view.stopButton.onPointerOut();\n                this.onStopButtonUp();\n                this.onStopClicked();\n            }\n        }\n\n        if (\n            ((e.code !== undefined && e.code === 'ArrowDown') || (e.keyCode !== undefined && e.keyCode === 40)) &&\n            !this.settingsOpened\n        ) {\n            if (\n                this.view.collectSmallButton.visible &&\n                this.view.collectSmallButton.enabled &&\n                (this.rootStore.uiStore.STATE.value === UIState.COLLECT_BEFORE_IDLE ||\n                    this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT)\n            ) {\n                this.onCollectClicked();\n            }\n        }\n    }\n\n    protected getFastSpinTime(): number {\n        let time: number = this.config.autoplayWinTurboTime;\n\n        const betResponse = this.rootStore.domainStore.betResponse;\n        if (betResponse) {\n            if (this.rootStore.isGreatWin) {\n                time = Core.hasFeature(Features.BIG_WIN) ? 0 : this.config.autoplayWinCoinFeatureTime;\n            }\n        }\n        return time;\n    }\n\n    protected getWinAmount(): number {\n        return this.rootStore.uiStore.WIN.value.amount ? this.rootStore.uiStore.WIN.value.amount : 0;\n    }\n\n    protected setBalance(): void {\n        switch (this.rootStore.uiStore.STATE.value) {\n            case UIState.WIN:\n            case UIState.WAITING_FOR_COLLECT:\n                this.rootStore.uiStore.BALANCE.next(\n                    this.rootStore.uiStore.BALANCE.value -\n                        this.rootStore.getBetAmount() +\n                        Number(this.rootStore.uiStore.WIN.value.amount),\n                    // cast to number because server send string and in some cases add the \"WIN.value.amount\" like a string at the end of balance\n                );\n                break;\n            default:\n                this.rootStore.uiStore.BALANCE.next(\n                    this.rootStore.uiStore.BALANCE.value - this.rootStore.getBetAmount(),\n                );\n                break;\n        }\n    }\n\n    protected setSpinState(): void {\n        this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_RESPONSE);\n    }\n\n    private onErrorWithInsifitionsFunds(error: IErrorData): void {\n        const errorCode = error.code.toString();\n        if (errorCode === '4813' || errorCode === '4818') {\n            this.forceStopFastSpinMode();\n        }\n    }\n\n    private forceStopFastSpinMode(): void {\n        this.rootStore.subjects.RESET_KEY_EVENTS.next();\n        this.rootStore.subjects.MODAL_PRESSED.next();\n        this.onFastPlayStopped();\n    }\n}\n","import Core, { FeatureFlags, IOrientation, Timers } from '@egt/core';\nimport { BuyBonusModes } from '@egt/buy-bonus';\nimport {\n    FeatureController,\n    Features,\n    IDenomOptionButtonConfig,\n    ISlotConfiguration,\n    InitialSettings,\n    RootStore,\n    ServerState,\n    SlotComponents,\n    SpinSpeedIndicator,\n    UIState,\n} from '@egt/slot';\nimport {\n    Button,\n    ButtonShapes,\n    ButtonStates,\n    DenominationOptionButton,\n    Text,\n    TextAlign,\n    TextConfig,\n    ViewContainer,\n} from '@egt/ui-lib';\nimport { gsap } from 'gsap';\nimport { Container, DisplayObject, Text as PixiText, Point, SimpleRope, Sprite, TextStyle } from 'pixi.js';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { IUIView } from '../../../IUIView';\nimport { IUIViewComponentConfigurationDefault } from '../configuration/IUIViewComponentConfigurationDefault';\nimport { IBlitzButtonDefault } from '../interfaces/IBlitzButtonDefault';\n\n@injectable()\nexport default class UIViewDefault extends ViewContainer implements IUIView {\n    // Win and Balance value tweens\n    public balanceTween: any;\n    public winValueTween: any;\n    // this container is added to stage outside of this view because background of the UI should be with different z order\n    public mainPanelBackground: Container = new Container();\n\n    // UI Elements - top level.\n    // private mainPanel: ViewContainer;\n    public sidePanel: ViewContainer;\n\n    public spinButton: Button;\n    public spinSpeedButton: Sprite;\n    public instaSpinsButton: IBlitzButtonDefault;\n\n    public instaSpinsButtonMode: Sprite;\n    public spinSpeedButtonDisabled: Sprite;\n    public autoPlayButton: Button;\n    public denominationButton: DenominationOptionButton;\n    public collectSmallButton: Button;\n    public stopButton: Button;\n    public skipButton: Button;\n    public spinSpeedIndicator: SpinSpeedIndicator;\n    // public turboAutoButton: ToggleButton;\n    // public quickAutoButton: ToggleButton;\n    public infinitySign: Sprite;\n    public ON_SPIN_BUTTON_POP_ANIM_COMPLETE = new Subject();\n\n    protected ropeTextTween: any;\n    public spinButtonTween: any;\n    public spinButtonSpecialTween: any;\n    public spinButtonSpecialTweenInterval: any;\n    public spinButtonSpecialTweenTimer: any;\n    protected noActivityTimeoutId: gsap.core.Tween;\n    public spinTimeoutId: gsap.core.Tween;\n\n    public turboModeActiveTimer: boolean = false;\n\n    public ropeText: SimpleRope;\n    public spinBtnBonusText: PixiText;\n\n    protected popButInterval: number = 5000;\n    protected spinSpeedText: Text;\n    protected spinSpeedTextDisabled: Text;\n\n    // Orientation independent constants.\n    protected autoplayCounterVerticalOffset: number = 8;\n\n    protected denominationTitleText: PixiText;\n    protected denominationText: Text;\n    protected denominationButtonWidth: number;\n    protected denominationDefaultFontSize: number;\n\n    protected spinPulseInterval: any;\n    protected skipButtonTween: any;\n    protected stopButtonTween: any;\n    // protected spinButtonWidth: number;\n    // protected spinButtonHeight: number;\n    // protected skipButtonWidth: number;\n    // protected skipButtonHeight: number;\n    // protected stopButtonSizeWidth: number;\n    // protected stopButtonSizeHeight: number;\n\n    // Landscape and portrait mode.\n    protected positions: any;\n\n    // UI elements - side panel.\n    protected autoplayCounter: Text;\n    protected spinButtonAutoplayCounter: Text;\n    protected autoPlayTextSize = 30;\n\n    private elements: Map<string, ViewContainer | DisplayObject> = new Map<string, DisplayObject>();\n    private instaSpins = false;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected config: ISlotConfiguration,\n        @inject('FeatureController') protected featureController: FeatureController,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('UIViewComponentConfiguration') protected componentConfiguration: IUIViewComponentConfigurationDefault,\n    ) {\n        super();\n        this.name = 'UIView';\n        // this.initialRender();\n        this.interactive = false;\n\n        this.init();\n        this.enableUI(true);\n\n        this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onAutoplayBetCounterChanged.bind(this),\n        );\n\n        this.rootStore.subjects.ACTIVE_FEATURE.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n        this.rootStore.subjects.SPIN_BUTTON_SPECIAL_TEXT_VISIBLE.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onSpinButtonSpecialTextVisible.bind(this),\n        );\n\n        this.rootStore.subjects.FEATURE_COMPLETE.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onFeatureComplete.bind(this),\n        );\n\n        this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onBuyBonusModeChanges.bind(this),\n        );\n\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n\n        this.rootStore.uiStore.STATE.pipe(takeUntil(this.DESTROY)).subscribe(this.onStateChanged.bind(this));\n        this.rootStore.subjects.BEFORE_SPIN.pipe(takeUntil(this.DESTROY)).subscribe(this.onBeforeSpin.bind(this));\n\n        Core.LEFT_HAND_MODE.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n        Core.UI_BLOCKER.pipe(takeUntil(this.DESTROY)).subscribe((isUiBlocked) => {\n            if (!this.featureController.isControlInFeature) {\n                this.spinSpeedButton.visible = !isUiBlocked;\n                this.spinSpeedButtonDisabled.visible = isUiBlocked;\n                this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                    name: 'instaSpinsButton',\n\n                    actions: 'enabled',\n\n                    values: !isUiBlocked && this.rootStore.domainStore.SPIN_MODE.value !== Features.AUTO_PLAY,\n                });\n            }\n        });\n\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.setProperties.bind(this),\n        );\n        this.rootStore.subjects.GET_UI_VIEW_COMPONENT_STATE.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.getChildProperty.bind(this),\n        );\n    }\n\n    public destroy(): void {\n        this.destroyIntervals();\n\n        if (this.balanceTween) {\n            this.balanceTween.totalProgress(1);\n            this.balanceTween.kill();\n            this.balanceTween = null;\n        }\n        if (this.winValueTween) {\n            this.winValueTween.totalProgress(1);\n            this.winValueTween.kill();\n            this.winValueTween = null;\n        }\n        this.destroyRopeText();\n        this.killRopeTextTween();\n        if (this.spinButtonTween) {\n            this.spinButtonTween.kill();\n            // @ts-ignore\n            this.spinButtonTween = null;\n        }\n        if (this.spinButtonSpecialTween) {\n            this.spinButtonSpecialTween.kill();\n            // @ts-ignore\n            this.spinButtonSpecialTween = null;\n        }\n        if (this.skipButtonTween) {\n            this.skipButtonTween.kill();\n            // @ts-ignore\n            this.skipButtonTween = null;\n        }\n        if (this.stopButtonTween) {\n            this.stopButtonTween.kill();\n            // @ts-ignore\n            this.stopButtonTween = null;\n        }\n        if (this.spinButton) {\n            this.spinButton.destroy();\n            // @ts-ignore\n            this.spinButton = null;\n        }\n        if (this.spinSpeedButton) {\n            this.spinSpeedButton.destroy();\n            // @ts-ignore\n            this.spinSpeedButton = null;\n        }\n        if (this.stopButton) {\n            this.stopButton.destroy();\n            // @ts-ignore\n            this.stopButton = null;\n        }\n\n        // @ts-ignore\n        this.spinButtonTween = null;\n        // @ts-ignore\n        this.spinButtonSpecialTween = null;\n        // @ts-ignore\n        this.skipButtonTween = null;\n\n        // @ts-ignore\n        this.stopButtonTween = null;\n        // @ts-ignore\n        // this.spinButtonWidth = null;\n        // @ts-ignore\n        this.spinButtonHeight = null;\n        // @ts-ignore\n        this.skipButtonHeight = null;\n        // @ts-ignore\n        this.skipButtonWidth = null;\n\n        if (this.spinSpeedIndicator) {\n            this.spinSpeedIndicator.destroy();\n            // @ts-ignore\n            this.spinSpeedIndicator = null;\n        }\n\n        Timers.clearTimeout(this.spinTimeoutId);\n        if (this.ON_SPIN_BUTTON_POP_ANIM_COMPLETE) {\n            this.ON_SPIN_BUTTON_POP_ANIM_COMPLETE.complete();\n            // @ts-ignore\n            this.ON_SPIN_BUTTON_POP_ANIM_COMPLETE = null;\n        }\n\n        this.elements.clear();\n        // @ts-ignore\n        this.elements = null;\n        super.destroy.apply(this, arguments);\n    }\n\n    public initialRender(): void {\n        //\n    }\n\n    public init(): void {\n        // Create buttons\n        this.instaSpins = Core.hasFeature(Features.BLITZ_PLAY);\n        const backgroundTextures = this.componentConfiguration.spinButtonPosition.useBackgroundTexture\n            ? [Core.assets.getAsset(this.componentConfiguration.spinButtonPosition.backgroundTexture).texture]\n            : undefined;\n        this.spinButton = new Button(\n            Core.assets.getAssets(this.componentConfiguration.spinButtonPosition.textures),\n            backgroundTextures,\n            ButtonShapes.Circle,\n            true,\n        );\n\n        this.spinButton.name = 'spinButton';\n        this.spinButton.pivot.set(this.spinButton.width / 2, this.spinButton.height / 2);\n\n        this.spinSpeedButton = new Sprite();\n\n        this.spinSpeedButton.name = 'spinSpeedButton';\n        this.spinSpeedButton.buttonMode = true;\n        this.spinSpeedButton.interactive = true;\n\n        this.spinSpeedButtonDisabled = new Sprite();\n        this.spinSpeedButtonDisabled.texture = Core.assets.getAsset('svgDisabledSpeed').texture;\n        this.spinSpeedButtonDisabled.name = 'spinSpeedButtonDisabled';\n        this.spinSpeedButtonDisabled.visible = false;\n        this.spinSpeedButtonDisabled.pivot.set(\n            this.spinSpeedButtonDisabled.width / 2,\n            this.spinSpeedButtonDisabled.height / 2,\n        );\n        if (this.componentConfiguration.spinSpeedTextProperties.display && !this.instaSpins) {\n            const spinSpeedTextTextConfig: TextConfig = new TextConfig();\n            const spinSpeedTextTextStyle = new TextStyle(this.componentConfiguration.spinSpeedTextProperties.style);\n            spinSpeedTextTextConfig.bounds.width = this.componentConfiguration.spinSpeedTextProperties.width;\n            spinSpeedTextTextConfig.bounds.height = this.componentConfiguration.spinSpeedTextProperties.height;\n            spinSpeedTextTextConfig.align = TextAlign.CENTER;\n            spinSpeedTextTextConfig.shouldFitInBounds = true;\n            this.spinSpeedText = new Text(\n                spinSpeedTextTextConfig,\n                Core.translator.translate('SPEED'),\n                spinSpeedTextTextStyle,\n            );\n            this.spinSpeedText.name = 'spinSpeedText';\n            this.spinSpeedText.pivot.set(\n                this.componentConfiguration.spinSpeedTextProperties.width / 2,\n                this.componentConfiguration.spinSpeedTextProperties.height / 2,\n            );\n            this.spinSpeedButton.addChild(this.spinSpeedText);\n\n            const spinSpeedTextTextConfigDisabled: TextConfig = new TextConfig();\n            spinSpeedTextTextConfigDisabled.bounds.width =\n                this.componentConfiguration.spinSpeedTextDisabledProperties.width;\n            spinSpeedTextTextConfigDisabled.bounds.height =\n                this.componentConfiguration.spinSpeedTextDisabledProperties.height;\n\n            const spinSpeedTextTextConfigDisabledStyle = new TextStyle(\n                this.componentConfiguration.spinSpeedTextDisabledProperties.style,\n            );\n            spinSpeedTextTextConfigDisabled.bounds.width = 90;\n            spinSpeedTextTextConfigDisabled.bounds.height = 30;\n            spinSpeedTextTextConfigDisabled.align = TextAlign.CENTER;\n            spinSpeedTextTextConfigDisabled.shouldFitInBounds = true;\n            this.spinSpeedTextDisabled = new Text(\n                spinSpeedTextTextConfigDisabled,\n                Core.translator.translate('SPEED'),\n                spinSpeedTextTextConfigDisabledStyle,\n            );\n            this.spinSpeedTextDisabled.name = 'spinSpeedTextDisabled';\n            this.spinSpeedTextDisabled.pivot.set(\n                this.componentConfiguration.spinSpeedTextDisabledProperties.width / 2,\n                this.componentConfiguration.spinSpeedTextDisabledProperties.height / 2,\n            );\n            this.spinSpeedButtonDisabled.addChild(this.spinSpeedTextDisabled);\n        }\n        this.autoPlayButton = new Button(\n            Core.assets.getAssets(this.componentConfiguration.autoPlayButtonPosition.textures),\n            undefined,\n            ButtonShapes.Circle,\n        );\n\n        this.autoPlayButton.name = 'autoPlayButton';\n        this.autoPlayButton.pivot.set(this.autoPlayButton.width / 2, this.autoPlayButton.height / 2);\n        if (!this.settings.autoplay) {\n            this.autoPlayButton.visible = false;\n        }\n        this.stopButton = new Button(\n            Core.assets.getAssets(this.componentConfiguration.stopButtonPosition.textures),\n            undefined,\n            ButtonShapes.Circle,\n        );\n        // this.stopButton = new Button([Core.assets.getAsset('svgAutoPlayStop').texture], undefined, ButtonShapes.Circle);\n\n        this.stopButton.pivot.set(this.stopButton.width / 2, this.stopButton.height / 2);\n        this.stopButton.name = 'stopButton';\n\n        this.skipButton = new Button(\n            [Core.assets.getAsset('svgSpinSkipAnimation').texture],\n            undefined,\n            ButtonShapes.Circle,\n        );\n        this.skipButton.pivot.set(this.skipButton.width / 2, this.skipButton.height / 2);\n        this.skipButton.name = 'skipButton';\n        this.skipButton.visible = false;\n        this.skipButton.enabled = false;\n\n        const denomOptionButtonConfig = this.createDenominationOptionButtonConfig();\n        this.denominationButton = new DenominationOptionButton(denomOptionButtonConfig);\n        this.denominationButton.name = 'denominationButton';\n        this.denominationButton.pivot.set(this.denominationButton.width / 2, this.denominationButton.height / 2);\n\n        const autoplayTextConfig: TextConfig = new TextConfig();\n        const autoplayTextStyle: TextStyle = new TextStyle(this.componentConfiguration.autoplayTextProperties.style);\n\n        // const spinButtonAutoplayTextStyle: TextStyle = new TextStyle(\n        //     this.componentConfiguration.autoplayTextProperties.style,\n        // );\n\n        this.autoplayCounter = new Text(autoplayTextConfig, '0', autoplayTextStyle);\n        this.autoplayCounter.name = 'autoplayCounter';\n        this.infinitySign = new Sprite(Core.assets.getAsset('svgAutoPlayInfinity').texture);\n        this.infinitySign.visible = false;\n        this.infinitySign.pivot.set(this.infinitySign.width / 2, this.infinitySign.height / 2);\n        this.infinitySign.x = this.componentConfiguration.autoplayTextProperties.x;\n        this.infinitySign.y = this.componentConfiguration.autoplayTextProperties.y;\n        /*  this.spinButtonAutoplayCounter = new Text(autoplayTextConfig, '0', spinButtonAutoplayTextStyle);\n        this.spinButtonAutoplayCounter.name = 'spinButtonAutoplayCounter';\n        this.spinButtonAutoplayCounter.visible = false;\n */\n        this.collectSmallButton = new Button(\n            Core.assets.getAssets(this.componentConfiguration.collectSmallButtonPosition.textures),\n            undefined,\n            ButtonShapes.Circle,\n        );\n        this.collectSmallButton.name = 'collectSmallButton';\n        this.collectSmallButton.pivot.set(this.collectSmallButton.width / 2, this.collectSmallButton.height / 2);\n        // this.spinButton.addChild(this.spinButtonAutoplayCounter);\n\n        this.addChild(this.autoPlayButton);\n\n        this.addChild(this.denominationButton);\n        this.addChild(this.collectSmallButton);\n        this.addChild(this.spinButton);\n\n        // container.addChild(this.turboAutoButton);\n        // container.addChild(this.quickAutoButton);\n\n        this.addChild(this.skipButton);\n        if (this.instaSpins) {\n            const instaPadButton = new Sprite();\n\n            instaPadButton.texture = Core.assets.getAsset('blitzBackgroundButton').texture;\n            this.instaSpinsButton = new Sprite() as IBlitzButtonDefault;\n\n            this.instaSpinsButtonMode = new Sprite();\n\n            this.instaSpinsButtonMode.texture = Core.assets.getAsset('blitzSpinButton').texture;\n\n            this.instaSpinsButton.name = 'instaSpinsButton';\n\n            this.instaSpinsButton.buttonMode = true;\n\n            this.instaSpinsButton.interactive = true;\n\n            this.instaSpinsButton.enabled = true;\n\n            this.instaSpinsButton.pivot.set(this.instaSpinsButton.width / 2, 0);\n\n            this.spinSpeedButton.texture = Core.assets.getAsset('blitzNormalSpeed').texture;\n\n            this.spinSpeedButton.pivot.set(this.spinSpeedButton.width - 5, this.spinSpeedButton.height / 2);\n\n            instaPadButton.pivot.set(instaPadButton.width / 2, instaPadButton.height / 2);\n\n            this.instaSpinsButtonMode.pivot.set(0, this.instaSpinsButtonMode.height / 2);\n\n            this.instaSpinsButtonMode.x = -4;\n\n            this.instaSpinsButton.addChild(this.instaSpinsButtonMode);\n            instaPadButton.x = 1;\n            this.instaSpinsButton.addChildAt(instaPadButton, 0);\n\n            this.addChild(this.instaSpinsButton);\n\n            this.spinSpeedButtonDisabled.texture = Core.assets.getAsset('blitzSpeedButtonDisabled').texture;\n\n            this.spinSpeedButtonDisabled.pivot.set(this.spinSpeedButton.width - 5, this.spinSpeedButton.height / 2);\n        } else {\n            this.spinSpeedButton.texture = Core.assets.getAsset('svgNormalSpeed').texture;\n\n            this.spinSpeedButton.pivot.set(this.spinSpeedButton.width / 2, this.spinSpeedButton.height / 2);\n        }\n        if (this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value === 0) {\n            this.addChild(this.spinSpeedButton);\n            this.addChild(this.spinSpeedButtonDisabled);\n\n            // this.ropeText.pivot.set(\n            //     this.ropeText.getLocalBounds().width / 2,\n            //     this.spinButton.getLocalBounds().height / 2,\n            // );\n        } else {\n            this.spinSpeedIndicator = new SpinSpeedIndicator(this.rootStore, this.config);\n            this.spinSpeedIndicator.interactive = true;\n            this.spinSpeedIndicator.name = 'spinSpeedIndicator';\n            this.spinSpeedIndicator.pivot.set(this.spinSpeedIndicator.width / 2, this.spinSpeedIndicator.height / 2);\n            this.addChild(this.spinSpeedIndicator);\n            this.stopButton = new Button(\n                Core.assets.getAssets(this.componentConfiguration.stopButtonPosition.textures),\n                undefined,\n                ButtonShapes.Circle,\n            );\n            this.stopButton.name = 'stopButton';\n        }\n        this.stopButton.addChild(this.autoplayCounter);\n        this.stopButton.addChild(this.infinitySign);\n        this.stopButton.pivot.set(this.stopButton.width / 2, this.stopButton.height / 2);\n        this.addChildAt(this.stopButton, 1);\n\n        // this.spinButtonWidth = this.spinButton.width;\n        // this.spinButtonHeight = this.spinButton.height;\n        // this.skipButtonWidth = this.skipButton.width;\n        // this.skipButtonHeight = this.skipButton.height;\n        // this.stopButtonSizeWidth = this.stopButton.width;\n        // this.stopButtonSizeHeight = this.stopButton.height;\n\n        if (\n            !Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS) &&\n            this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value === 0 &&\n            !Core.flags.isActive(FeatureFlags.HIDE_HOLD_AND_PLAY)\n        ) {\n            this.createRopeText('HOLD FOR FAST PLAY');\n            this.createRopeTextTween();\n        }\n\n        this.setOrientation();\n        this.children.forEach((child) => {\n            this.elements.set(child.name, child);\n        });\n\n        this.elements.set('autoplayCounter', this.autoplayCounter);\n    }\n\n    public enableUI(enableUI: boolean): void {\n        this.interactiveChildren = enableUI;\n    }\n    //// START///////////////////////////////////////\n\n    public pulseSpin(): void {\n        this.destroyIntervals();\n        this.destroyTimers();\n        this.spinPulseInterval = Timers.setInterval(() => {\n            this.spinButtonTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/ui-view/src/egt/modes/default/views/UIViewDefault.ts:511:36\",null]), gsap.to(this.spinButton, {\n                duration: 0.5,\n                width: this.spinButton.width * 1.1,\n                height: this.spinButton.height * 1.1,\n                ease: 'power2.out',\n                repeat: 1,\n                onComplete: () => {\n                    this.resetSpinBtnSize();\n                },\n            }));\n        }, 6500);\n    }\n\n    public rotateSpinBtnArrows(): void {\n        // this.destroyIntervals();\n        // this.destroyTimers();\n        // this.spinPulseInterval = Timers.setInterval(() => {\n\n        this.spinButtonSpecialTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/ui-view/src/egt/modes/default/views/UIViewDefault.ts:529:39\",null]), gsap.timeline({\n            onComplete: () => {\n                this.spinButtonSpecialTween.kill();\n                this.spinButtonSpecialTween = null;\n            },\n        }));\n        this.spinButtonSpecialTween\n            .to(this.spinButton.btnSprite, {\n                duration: 0.2,\n                angle: -20,\n                ease: 'power2.out',\n            })\n            .to(this.spinButton.btnSprite, {\n                duration: 0.4,\n                angle: 20,\n                ease: 'power2.out',\n            })\n            .to(this.spinButton.btnSprite, {\n                duration: 0.2,\n                angle: 0,\n                ease: 'power2.out',\n            });\n    }\n\n    public stopSpinPulsation(): void {\n        this.destroyIntervals();\n        this.destroyTimers();\n        this.resetSpinBtnSize();\n        this.onStopButtonUp();\n    }\n\n    public destroyTimers(): void {\n        Timers.clearTimeout(this.spinTimeoutId);\n    }\n\n    public destroyIntervals(): void {\n        if (this.spinPulseInterval) {\n            Timers.clearInterval(this.spinPulseInterval);\n        }\n    }\n\n    public onStopButtonDown(): void {\n        if (!this.stopButton.visible || !this.stopButton.enabled) {\n            return;\n        }\n        if (this.stopButtonTween) {\n            this.stopButtonTween.kill();\n        }\n        // this.stopButtonTween = gsap.timeline();\n        const scale = this.componentConfiguration.spinButtonPosition.scale || 1;\n        this.stopButton.scale.set(scale);\n        // this.stopButton.width = this.stopButtonSizeWidth;\n        // this.stopButton.height = this.stopButtonSizeHeight;\n        this.stopButtonTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/ui-view/src/egt/modes/default/views/UIViewDefault.ts:582:32\",null]), gsap.to(this.stopButton.scale, {\n            duration: 0.1,\n            x: scale + 0.05,\n            y: scale + 0.05,\n        }));\n        this.resetSpinBtnSize();\n    }\n\n    public onStopButtonUp(): void {\n        if (this.stopButtonTween) {\n            this.stopButtonTween.kill();\n        }\n\n        this.stopButton.scale.set(this.componentConfiguration.spinButtonPosition.scale || 1);\n        this.resetSpinBtnSize();\n    }\n\n    public onSpinButtonDown(): void {\n        this.destroyIntervals();\n        this.destroyTimers();\n        if (\n            this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value > 0 ||\n            Core.flags.isActive(FeatureFlags.HIDE_HOLD_AND_PLAY)\n        ) {\n            return;\n        }\n        const scale = this.componentConfiguration.spinButtonPosition.scale || 1;\n        this.spinTimeoutId = Timers.setTimeout(() => {\n            // this.killRopeTextTween();\n            // this.spinButton.enabled = false;\n            this.spinButtonTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/ui-view/src/egt/modes/default/views/UIViewDefault.ts:612:36\",null]), gsap.timeline({\n                onComplete: () => {\n                    this.ON_SPIN_BUTTON_POP_ANIM_COMPLETE.next();\n                },\n            }));\n            this.spinButtonTween\n                .to(this.spinButton.scale, {\n                    duration: 0.5,\n                    x: scale + 0.2,\n                    y: scale + 0.2,\n                    ease: 'power2.out',\n                })\n                .to(this.spinButton.scale, {\n                    duration: 0.1,\n                    x: scale,\n                    y: scale,\n                    ease: 'power2.out',\n                });\n            this.spinButtonTween.play();\n        }, 500);\n    }\n\n    public onSpinButtonUp(): void {\n        this.spinButton.state = ButtonStates.Normal;\n\n        if (this.turboModeActiveTimer && !this.rootStore.uiStore.turboModeEnabled) {\n            this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_COLLECT);\n            this.turboModeActiveTimer = false;\n        }\n    }\n\n    public resetStopBtnSize(): void {\n        if (this.stopButton) {\n            this.stopButton.scale.set(this.componentConfiguration.spinButtonPosition.scale || 1);\n        }\n    }\n\n    public resetSpinBtnSize(): void {\n        if (this.spinButton) {\n            this.spinButton.scale.set(this.componentConfiguration.spinButtonPosition.scale || 1);\n        }\n    }\n\n    public setPopDownSpinBut(): void {\n        this.stopButton.state = ButtonStates.Normal; // reset the state because some features set it to disabled and it is not updated sometimes\n        const scale = this.componentConfiguration.spinButtonPosition.scale || 1;\n        this.spinButtonTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/ui-view/src/egt/modes/default/views/UIViewDefault.ts:658:32\",null]), gsap.to(this.spinButton.scale, {\n            duration: 0.1,\n            x: scale,\n            y: scale,\n            repeat: 0,\n            onComplete: () => {\n                if (this.ropeText?.alpha === 0) {\n                    this.killRopeTextTween();\n                    this.createRopeTextTween();\n                }\n            },\n        }));\n        if (this.ropeText?.alpha > 0) {\n            this.ropeText.alpha = 1;\n        }\n        if (this.spinBtnBonusText) {\n            this.spinBtnBonusText.alpha = 1;\n        }\n    }\n    public setPopDownSkipBut(): void {\n        const scale = this.componentConfiguration.spinButtonPosition.scale || 1;\n        this.skipButtonTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/ui-view/src/egt/modes/default/views/UIViewDefault.ts:679:32\",null]), gsap.to(this.skipButton.scale, {\n            duration: 0.1,\n            x: scale,\n            y: scale,\n        }));\n    }\n\n    public setPopUpSpinBut(): void {\n        const dynamicScale = (this.componentConfiguration.spinButtonPosition.scale || 1) + 0.05;\n        this.spinButtonTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/ui-view/src/egt/modes/default/views/UIViewDefault.ts:688:32\",null]), gsap.to(this.spinButton.scale, {\n            duration: 0.1,\n            x: dynamicScale,\n            y: dynamicScale,\n        }));\n        if (this.ropeText?.alpha > 0) {\n            this.ropeText.alpha = 0.4;\n        }\n        if (this.spinBtnBonusText?.alpha > 0) {\n            this.spinBtnBonusText.alpha = 0.4;\n        }\n    }\n\n    public setPopUpSkipBut(): void {\n        const dynamicScale = (this.componentConfiguration.spinButtonPosition.scale || 1) + 0.05;\n        this.skipButtonTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/ui-view/src/egt/modes/default/views/UIViewDefault.ts:703:32\",null]), gsap.to(this.skipButton.scale, {\n            duration: 0.1,\n            x: dynamicScale,\n            y: dynamicScale,\n        }));\n    }\n\n    public killRopeTextTween(): void {\n        Timers.clearTimeout(this.noActivityTimeoutId);\n        if (this.ropeTextTween) {\n            this.ropeTextTween.kill();\n            this.ropeTextTween = null;\n            if (this.ropeText) {\n                this.ropeText.alpha = 0;\n            }\n        }\n    }\n\n    public createRopeTextTween(): void {\n        if (!this.ropeText) {\n            return;\n        }\n        const timeOut: number = this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value\n            ? 100\n            : this.popButInterval;\n        this.noActivityTimeoutId = Timers.setTimeout(() => {\n            if (\n                (this.rootStore.uiStore.STATE.value === UIState.IDLE ||\n                    this.rootStore.uiStore.STATE.value === UIState.BONUS_IDLE ||\n                    this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT) &&\n                this.spinButton.enabled\n            ) {\n                this.ropeTextTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/ui-view/src/egt/modes/default/views/UIViewDefault.ts:735:38\",null]), gsap.to(this.ropeText, {\n                    duration: 0.2,\n                    alpha: 1,\n                    ease: 'none',\n                }));\n            }\n        }, timeOut);\n    }\n\n    public onSpinSpeedChanged(speed: number): void {\n        const btnPrefix = this.instaSpins ? 'blitz' : 'svg';\n\n        switch (speed) {\n            case 0:\n                this.spinSpeedButton.texture = Core.assets.getAsset(btnPrefix + 'NormalSpeed').texture;\n\n                break;\n\n            case 1:\n                this.spinSpeedButton.texture = Core.assets.getAsset(btnPrefix + 'QuickSpeed').texture;\n\n                break;\n\n            case 2:\n                this.spinSpeedButton.texture = Core.assets.getAsset(btnPrefix + 'TurboSpeed').texture;\n\n                break;\n        }\n    }\n\n    //// END/////////\n\n    protected destroyRopeText(): void {\n        if (this.ropeText) {\n            this.ropeText.destroy({ children: true });\n            // @ts-ignore\n            this.ropeText = null;\n        }\n    }\n\n    protected setOrientation(_orientation?: IOrientation): void {\n        this.x = this.componentConfiguration.uiViewPosition.x;\n        this.y = this.componentConfiguration.uiViewPosition.y;\n        this.denominationButton.x = this.componentConfiguration.denominationButtonPosition.x;\n        this.denominationButton.y = this.componentConfiguration.denominationButtonPosition.y;\n        this.denominationButton.scale.set(this.componentConfiguration.denominationButtonPosition.scale || 1);\n\n        this.collectSmallButton.x = this.componentConfiguration.collectSmallButtonPosition.x;\n        this.collectSmallButton.y = this.componentConfiguration.collectSmallButtonPosition.y;\n        this.collectSmallButton.scale.set(this.componentConfiguration.collectSmallButtonPosition.scale || 1);\n\n        this.autoPlayButton.x = this.componentConfiguration.autoPlayButtonPosition.x;\n        this.autoPlayButton.y = this.componentConfiguration.autoPlayButtonPosition.y;\n        this.autoPlayButton.scale.set(this.componentConfiguration.autoPlayButtonPosition.scale || 1);\n\n        this.spinSpeedButton.x = this.componentConfiguration.spinSpeedButtonPosition.x;\n        this.spinSpeedButton.y = this.componentConfiguration.spinSpeedButtonPosition.y;\n        this.spinSpeedButton.scale.set(this.componentConfiguration.spinSpeedButtonPosition.scale || 1);\n\n        if (this.instaSpins) {\n            this.instaSpinsButton.x = this.componentConfiguration.blitzPlayButtonPosition\n                ? this.componentConfiguration.blitzPlayButtonPosition.x\n                : this.componentConfiguration.spinSpeedButtonPosition.x;\n            this.instaSpinsButton.y = this.componentConfiguration.blitzPlayButtonPosition\n                ? this.componentConfiguration.blitzPlayButtonPosition.y\n                : this.componentConfiguration.spinSpeedButtonPosition.y;\n            this.instaSpinsButton.scale.set(\n                this.componentConfiguration.blitzPlayButtonPosition\n                    ? this.componentConfiguration.blitzPlayButtonPosition.scale\n                    : this.componentConfiguration.spinSpeedButtonPosition.scale,\n            );\n            this.spinSpeedButton.x = this.instaSpinsButton.x;\n            this.spinSpeedButton.y = this.instaSpinsButton.y;\n        }\n\n        this.spinSpeedButtonDisabled.x = this.spinSpeedButton.x;\n        this.spinSpeedButtonDisabled.y = this.spinSpeedButton.y;\n        this.spinSpeedButtonDisabled.scale.set(this.spinSpeedButton.scale.x);\n\n        this.spinButton.x = this.componentConfiguration.spinButtonPosition.x;\n        this.spinButton.y = this.componentConfiguration.spinButtonPosition.y;\n        this.spinButton.scale.set(this.componentConfiguration.spinButtonPosition.scale || 1);\n\n        this.stopButton.x = this.componentConfiguration.stopButtonPosition.x;\n        this.stopButton.y = this.componentConfiguration.stopButtonPosition.y;\n        this.stopButton.scale.set(this.componentConfiguration.stopButtonPosition.scale || 1);\n\n        this.skipButton.x = this.componentConfiguration.spinButtonPosition.x;\n        this.skipButton.y = this.componentConfiguration.spinButtonPosition.y;\n        this.skipButton.scale.set(this.componentConfiguration.spinButtonPosition.scale || 1);\n\n        if (this.componentConfiguration.spinSpeedTextProperties.display && !this.instaSpins) {\n            // this.spinSpeedText.x = this.componentConfiguration.spinSpeedTextProperties.x;\n            this.spinSpeedText.x = this.spinSpeedButton.texture.width / 2;\n            this.spinSpeedText.y = this.componentConfiguration.spinSpeedTextProperties.y;\n            this.spinSpeedText.config.bounds.width = this.componentConfiguration.spinSpeedTextProperties.width;\n            this.spinSpeedText.config.bounds.height = this.componentConfiguration.spinSpeedTextProperties.height;\n            this.spinSpeedText.style = this.componentConfiguration.spinSpeedTextProperties.style;\n\n            // this.spinSpeedTextDisabled.x = this.componentConfiguration.spinSpeedTextDisabledProperties.x;\n            this.spinSpeedTextDisabled.x = this.spinSpeedButtonDisabled.texture.width / 2;\n            this.spinSpeedTextDisabled.y = this.componentConfiguration.spinSpeedTextDisabledProperties.y;\n            this.spinSpeedTextDisabled.config.bounds.width =\n                this.componentConfiguration.spinSpeedTextDisabledProperties.width;\n            this.spinSpeedTextDisabled.config.bounds.height =\n                this.componentConfiguration.spinSpeedTextDisabledProperties.height;\n            this.spinSpeedTextDisabled.style = this.componentConfiguration.spinSpeedTextDisabledProperties.style;\n        }\n\n        if (this.spinSpeedIndicator) {\n            this.spinSpeedIndicator.x = this.componentConfiguration.minSpinTimeButtonPosition.x;\n            this.spinSpeedIndicator.y = this.componentConfiguration.minSpinTimeButtonPosition.y;\n            this.spinSpeedIndicator.scale.set(this.componentConfiguration.minSpinTimeButtonPosition.scale || 1);\n        }\n    }\n\n    protected createRopeText(ropeString: string): void {\n        const text = new PixiText(\n            Core.translator.translate(ropeString),\n            new TextStyle(this.componentConfiguration.ropeTextProperties.style),\n        );\n\n        text.updateText(true);\n        const radius = this.componentConfiguration.ropeTextProperties.radius;\n        const maxRopePoints = this.componentConfiguration.ropeTextProperties.maxRopePoints;\n        const step = Math.PI / maxRopePoints;\n        const resolution = this.componentConfiguration.ropeTextProperties.resolution;\n        if (resolution > 1) {\n            text.resolution = resolution;\n            text.updateText(true);\n        }\n\n        const spr = new Sprite(text.texture);\n\n        let ropePoints = maxRopePoints - Math.round((text.texture.width / (radius * Math.PI)) * maxRopePoints);\n        ropePoints /= 2;\n\n        const points: any[] = [];\n        for (let i = maxRopePoints - ropePoints; i > ropePoints; i--) {\n            const x = radius * Math.cos(step * i);\n            const y = radius * Math.sin(step * i);\n            points.push(new Point(x, -y));\n        }\n\n        const rope = new SimpleRope(spr.texture, points);\n        rope.alpha = 0;\n        this.ropeText = rope;\n        this.ropeText.name = 'ropeText';\n\n        this.spinButton.addChild(this.ropeText);\n        this.ropeText.x = this.componentConfiguration.ropeTextProperties.x;\n        this.ropeText.y = this.componentConfiguration.ropeTextProperties.y;\n        this.elements.set('ropeText', this.ropeText);\n    }\n\n    protected createDenominationOptionButtonConfig(): IDenomOptionButtonConfig {\n        const texturesArr = this.componentConfiguration.denominationButtonPosition.textures;\n        const config = {\n            currency: this.rootStore.uiStore.currency,\n            denominations: this.rootStore.uiStore.denominations,\n            textures: Core.assets.getAssets(texturesArr),\n            shape: ButtonShapes.Circle,\n            denominationTitleTextStyle:\n                this.componentConfiguration.denominationOptionProperties.denominationTitleTextStyles,\n\n            denominationTextStyle: this.componentConfiguration.denominationOptionProperties.denominationTextStyles,\n\n            denominationTitleTextFontOffset:\n                this.componentConfiguration.denominationOptionProperties.denominationTitleTextFontOffset,\n            denominationTextVerticalOffset:\n                this.componentConfiguration.denominationOptionProperties.denominationTextVerticalOffset || 0,\n            denominationTextHorizontalOffset:\n                this.componentConfiguration.denominationOptionProperties.denominationTextHorizontalOffset || 0,\n            denominationTitleTextVerticalOffset:\n                this.componentConfiguration.denominationOptionProperties.denominationTitleTextVerticalOffset || 0,\n            haveText: this.componentConfiguration.denominationOptionProperties.haveText,\n        };\n        return config;\n    }\n\n    protected onStateChanged(): void {\n        // Features and GiftSpins to handle Buttons states\n        if (this.featureController.isControlInFeature) {\n            return;\n        }\n        switch (this.rootStore.uiStore.STATE.value) {\n            case UIState.IDLE:\n                this.spinButton.visible = true;\n                this.spinButton.enabled = true;\n                this.spinButton.state = ButtonStates.Normal;\n                this.spinSpeedButton.visible = true;\n\n                if (this.instaSpinsButton) {\n                    this.instaSpinsButtonMode.texture = !this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED\n                        .value\n                        ? Core.assets.getAsset('blitzSpinButton').texture\n                        : Core.assets.getAsset('blitzSpinButtonDisabled').texture;\n                    this.instaSpinsButton.visible = true;\n                    this.instaSpinsButton.enabled =\n                        !this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value;\n                }\n\n                if (this.ropeText) {\n                    this.ropeText.visible = true;\n                } else {\n                    // Quick dirty fix, the whole logic about the rope text should be refactored.\n                    // ON-123471\n                    if (\n                        !this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value &&\n                        this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value === 0 &&\n                        !Core.flags.isActive(FeatureFlags.HIDE_HOLD_AND_PLAY)\n                    ) {\n                        this.createRopeText('HOLD FOR FAST PLAY');\n                        this.createRopeTextTween();\n                    }\n                }\n                if (this.spinBtnBonusText) {\n                    this.spinBtnBonusText.alpha = 1;\n                }\n                this.spinSpeedButtonDisabled.visible = false;\n                // this.spinButton.state = ButtonStates.Normal;\n                if (this.settings.autoplay === false) {\n                    this.autoPlayButton.visible = false;\n                    this.autoPlayButton.enabled = false;\n                } else {\n                    this.autoPlayButton.visible = true;\n                    this.autoPlayButton.enabled = true;\n                }\n                // this.turboAutoButton.visible = false;\n                // this.turboAutoButton.enabled = false;\n                // this.quickAutoButton.visible = false;\n                // this.quickAutoButton.enabled = false;\n                this.stopButton.visible = false;\n                this.skipButton.visible = false;\n                //  this.spinButtonAutoplayCounter.visible = false;\n                this.denominationButton.visible = true;\n                this.denominationButton.enabled = true;\n                this.collectSmallButton.visible = false;\n                break;\n            case UIState.BONUS_SUMMARY:\n                this.spinButton.visible = false;\n                this.spinSpeedButton.visible = false;\n                if (this.instaSpinsButton) {\n                    this.instaSpinsButton.visible = false;\n                }\n                this.spinSpeedButtonDisabled.visible = false;\n                this.autoPlayButton.visible = false;\n                // this.turboAutoButton.visible = false;\n                // this.quickAutoButton.visible = false;\n                this.stopButton.visible = false;\n                this.skipButton.visible = false;\n                // this.spinButtonAutoplayCounter.visible = false;\n                this.denominationButton.visible = false;\n                this.collectSmallButton.visible = false;\n                if (this.ropeText) {\n                    this.ropeText.visible = false;\n                }\n\n                break;\n\n            // remove this case if not needed after gift spins protocol changes\n            // applied and gift spins state machine is done\n            case UIState.COLLECT_BEFORE_IDLE:\n                this.spinButton.visible = false;\n                this.autoPlayButton.visible = false;\n                // this.turboAutoButton.visible = false;\n                // this.quickAutoButton.visible = false;\n                this.stopButton.visible = false;\n                this.skipButton.visible = false;\n                // this.spinButtonAutoplayCounter.visible = false;\n                this.denominationButton.visible = false;\n                this.collectSmallButton.visible = false;\n                this.spinSpeedButtonDisabled.visible = false;\n                this.spinSpeedButton.visible = false;\n                if (this.instaSpinsButton) {\n                    this.instaSpinsButton.visible = false;\n                }\n\n                break;\n            case UIState.WAITING_FOR_RESPONSE:\n                this.spinButton.visible =\n                    (this.rootStore.uiStore.fastSpinMode || this.rootStore.uiStore.turboModeEnabled) &&\n                    this.rootStore.domainStore.SPIN_MODE.value === Features.MANUAL_SPIN;\n                this.spinButton.enabled = this.spinButton.visible && !this.rootStore.subjects.KEY_DOWN.value;\n                // this.spinButton.state = ButtonStates.Disabled;\n                //  this.spinButtonAutoplayCounter.visible = false;\n                if (this.settings.autoplay === false) {\n                    this.autoPlayButton.visible = false;\n                    this.autoPlayButton.enabled = false;\n                } else {\n                    this.autoPlayButton.visible = true;\n                    this.autoPlayButton.enabled = false;\n                }\n                if (this.instaSpinsButton) {\n                    this.instaSpinsButtonMode.texture = Core.assets.getAsset('blitzSpinButtonDisabled').texture;\n                    this.instaSpinsButton.visible = true;\n                    this.instaSpinsButton.enabled = false;\n                }\n\n                // this.turboAutoButton.visible = false;\n                // this.quickAutoButton.visible = false;\n                this.stopButton.visible = !this.spinButton.visible;\n                this.stopButton.enabled = this.stopButton.visible;\n                this.spinButton.enabled = true;\n                this.denominationButton.visible = true;\n                this.denominationButton.enabled = false;\n                this.skipButton.visible = false;\n                this.collectSmallButton.visible = false;\n                if (this.ropeText) {\n                    this.ropeText.visible = true;\n                }\n                // if (this.spinBtnBonusText) {\n                //     this.spinBtnBonusText.alpha = 1;\n                // }\n                break;\n            case UIState.WAITING_FOR_RESPONSE_IN_AUTOPLAY:\n                this.spinButton.visible = false;\n                if (this.settings.autoplay === false) {\n                    this.autoPlayButton.visible = false;\n                    this.autoPlayButton.enabled = false;\n                } else {\n                    this.autoPlayButton.visible = true;\n                    this.autoPlayButton.enabled = false;\n                }\n                if (this.instaSpinsButton) {\n                    this.instaSpinsButtonMode.texture = Core.assets.getAsset('blitzSpinButtonDisabled').texture;\n                    this.instaSpinsButton.visible = true;\n                    this.instaSpinsButton.enabled = false;\n                }\n\n                // this.turboAutoButton.visible = true;\n                // this.turboAutoButton.enabled = true;\n                // this.turboAutoButton.selected = this.rootStore.uiStore.turboModeEnabled;\n                // this.quickAutoButton.visible = true;\n                // this.quickAutoButton.enabled = true;\n                // this.quickAutoButton.selected = this.rootStore.subjects.TOGGLE_QUICK_SPIN.value;\n                this.stopButton.visible = true;\n                this.stopButton.enabled = true;\n                this.skipButton.visible = false;\n                // this.spinButtonAutoplayCounter.visible = true;\n                this.autoplayCounter.visible = this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value !== -1;\n                this.denominationButton.visible = true;\n                this.denominationButton.enabled = false;\n                this.collectSmallButton.visible = false;\n                break;\n\n            case UIState.WIN:\n                this.spinButton.visible = true;\n                this.spinButton.enabled = true;\n                this.spinSpeedButton.visible = true;\n                this.spinSpeedButtonDisabled.visible = false;\n                if (this.instaSpinsButton) {\n                    this.instaSpinsButton.visible = true;\n                }\n\n                // this.spinButton.state = ButtonStates.Disabled;\n                this.autoPlayButton.visible = false;\n                this.stopButton.visible = false;\n                this.skipButton.visible = false;\n                this.denominationButton.visible = false;\n                // this.spinButtonAutoplayCounter.visible = false;\n                if (this.ropeText) {\n                    this.ropeText.visible = true;\n                }\n                if (this.spinBtnBonusText) {\n                    this.spinBtnBonusText.alpha = 1;\n                }\n                // this.turboAutoButton.visible = false;\n                // this.turboAutoButton.enabled = false;\n                // this.quickAutoButton.visible = false;\n                // this.quickAutoButton.enabled = false;\n                if (\n                    this.rootStore.domainStore.SPIN_MODE.value === Features.AUTO_PLAY\n                    // ||\n                    // this.rootStore.domainStore.SPIN_MODE.value === Features.FREE_SPINS\n                ) {\n                    this.stopButton.visible = true;\n                    this.stopButton.enabled = true;\n                    // this.spinButtonAutoplayCounter.visible = false;\n                    this.autoplayCounter.visible = this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value !== -1;\n                    this.spinButton.visible = false;\n                    this.denominationButton.visible = true;\n                    this.denominationButton.enabled = false;\n                    if (this.settings.autoplay === false) {\n                        this.autoPlayButton.visible = false;\n                        this.autoPlayButton.enabled = false;\n                    } else {\n                        this.autoPlayButton.visible = true;\n                        this.autoPlayButton.enabled = false;\n                    }\n                    // this.turboAutoButton.visible =\n                    //     this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value !== 0 ? true : false;\n                    // this.turboAutoButton.enabled =\n                    //     this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value !== 0 ? true : false;\n                    // this.quickAutoButton.visible =\n                    //     this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value !== 0 ? true : false;\n                    // this.quickAutoButton.enabled =\n                    //     this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value !== 0 ? true : false;\n                }\n\n                break;\n\n            case UIState.WAITING_FOR_COLLECT:\n                this.stopButton.visible = false; // this.rootStore.uiStore.BANGUP_RUNNING.value;\n                this.stopButton.enabled = this.stopButton.visible;\n                this.spinButton.visible = !this.stopButton.visible;\n                this.skipButton.visible = false;\n                this.spinButton.enabled = this.spinButton.visible;\n                if (this.spinButton.visible) {\n                    this.spinButton.state = ButtonStates.Normal;\n                }\n                if (this.spinBtnBonusText && this.spinButton.visible) {\n                    this.spinBtnBonusText.alpha = 1;\n                }\n                if (this.instaSpinsButton) {\n                    this.instaSpinsButtonMode.texture = !this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED\n                        .value\n                        ? Core.assets.getAsset('blitzSpinButton').texture\n                        : Core.assets.getAsset('blitzSpinButtonDisabled').texture;\n                    this.instaSpinsButton.visible = true;\n                    this.instaSpinsButton.enabled =\n                        !this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value;\n                }\n\n                this.spinSpeedButton.visible = true;\n                this.spinSpeedButtonDisabled.visible = false;\n                // this.spinButton.state = ButtonStates.Normal;\n                this.collectSmallButton.visible = true;\n                this.collectSmallButton.enabled = true;\n                this.denominationButton.visible = false;\n                this.autoPlayButton.visible = false;\n                if (!Core.hasFeature(Features.GAMBLE) && this.settings.autoplay === true) {\n                    this.autoPlayButton.visible = true;\n                    this.autoPlayButton.enabled = false;\n                }\n                // this.turboAutoButton.visible = false;\n                // this.turboAutoButton.enabled = false;\n                // this.quickAutoButton.visible = false;\n                // this.quickAutoButton.enabled = false;\n                break;\n            case UIState.WAITING_FOR_COLLECT_IN_AUTOPLAY:\n                this.stopButton.visible = true;\n                this.stopButton.enabled = true;\n                this.spinButton.visible = false;\n                this.spinSpeedButton.visible = true;\n                this.spinSpeedButtonDisabled.visible = false;\n                this.skipButton.visible = false;\n                if (this.instaSpinsButton) {\n                    this.instaSpinsButton.visible = true;\n                }\n\n                //  this.spinButtonAutoplayCounter.visible = false;\n                this.autoplayCounter.visible = this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value !== -1;\n                // this.turboAutoButton.visible = true;\n                // this.turboAutoButton.enabled = true;\n                // this.quickAutoButton.visible = true;\n                // this.quickAutoButton.enabled = true;\n                break;\n\n            case UIState.WAITING_FOR_STATE_CHANGE:\n                this.spinButton.visible = false;\n                this.spinSpeedButton.visible = false;\n                if (this.instaSpinsButton) {\n                    this.instaSpinsButton.visible = false;\n                }\n\n                this.spinSpeedButtonDisabled.visible = false;\n                this.autoPlayButton.visible = false;\n                this.stopButton.visible = false;\n                this.skipButton.visible = false;\n                //  this.spinButtonAutoplayCounter.visible = false;\n                this.denominationButton.visible = false;\n                this.collectSmallButton.visible = false;\n                break;\n            case UIState.DISABLED:\n            case UIState.SLIDING_BETS:\n                this.spinButton.enabled = false;\n                this.autoPlayButton.enabled = false;\n                this.stopButton.enabled = false;\n                this.skipButton.enabled = false;\n                this.denominationButton.enabled = false;\n                this.collectSmallButton.enabled = false;\n                if (this.instaSpinsButton) {\n                    //this.instaSpinsButtonMode.texture = Core.assets.getAsset('blitzSpinButton').texture;\n                    this.instaSpinsButtonMode.texture = Core.assets.getAsset('blitzSpinButtonDisabled').texture;\n                    this.instaSpinsButton.visible = true;\n                    this.instaSpinsButton.enabled = false;\n                }\n\n                if (this.ropeText) {\n                    this.ropeText.visible = false;\n                }\n                if (this.spinBtnBonusText) {\n                    this.spinBtnBonusText.alpha = 0.4;\n                }\n                break;\n        }\n        if (this.instaSpinsButton) {\n            this.instaSpinsButton.buttonMode = this.instaSpinsButton.enabled;\n        }\n    }\n\n    protected onAutoplayBetCounterChanged(autoplayBetCounter: number): void {\n        if (autoplayBetCounter < 0 || this.rootStore.domainStore.SERVER_STATE.value === ServerState.FREESPIN) {\n            this.autoplayCounter.visible = false;\n            // this.spinButtonAutoplayCounter.visible = false;\n            this.rootStore.uiStore.autoPlayFromSettings = false;\n        } else if (this.rootStore.uiStore.autoPlayFromSettings) {\n            this.autoplayCounter.visible = true;\n            //  this.spinButtonAutoplayCounter.text = autoplayBetCounter.toString();\n            this.autoplayCounter.text = autoplayBetCounter.toString();\n            //  this.autoplayCounter.x = (this.spinButton.width - this.autoplayCounter.width) / 2;\n            //   this.spinButtonAutoplayCounter.x = (this.spinButton.width - this.spinButtonAutoplayCounter.width) / 2;\n        } else {\n            this.autoplayCounter.visible = true;\n            this.autoplayCounter.text = autoplayBetCounter.toString();\n            //  this.autoplayCounter.x = (this.spinButton.width - this.autoplayCounter.width) / 2;\n        }\n        if (autoplayBetCounter < 1) {\n            this.autoplayCounter.visible = false;\n            //  this.spinButtonAutoplayCounter.visible = false;\n        }\n        this.autoplayCounter.pivot.set(this.autoplayCounter.width / 2, this.autoplayCounter.textBounds.height / 2);\n        this.autoplayCounter.x = this.componentConfiguration.autoplayTextProperties.x;\n        this.autoplayCounter.y = this.componentConfiguration.autoplayTextProperties.y;\n    }\n\n    private setProperties(val): void {\n        // do not change autoplay buttton if autoplay is not enabled\n        if (val.name === 'autoPlayButton' && this.settings.autoplay === false) {\n            return;\n        }\n        if (val.name === 'instaSpinsButton' && this.instaSpins) {\n            const actions = Array.isArray(val.actions) ? val.actions : [val.actions];\n            if (actions.indexOf('enabled') > -1) {\n                const enabled = val.values && !this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value;\n                this.instaSpinsButtonMode.texture = enabled\n                    ? Core.assets.getAsset('blitzSpinButton').texture\n                    : Core.assets.getAsset('blitzSpinButtonDisabled').texture;\n                this.instaSpinsButton.enabled = enabled;\n                this.instaSpinsButton.buttonMode = enabled;\n            }\n            if (actions.indexOf('visible') > -1) {\n                this.instaSpinsButton.visible = val.values;\n            }\n            return;\n        }\n\n        const found = this.elements.get(val.name);\n        if (found) {\n            /*  if (val.update !== undefined) {\n                found['sendUpdate'] = val.update;\n            } */\n            if (Array.isArray(val.actions)) {\n                let i = 0;\n                val.actions.forEach((action) => {\n                    found[action] =\n                        val.values[i] !== undefined\n                            ? val.values[i]\n                            : Array.isArray(val.values)\n                              ? val.values[0]\n                              : val.values;\n                    i++;\n                });\n            } else {\n                found[val.actions] = val.values;\n            }\n            // found['sendUpdate'] = true;\n        }\n    }\n\n    private getChildProperty(val): void {\n        if (this[val.name] && val.value === undefined && this[val.name][val.property] !== undefined) {\n            this.rootStore.subjects.GET_UI_VIEW_COMPONENT_STATE.next({\n                name: val.name,\n                value: this[val.name][val.property],\n            });\n        }\n    }\n\n    private onBuyBonusModeChanges(): void {\n        if (!Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS)) {\n            return;\n        }\n        if (this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value) {\n            this.spinButton.setTextures(\n                Core.assets.getAssets(this.componentConfiguration.spinButtonPosition.texturesSpecial),\n            );\n            this.spinButton.setBackgroundTextures([\n                Core.assets.getAsset(this.componentConfiguration.spinButtonPosition.backgroundTextureSpecial).texture,\n            ]);\n            this.stopButton.setTextures(\n                Core.assets.getAssets(this.componentConfiguration.stopButtonPosition.texturesSpecial),\n            );\n            this.spinBtnArrowsRotation();\n            this.skipButton.setTextures(Core.assets.getAssets(['svgSpinSkipAnimationButtonSpecial']));\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'instaSpinsButton',\n                actions: 'enabled',\n                values: false,\n            });\n            // this.ropeText.tint = Number(\n            //     this.componentConfiguration.ropeTextProperties.activeBuyBonusColor.toString().replace('#', '0x'),\n            // );\n            if (this.spinBtnBonusText) {\n                this.spinBtnBonusText.tint = Number(\n                    this.componentConfiguration.ropeTextProperties.activeBuyBonusColor.toString().replace('#', '0x'),\n                );\n            }\n        } else {\n            if (\n                this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value === 0 &&\n                !Core.flags.isActive(FeatureFlags.HIDE_HOLD_AND_PLAY)\n            ) {\n                this.killRopeTextTween();\n                this.destroyRopeText();\n                this.createRopeText('HOLD FOR FAST PLAY');\n                this.createRopeTextTween();\n                // this.ropeText.tint = Number(\n                //     this.componentConfiguration.ropeTextProperties.style.fill.toString().replace('#', '0x'),\n                // );\n                if (this.spinBtnBonusText) {\n                    this.spinBtnBonusText.tint = Number(\n                        this.componentConfiguration.ropeTextProperties.style.fill.toString().replace('#', '0x'),\n                    );\n                }\n            }\n            this.spinButton.setTextures(Core.assets.getAssets(this.componentConfiguration.spinButtonPosition.textures));\n            this.spinButton.setBackgroundTextures([\n                Core.assets.getAsset(this.componentConfiguration.spinButtonPosition.backgroundTexture).texture,\n            ]);\n            this.stopButton.setTextures(Core.assets.getAssets(this.componentConfiguration.stopButtonPosition.textures));\n            this.skipButton.setTextures(Core.assets.getAssets(['svgSpinSkipAnimation']));\n            this.clearSpinBtnArrowAnim();\n            this.destroySpinBtnText();\n\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'instaSpinsButton',\n                actions: 'enabled',\n                values: true,\n            });\n        }\n    }\n\n    private onSpinButtonSpecialTextVisible(visible: boolean): void {\n        this.killRopeTextTween();\n        // this.createRopeTextTween();\n        this.destroyRopeText();\n        // this.createRopeText(_bonusText);\n        if (!this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value) {\n            return;\n        }\n        if (this.spinBtnBonusText) {\n            this.spinBtnBonusText.visible = visible;\n            return;\n        }\n\n        this.spinBtnBonusText = new PixiText(\n            Core.translator.translate('EXTENDED_MULTIPLE.BUY_BONUS.START_BONUS'),\n            new TextStyle(this.componentConfiguration.spinBtnBonusTextStyle.style),\n        );\n        this.spinBtnBonusText.x = this.componentConfiguration.spinBtnBonusTextStyle.x;\n        this.spinBtnBonusText.y = this.componentConfiguration.spinBtnBonusTextStyle.y;\n        this.spinBtnBonusText.pivot.set(this.spinBtnBonusText.width / 2, this.spinBtnBonusText.height / 2);\n        this.spinBtnBonusText.visible = visible;\n        if (this.spinBtnBonusText.width > this.spinButton.width - 70) {\n            this.spinBtnBonusText.scale.set((this.spinButton.width - 70) / this.spinBtnBonusText.width);\n        }\n        this.spinButton.addChild(this.spinBtnBonusText);\n    }\n\n    private destroySpinBtnText(): void {\n        if (this.spinBtnBonusText) {\n            this.spinButton.removeChild(this.spinBtnBonusText);\n            this.spinBtnBonusText.destroy();\n            // @ts-ignore\n            this.spinBtnBonusText = null;\n        }\n    }\n\n    private clearSpinBtnArrowAnim(): void {\n        if (this.spinButtonSpecialTweenTimer) {\n            Timers.clearTimeout(this.spinButtonSpecialTweenTimer);\n            this.spinButtonSpecialTweenTimer = null;\n        }\n        if (this.spinButtonSpecialTweenInterval) {\n            Timers.clearInterval(this.spinButtonSpecialTweenInterval);\n            this.spinButtonSpecialTweenInterval = null;\n        }\n        if (this.spinButtonSpecialTween) {\n            this.spinButtonSpecialTween.totalProgress(1);\n        }\n    }\n\n    private onBeforeSpin(): void {\n        this.clearSpinBtnArrowAnim();\n    }\n\n    private onFeatureComplete(): void {\n        this.clearSpinBtnArrowAnim();\n        this.spinBtnArrowsRotation();\n    }\n\n    private spinBtnArrowsRotation(): void {\n        if (this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value) {\n            this.spinButtonSpecialTweenTimer = Timers.setTimeout(() => {\n                this.rotateSpinBtnArrows();\n            }, 700);\n            this.spinButtonSpecialTweenInterval = Timers.setInterval(() => {\n                this.rotateSpinBtnArrows();\n            }, 10000);\n        }\n    }\n}\n","import {\n    AssetPriority,\n    AssetsCollection,\n    BaseComponentConfiguration,\n    DefaultAssets,\n    DefaultValue,\n    DynamicPositionObject,\n    IPositionPoint,\n} from '@egt/core';\nimport { SlotComponents } from '@egt/slot';\nimport { IMoveUIViewButtonsInFreeSpinsTurtle } from '@egt/ui-view';\nimport { TextStyle } from 'pixi.js';\nimport { IButtonInterfaceSpecialTurtle, IButtonInterfaceTurtle } from '../interfaces/IButtonInterfaceTurtle';\nimport { IDenominationTextInterfaceTurtle } from '../interfaces/IDenominationTextInterfaceTurtle';\nimport { IRopeTextInterfaceTurtle } from '../interfaces/IRopeTextInterfaceTurtle';\nimport { ISpinBtnBonusTextInterfaceTurtle } from '../interfaces/ISpinBtnBonusTextInterfaceTurtle';\nimport { ITextInterfaceTurtle } from '../interfaces/ITextInterfaceTurtle';\nimport { IUIViewComponentConfigurationTurtle } from './IUIViewComponentConfigurationTurtle';\nimport { IBetUiGuardsConfigurationTurtle } from '../interfaces/IBetUiGuardsConfigurationTurtle';\n\nexport default class UIViewComponentConfigurationTurtle extends BaseComponentConfiguration {}\n\nexport function UIViewComponentConfigurationFactoryTurtle(\n    ClassType: typeof UIViewComponentConfigurationTurtle = UIViewComponentConfigurationTurtle,\n): typeof UIViewComponentConfigurationTurtle {\n    class InternalUIViewComponentConfigurationTurtle extends ClassType implements IUIViewComponentConfigurationTurtle {\n        public x: number = 0;\n        public y: number = 0;\n\n        public betUiGuards: IBetUiGuardsConfigurationTurtle = {\n            blockBetSlideWhenActiveComponents: [SlotComponents.DENOMINATION_POPUP, SlotComponents.AUTOPLAY_POPUP],\n            markBetChangeAsFromPopupComponents: [SlotComponents.DENOMINATION_POPUP, SlotComponents.AUTOPLAY_POPUP],\n        };\n\n        @DefaultAssets([\n            {\n                id: 'svgAutoPlay',\n                url: '../assets/components/slot/ui-view/turtle/ui-svg/autoplayButton.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 135, height: 76 },\n                },\n            },\n            {\n                id: 'svgAutoPlayInactive',\n                url: '../assets/components/slot/ui-view/turtle/ui-svg/autoplayButtonDisabled.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 135, height: 76 },\n                },\n            },\n            {\n                id: 'svgAutoPlayStop',\n                url: '../assets/components/slot/ui-view/turtle/ui-svg/autoplayStopButton.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 196, height: 196 },\n                    desktop: { width: 196, height: 196 },\n                },\n            },\n            {\n                id: 'svgChooseBet',\n                url: '../assets/components/slot/ui-view/turtle/ui-svg/chooseBetButton.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 135, height: 76 },\n                },\n            },\n            {\n                id: 'svgChooseBetInactive',\n                url: '../assets/components/slot/ui-view/turtle/ui-svg/chooseBetButtonDisabled.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 135, height: 76 },\n                },\n            },\n            {\n                id: 'svgCollectSmall',\n                url: '../assets/components/slot/ui-view/turtle/ui-svg/collectSmallButton.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 135, height: 76 },\n                },\n            },\n            {\n                id: 'svgCollectSmallDisabled',\n                url: '../assets/components/slot/ui-view/turtle/ui-svg/collectSmallButtonDisabled.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 135, height: 76 },\n                },\n            },\n            {\n                id: 'svgDisabledSpeed',\n                url: '../assets/components/slot/ui-view/turtle/ui-svg/speedButtonDisabled.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 100, height: 57 },\n                },\n            },\n            {\n                id: 'svgNormalSpeed',\n                url: '../assets/components/slot/ui-view/turtle/ui-svg/normalSpeedButton.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 100, height: 57 },\n                },\n            },\n            {\n                id: 'svgQuickSpeed',\n                url: '../assets/components/slot/ui-view/turtle/ui-svg/quickSpeedButton.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 100, height: 57 },\n                },\n            },\n            {\n                id: 'svgTurboSpeed',\n                url: '../assets/components/slot/ui-view/turtle/ui-svg/turboSpeedButton.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 100, height: 57 },\n                },\n            },\n            {\n                id: 'svgSpin',\n                url: '../assets/components/slot/ui-view/turtle/ui-svg/spinButton.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 196, height: 196 },\n                },\n            },\n            {\n                id: 'svgSpinDisabled',\n                url: '../assets/components/slot/ui-view/turtle/ui-svg/spinButtonDisabled.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 196, height: 196 },\n                },\n            },\n            {\n                id: 'svgSpinButtonBackground',\n                url: '../assets/components/slot/ui-view/turtle/ui-svg/spinButtonBackground.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 196, height: 196 },\n                },\n            },\n            {\n                id: 'svgSpinSkipAnimation',\n                url: '../assets/components/slot/ui-view/turtle/ui-svg/spinSkipAnimationButton.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 196, height: 196 },\n                },\n            },\n            {\n                id: 'svgBetMinusBtnActive',\n                url: '../assets/components/slot/ui-view/turtle/ui-svg/betMinusBtnActive.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 76, height: 76 },\n                },\n            },\n            {\n                id: 'svgBetMinusBtnInactive',\n                url: '../assets/components/slot/ui-view/turtle/ui-svg/betMinusBtnInactive.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 76, height: 76 },\n                },\n            },\n            {\n                id: 'svgBetPlusBtnActive',\n                url: '../assets/components/slot/ui-view/turtle/ui-svg/betPlusBtnActive.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 76, height: 76 },\n                },\n            },\n            {\n                id: 'svgBetPlusBtnInactive',\n                url: '../assets/components/slot/ui-view/turtle/ui-svg/betPlusBtnInactive.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 76, height: 76 },\n                },\n            },\n            {\n                id: 'svgAutoPlayInfinity',\n                url: '../assets/components/slot/ui-view/turtle/ui-svg/autoInfinityIcon.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 40, height: 21 },\n                    desktop: { width: 40, height: 21 },\n                },\n            },\n            {\n                id: 'progressSpinTime',\n                url: '../assets/commons/images/ui/spinSpeedIndicator/turtle/progressBarLoading.json',\n                priority: AssetPriority.HIGHEST,\n                type: 'spineAnimation',\n            },\n        ])\n        public assets: AssetsCollection;\n\n        @DefaultValue<IPositionPoint>({\n            defaults: {\n                x: 0,\n                y: 0, //1000\n                width: 90,\n                height: 30,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n                scale: 1,\n                visible: true,\n            },\n            landscape: { x: 0, y: 0, leftHandX: 0 }, //x: 1200, y:0, leftHandX: -10\n        })\n        public uiViewPosition: DynamicPositionObject<IPositionPoint> & IPositionPoint;\n\n        @DefaultValue<IButtonInterfaceTurtle>({\n            defaults: {\n                x: 187,\n                y: 1061,\n                width: 0,\n                height: 0,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n                scale: 1,\n                visible: true,\n                hitPadding: 0,\n                textures: ['svgAutoPlay', 'svgAutoPlay', 'svgAutoPlay', 'svgAutoPlayInactive'],\n            },\n            landscape: { x: 1208, y: 217 },\n            portrait: { x: 206, y: 1227 },\n        })\n        public autoPlayButtonPosition: DynamicPositionObject<IButtonInterfaceTurtle> & IButtonInterfaceTurtle;\n\n        @DefaultValue<IButtonInterfaceTurtle>({\n            defaults: {\n                x: 187,\n                y: 1061,\n                width: 0,\n                height: 0,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n                scale: 1,\n                visible: true,\n                hitPadding: 10,\n                textures: [\n                    'svgBetMinusBtnActive',\n                    'svgBetMinusBtnActive',\n                    'svgBetMinusBtnActive',\n                    'svgBetMinusBtnInactive',\n                ],\n            },\n            landscape: { x: 1140, y: 531 },\n            desktop: { x: 1140, y: 531, hitPadding: 0 },\n            portrait: { x: 237, y: 1120 },\n        })\n        public betMinusBtnPositions: DynamicPositionObject<IButtonInterfaceTurtle> & IButtonInterfaceTurtle;\n\n        @DefaultValue<IButtonInterfaceTurtle>({\n            defaults: {\n                x: 187,\n                y: 1061,\n                width: 0,\n                height: 0,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n                scale: 1,\n                visible: true,\n                hitPadding: 10,\n                textures: [\n                    'svgBetPlusBtnActive',\n                    'svgBetPlusBtnActive',\n                    'svgBetPlusBtnActive',\n                    'svgBetPlusBtnInactive',\n                ],\n            },\n            landscape: { x: 1276, y: 531 },\n            desktop: { x: 1276, y: 531, hitPadding: 0 },\n            portrait: { x: 529, y: 1120 },\n        })\n        public betPlusBtnPositions: DynamicPositionObject<IButtonInterfaceTurtle> & IButtonInterfaceTurtle;\n\n        @DefaultValue<IButtonInterfaceTurtle>({\n            defaults: {\n                x: 578,\n                y: 1061,\n                width: 0,\n                height: 0,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n                scale: 1,\n                visible: true,\n                hitPadding: 0,\n                textures: ['svgChooseBet', 'svgChooseBet', 'svgChooseBet', 'svgChooseBetInactive'],\n            },\n            landscape: { x: 1208, y: 131 },\n            portrait: { x: 557, y: 1227 },\n        })\n        public denominationButtonPosition: DynamicPositionObject<IButtonInterfaceTurtle> & IButtonInterfaceTurtle;\n\n        @DefaultValue<IButtonInterfaceTurtle>({\n            defaults: {\n                x: 578,\n                y: 1061,\n                width: 0,\n                height: 0,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n                scale: 1,\n                visible: true,\n                hitPadding: 0,\n                textures: ['svgCollectSmall', 'svgCollectSmall', 'svgCollectSmall', 'svgCollectSmallDisabled'],\n            },\n            landscape: { x: 1208, y: 131 },\n            portrait: { x: 557, y: 1227 },\n        })\n        public collectSmallButtonPosition: DynamicPositionObject<IButtonInterfaceTurtle> & IButtonInterfaceTurtle;\n\n        @DefaultValue<IPositionPoint>({\n            defaults: {\n                x: 382.5,\n                y: 1190,\n                width: 0,\n                height: 0,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n                scale: 1,\n                visible: true,\n            },\n            landscape: { x: 1208, y: 455 },\n            portrait: { x: 383, y: 1300 },\n        })\n        public spinSpeedButtonPosition: DynamicPositionObject<IPositionPoint> & IPositionPoint;\n\n        @DefaultValue<IPositionPoint>({\n            defaults: {\n                x: 382.5,\n                y: 1190,\n                width: 0,\n                height: 0,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n                scale: 1,\n                visible: true,\n            },\n            landscape: { x: 1208, y: 455 },\n            portrait: { x: 383, y: 1300 },\n        })\n        public blitzPlayButtonPosition: DynamicPositionObject<IPositionPoint> & IPositionPoint;\n\n        @DefaultValue<IPositionPoint>({\n            defaults: {\n                x: 384.5,\n                y: 1191,\n                width: 0,\n                height: 0,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n                scale: 1,\n                visible: true,\n            },\n            landscape: { x: 1208, y: 455 },\n            portrait: { x: 383, y: 1300 },\n        })\n        public minSpinTimeButtonPosition: DynamicPositionObject<IPositionPoint> & IPositionPoint;\n\n        @DefaultValue<IButtonInterfaceSpecialTurtle>({\n            defaults: {\n                x: 382.5,\n                y: 1060.5,\n                width: 0,\n                height: 0,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n                scale: 1,\n                visible: true,\n                textures: ['svgSpin', 'svgSpinDisabled', 'svgSpin', 'svgSpinDisabled'],\n                useBackgroundTexture: true,\n                backgroundTexture: 'svgSpinButtonBackground',\n                texturesSpecial: [\n                    'svgSpinSpecial',\n                    'svgSpinDisabledSpecial',\n                    'svgSpinSpecial',\n                    'svgSpinDisabledSpecial',\n                ],\n                backgroundTextureSpecial: 'svgSpinButtonBackgroundSpecial',\n            },\n            landscape: { x: 1208, y: 350, scale: 0.86734, leftHandX: -10 },\n            portrait: { x: 382, y: 1181 },\n        })\n        public spinButtonPosition: DynamicPositionObject<IButtonInterfaceSpecialTurtle> & IButtonInterfaceSpecialTurtle;\n\n        @DefaultValue<IButtonInterfaceSpecialTurtle>({\n            defaults: {\n                x: 382.5,\n                y: 1060.5,\n                width: 0,\n                height: 0,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n                scale: 1,\n                visible: true,\n                textures: ['svgAutoPlayStop'],\n                useBackgroundTexture: false,\n                backgroundTexture: 'svgSpinButtonBackground',\n                texturesSpecial: [\n                    'svgAutoPlayStopSpecial',\n                    'svgAutoPlayStopSpecial',\n                    'svgAutoPlayStopSpecial',\n                    'svgAutoPlayStopSpecial',\n                ],\n                backgroundTextureSpecial: 'svgSpinButtonBackgroundSpecial',\n            },\n            landscape: { x: 1208, y: 263502, scale: 0.86734, leftHandX: -10 },\n            portrait: { x: 382, y: 1181 },\n        })\n        public stopButtonPosition: DynamicPositionObject<IButtonInterfaceSpecialTurtle> & IButtonInterfaceSpecialTurtle;\n\n        @DefaultValue<ITextInterfaceTurtle>({\n            defaults: {\n                style: new TextStyle({\n                    fontSize: 17,\n                    padding: 0,\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fill: 'white',\n                    lineHeight: 18,\n                }),\n                x: 22,\n                y: 39.5,\n                width: 90,\n                height: 30,\n                display: true,\n                alpha: 1,\n            },\n            landscape: {\n                style: new TextStyle({\n                    fontSize: 17,\n                    padding: 0,\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fill: 'white',\n                    lineHeight: 18,\n                }),\n                y: 39.5,\n                width: 75,\n                height: 30,\n            },\n            portrait: {\n                style: new TextStyle({\n                    fontSize: 17,\n                    padding: 0,\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fill: 'white',\n                    lineHeight: 18,\n                }),\n                y: 39.5,\n                width: 75,\n                height: 30,\n            },\n        })\n        public spinSpeedTextProperties: DynamicPositionObject<ITextInterfaceTurtle> & ITextInterfaceTurtle;\n\n        @DefaultValue<ITextInterfaceTurtle>({\n            defaults: {\n                style: new TextStyle({\n                    fontSize: 17,\n                    padding: 0,\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fill: 'white',\n                    lineHeight: 18,\n                }),\n                x: 22,\n                y: 39.5,\n                width: 90,\n                height: 30,\n                display: true,\n                alpha: 0.6,\n            },\n            landscape: {\n                style: new TextStyle({\n                    fontSize: 17,\n                    padding: 0,\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fill: 'white',\n                    lineHeight: 18,\n                }),\n                y: 39.5,\n                width: 75,\n                height: 30,\n            },\n            portrait: {\n                style: new TextStyle({\n                    fontSize: 17,\n                    padding: 0,\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fill: 'white',\n                    lineHeight: 18,\n                }),\n                y: 39.5,\n                width: 75,\n                height: 30,\n            },\n        })\n        public spinSpeedTextDisabledProperties: DynamicPositionObject<ITextInterfaceTurtle> & ITextInterfaceTurtle;\n\n        @DefaultValue<ITextInterfaceTurtle>({\n            defaults: {\n                style: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    align: 'center',\n                    fontSize: 30,\n                    fill: 0x000000,\n                }),\n                alpha: 1,\n                x: 97,\n                y: 98,\n                width: 220,\n                height: 220,\n                display: true,\n            },\n        })\n        public autoplayTextProperties: DynamicPositionObject<ITextInterfaceTurtle> & ITextInterfaceTurtle;\n\n        @DefaultValue<IRopeTextInterfaceTurtle>({\n            defaults: {\n                style: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fontSize: 20,\n                    fill: '#FFFFFF',\n                }),\n                activeBuyBonusColor: '#FFFFFF',\n                x: 98,\n                y: 98,\n                radius: 81,\n                maxRopePoints: 1400,\n                resolution: 2,\n                visible: true,\n            },\n        })\n        public ropeTextProperties: DynamicPositionObject<IRopeTextInterfaceTurtle> & IRopeTextInterfaceTurtle;\n\n        @DefaultValue<ISpinBtnBonusTextInterfaceTurtle>({\n            defaults: {\n                style: new TextStyle({\n                    fontSize: 30,\n                    fill: '#FFFFFF',\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    lineHeight: 30,\n                    align: 'center',\n                    wordWrap: true,\n                    wordWrapWidth: 130,\n                }),\n                x: 97,\n                y: 97,\n                display: true,\n            },\n        })\n        public spinBtnBonusTextStyle: DynamicPositionObject<ISpinBtnBonusTextInterfaceTurtle> &\n            ISpinBtnBonusTextInterfaceTurtle;\n\n        @DefaultValue<IDenominationTextInterfaceTurtle>({\n            defaults: {\n                denominationTitleTextStyles: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fill: '#FFFFFF',\n                    fontSize: 19,\n                    align: 'center',\n                    lineHeight: 19,\n                }),\n                denominationTextStyles: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fill: '#FFD200',\n                    fontSize: 28,\n                    lineHeight: 30,\n                }),\n                textures: [],\n                denominationTitleTextFontOffset: 20,\n                denominationTextHorizontalOffset: -6,\n                denominationTextVerticalOffset: -6,\n                denominationTitleTextVerticalOffset: -1,\n                haveText: true,\n            },\n        })\n        public denominationOptionProperties: DynamicPositionObject<IDenominationTextInterfaceTurtle> &\n            IDenominationTextInterfaceTurtle;\n\n        @DefaultValue<IMoveUIViewButtonsInFreeSpinsTurtle>({\n            defaults: {\n                move: false,\n                offsetX: 0,\n                offsetY: 0,\n            },\n        })\n        public moveButtonsInFreeSpins: DynamicPositionObject<IMoveUIViewButtonsInFreeSpinsTurtle> &\n            IMoveUIViewButtonsInFreeSpinsTurtle;\n    }\n    return InternalUIViewComponentConfigurationTurtle;\n}\n","import Core, {\n    AnalyticsDispatcher,\n    BaseController,\n    ErrorTypes,\n    IErrorData,\n    Log,\n    PostMessageDispatcher,\n    Timers,\n} from '@egt/core';\nimport { SettingsTab } from '@egt/settings-popup';\nimport {\n    AnalyticsState,\n    BangupActionConsts,\n    BetResponse,\n    FeatureController,\n    Features,\n    ISlotConfiguration,\n    InitialSettings,\n    MessBarTypes,\n    RootStore,\n    SlotComponents,\n    UIState,\n} from '@egt/slot';\nimport { ButtonStates } from '@egt/ui-lib';\nimport { Subject } from 'rxjs';\nimport { filter, takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport UIViewTurtle from '../views/UIViewTurtle';\nimport { AutoplayPopupModes } from '@egt/autoplay-popup';\n\n@injectable()\nexport default class UIViewAutoPlayControllerTurtle extends BaseController {\n    // biome-ignore lint/correctness/noUndeclaredVariables: <explanation>\n    protected timeoutId: gsap.core.Tween;\n    protected fastStopRequested: boolean = false;\n    private stopFromOutside: any;\n    protected reelsStopped: boolean = true;\n    protected waitingBeforeNexSpin: boolean = false;\n\n    private GREAT_WINFINISHED = new Subject();\n\n    constructor(\n        @inject('UIView') protected view: UIViewTurtle,\n        @inject('ISlotConfiguration') protected config: ISlotConfiguration,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('FeatureController') protected featureController: FeatureController,\n    ) {\n        super(undefined);\n        this.stopFromOutside = this.stopAutoplayFromOutside.bind(this);\n        window.addEventListener('message', this.stopFromOutside);\n        this.attachEventListeners();\n    }\n\n    public destroy(): void {\n        window.removeEventListener('message', this.stopFromOutside);\n        // @ts-ignore\n        this.view = null;\n        if (this.rootStore) {\n            // @ts-ignore\n            this.rootStore = null;\n        }\n        if (this.featureController) {\n            // @ts-ignore\n            this.featureController = null;\n        }\n        if (this.config) {\n            // @ts-ignore\n            this.config = null;\n        }\n        if (this.stopFromOutside) {\n            this.stopFromOutside = null;\n        }\n        super.destroy();\n    }\n\n    protected onAutoPlayClicked(): void {\n        if (\n            !this.view.autoPlayButton.enabled &&\n            this.rootStore.uiStore.SELECTED_SETTINGS_TAB.value !== SettingsTab.AUTOPLAY\n        ) {\n            return;\n        }\n        this.rootStore.uiStore.CLEAR_BANG_UP.next();\n        if (\n            this.settings.autoplayRestrictions.mandatory.length === 0 ||\n            !Core.hasComponent(SlotComponents.AUTOPLAY_POPUP, AutoplayPopupModes.DEFAULT)\n        ) {\n            if (!this.settings.autoplayRestrictions.infinityByDefault) {\n                this.rootStore.subjects.TOGGLE_AUTOPLAY_POPUP.next();\n            } else {\n                this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.next(-1);\n                this.rootStore.subjects.CLOSE_AUTOPLAY_POPUP.next();\n                this.rootStore.subjects.START_AUTOPLAY.next(-1);\n            }\n        } else {\n            this.rootStore.uiStore.SELECTED_SETTINGS_TAB.next(SettingsTab.AUTOPLAY);\n            this.rootStore.subjects.OPEN_SETTINGS_POPUP.next();\n            Core.sounds.play('showDenominationsSound');\n        }\n        AnalyticsDispatcher.incrementUserAction('autoplayUsed');\n    }\n\n    protected attachEventListeners(): void {\n        this.view.autoPlayButton.CLICK.pipe(\n            filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n            takeUntil(this.DESTROY),\n        ).subscribe(this.onAutoPlayClicked.bind(this));\n\n        /*   this.view.autoPlayButton.VALUE_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe((e) => {\n            this.rootStore.subjects.GET_UI_VIEW_COMPONENT_STATE.next({\n                name: 'autoPlayButton',\n                property: e.property,\n                value: e.value,\n            });\n        }); */\n\n        this.view.stopButton.CLICK.pipe(\n            filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n            takeUntil(this.DESTROY),\n        ).subscribe(this.onStopClicked.bind(this));\n        this.rootStore.uiStore.COLLECT_CLICKED.chainSubscribe(Features.AUTO_PLAY, this.onCollectClicked.bind(this));\n        this.rootStore.subjects.REELS_STOPPED.chainSubscribe(Features.AUTO_PLAY, this.onReelsStopped.bind(this));\n        this.rootStore.subjects.REELS_STOPPED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.sendAnalyticsData.bind(this),\n        );\n        this.rootStore.subjects.START_AUTOPLAY.pipe(takeUntil(this.DESTROY)).subscribe(this.onAutoPlayStart.bind(this));\n        this.rootStore.subjects.REELS_STOP_ALL.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.fastStopRequested = true;\n        });\n        this.rootStore.subjects.STOP_AUTOPLAY.pipe(takeUntil(this.DESTROY)).subscribe(this.stopAutoplay.bind(this));\n        // this.rootStore.domainStore.BET.pipe(takeUntil(this.DESTROY)).subscribe(this.onBetResponse.bind(this));\n        this.rootStore.subjects.KEY_UP.pipe(takeUntil(this.DESTROY)).subscribe(this.onKeyReleased.bind(this));\n        Core.SHOW_ERROR.pipe(takeUntil(this.DESTROY)).subscribe(this.onShowError.bind(this));\n    }\n\n    protected onReelsStopped(): void {\n        this.reelsStopped = true;\n        const betResponse: BetResponse = this.rootStore.domainStore.betResponse;\n\n        const win = betResponse.bonusGamesTotalWinAmount || betResponse.totalWinAmount;\n        const bet = this.rootStore.getBetAmount();\n        this.rootStore.uiStore.WIN.next({\n            amount: win,\n            action: win > 0 ? BangupActionConsts.BANGUP : BangupActionConsts.SET,\n            feature: Features.AUTO_PLAY,\n        });\n\n        if (this.rootStore.uiStore.turboModeEnabled) {\n            this.rootStore.uiStore.WIN.prevValue.amount = win > 0 ? win : this.rootStore.uiStore.turboModeLastWin;\n        }\n        this.rootStore.uiStore.STATE.next(betResponse.state);\n\n        this.rootStore.uiStore.BALANCE.next(betResponse.balance);\n\n        if (bet > win) {\n            this.rootStore.uiStore.currentTotalLoss += bet - win;\n        }\n\n        this.autoplay();\n\n        this.handleUiStateTransition();\n    }\n\n    protected handleUiStateTransition(): void {\n        if (\n            this.rootStore.domainStore.SPIN_MODE.value === Features.MANUAL_SPIN &&\n            this.rootStore.domainStore.SPIN_MODE.prevValue === Features.MANUAL_SPIN &&\n            this.rootStore.uiStore.STATE.value === UIState.WIN\n        ) {\n            this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_COLLECT);\n        }\n    }\n\n    protected sendAnalyticsData(): void {\n        if (this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value !== 0) {\n            AnalyticsDispatcher.reelsStoppedAnalyticsEvent(\n                Core.configuration.gameKey,\n                AnalyticsState[this.rootStore.domainStore.SERVER_STATE.value],\n                Core.isDesktopMode,\n                Core.configuration.demo,\n                Core.ORIENTATION.value.orientation.toLowerCase(),\n                Core.configuration.mode,\n                Boolean(this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value),\n                this.fastStopRequested,\n                Core.environment.isFullScreen(), // full screen value is not correct when website is zoomed.\n                Core.LEFT_HAND_MODE.value,\n                this.rootStore.subjects.TOGGLE_QUICK_SPIN.value,\n                this.rootStore.subjects.TOGGLE_TURBO_SPIN.value,\n                this.rootStore.domainStore.SPIN_MODE.value,\n                Core.sounds.ON_SOUND_MUTED.value,\n                Core.BATTERY_SAVE_MODE.value,\n                false,\n                this.rootStore.uiStore.SELECTED_BET.value,\n                Core.SELECTED_DENOMINATION.value,\n                Core.PLAYER_BALANCE.value.currency,\n                this.rootStore.settings.factor,\n                Core.hasComponent(SlotComponents.BACKGROUND_SOUND)\n                    ? Core.sounds.ON_BACKGROUND_SOUNDS_MUTED.value || Core.sounds.ON_SOUND_MUTED.value\n                    : undefined,\n            );\n        }\n    }\n\n    protected stopAutoplay(clicked: boolean = false): void {\n        Timers.clearTimeout(this.timeoutId);\n        this.rootStore.subjects.RESET_AUTOPLAY_RESTRICTIONS.next();\n        this.resetAutoState();\n        if (\n            this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_RESPONSE_IN_AUTOPLAY &&\n            !this.rootStore.domainStore.betResponse?.totalWinAmount\n        ) {\n            this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_RESPONSE);\n        }\n\n        if (clicked) {\n            this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_RESPONSE);\n        }\n\n        if (this.waitingBeforeNexSpin && this.reelsStopped && !this.rootStore.domainStore.betResponse?.totalWinAmount) {\n            this.rootStore.uiStore.STATE.next(UIState.IDLE);\n        }\n\n        if (this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value > 0) {\n            this.view.stopButton.state = ButtonStates.Normal;\n        }\n        // set to MANUAL only if no other feature got the SPIN_MODE already\n        if (this.rootStore.domainStore.SPIN_MODE.value === Features.AUTO_PLAY) {\n            if (\n                this.featureController.isInGiftSpins &&\n                this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_RESPONSE_IN_AUTOPLAY\n            ) {\n                return;\n            }\n            this.rootStore.domainStore.SPIN_MODE.next(Features.MANUAL_SPIN);\n            this.rootStore.domainStore.SPIN_MODE.prevValue = Features.MANUAL_SPIN;\n        }\n        // this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(false);\n        ////////////////////////// JP STATS ENABLE DISABLE ///////////////////////////////////////////////////////////////////////////\n        /*   const hasWin = this.rootStore.domainStore.betResponse?.totalWinAmount;\n        if (hasWin > 0) {\n            if (this.rootStore.isGreatWin) {\n                //&& this.rootStore.uiStore.WIN.value.amount === 0 || this.rootStore.uiStore.WIN.value.amount === undefined\n                this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(true);\n                this.rootStore.subjects.FEATURE_COMPLETE.pipe(takeUntil(this.GREAT_WINFINISHED)).subscribe((e) => {\n                    if (\n                        e === Features.COIN ||\n                        e === Features.BIG_WIN ||\n                        e === Features.MAX_WIN ||\n                        e === Features.HIGH_CASH_COIN\n                    ) {\n                        this.GREAT_WINFINISHED.next();\n                        if (this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT) {\n                            this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(false);\n                        }\n                    }\n                });\n            } else {\n                this.rootStore.uiStore.STATE.pipe(take(2)).subscribe(() => {\n                    if (this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT) {\n                        this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(false);\n                    }\n                });\n            }\n        } else {\n            this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(false);\n        } */\n        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    }\n\n    protected autoplay(): void {\n        if (this.shouldStopAutoplay()) {\n            this.stopAutoplay();\n            this.rootStore.uiStore.STATE.next(this.rootStore.uiStore.STATE.value);\n            return;\n        }\n\n        if (this.rootStore.subjects.MAX_WIN_LIMIT_HIT.value) {\n            this.rootStore.subjects.MAX_WIN_LIMIT_MESSAGE.next('MAX_WIN.LIMIT_HIT');\n        }\n\n        const delay = this.rootStore.domainStore.betResponse.totalWinAmount\n            ? this.getAutoplayTime()\n            : this.getDelayOnNonWiningSpin();\n        if (!this.rootStore.domainStore.betResponse.totalWinAmount) {\n            this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_RESPONSE_IN_AUTOPLAY);\n            this.rootStore.subjects.BET_BUTTONS_LABLE_STATE.next('STOP');\n        }\n        if (this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value === -1) {\n            this.view.infinitySign.visible = true;\n        }\n        this.waitingBeforeNexSpin = true;\n        this.timeoutId = Timers.setTimeout(() => {\n            this.waitingBeforeNexSpin = false;\n            this.spin();\n        }, delay);\n    }\n\n    protected getDelayOnNonWiningSpin(): number {\n        return this.config.autoplayDelayOnNonWiningSpin;\n    }\n\n    protected getWinAmount(): number {\n        return this.rootStore.uiStore.WIN.value.amount ? this.rootStore.uiStore.WIN.value.amount : 0;\n    }\n\n    protected spin(): void {\n        this.reelsStopped = false;\n        this.view.killRopeTextTween();\n        if (this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value === 0) {\n            return;\n        }\n        if (\n            this.rootStore.getBetAmount() > this.rootStore.uiStore.BALANCE.value + this.getWinAmount() &&\n            !this.featureController.isInGiftSpins\n        ) {\n            this.rootStore.subjects.SHOW_DIRECT_MESSAGEBAR_TEXT.next([\n                MessBarTypes.INSUFFICIENT,\n                Core.translator.translate('4813').toUpperCase().replace('. (##ERROR_CODE##)', ''),\n            ]);\n            PostMessageDispatcher.balanceTooLow();\n\n            this.rootStore.subjects.CLOSE_AUTOPLAY_POPUP.next();\n            this.rootStore.subjects.STOP_AUTOPLAY.next(false);\n            if (this.getWinAmount() > 0) {\n                this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_COLLECT);\n            } else {\n                this.rootStore.uiStore.STATE.next(UIState.IDLE);\n            }\n            return;\n        }\n        if (this.rootStore.subjects.SHOW_DIRECT_MESSAGEBAR_TEXT.value) {\n            this.rootStore.subjects.SHOW_DIRECT_MESSAGEBAR_TEXT.next(false);\n        }\n        if (\n            this.rootStore.domainStore.SPIN_MODE.value === Features.AUTO_PLAY &&\n            this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value > 0\n        ) {\n            this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.next(this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value - 1);\n        }\n\n        this.rootStore.uiStore.turboModeEnabled = this.rootStore.subjects.TOGGLE_TURBO_SPIN.value;\n\n        this.rootStore.uiStore.quickSpinEnabled = this.rootStore.subjects.TOGGLE_QUICK_SPIN.value;\n\n        this.rootStore.subjects.CLOSE_ALL_POPUPS.next();\n        this.rootStore.subjects.BEFORE_SPIN.next();\n        this.rootStore.subjects.SPIN_STARTED.next();\n        // metrics: mark spin start for session aggregation\n        AnalyticsDispatcher.onSpinStarted({\n            orientation: Core.ORIENTATION.value.orientation,\n            desktop: Core.isDesktopMode,\n            spinMode: this.rootStore.domainStore.SPIN_MODE.value,\n            spinSpeed: this.rootStore.subjects.SPIN_SPEED?.value,\n        });\n\n        if (\n            !this.featureController.isInGiftSpins &&\n            (this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT_IN_AUTOPLAY ||\n                this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT ||\n                this.rootStore.uiStore.STATE.value === UIState.WIN)\n        ) {\n            this.rootStore.uiStore.BALANCE.next(\n                this.rootStore.uiStore.BALANCE.value -\n                    this.rootStore.getBetAmount() +\n                    this.rootStore.uiStore.WIN.value.amount,\n            );\n        } else if (!this.featureController.isInGiftSpins) {\n            this.rootStore.uiStore.BALANCE.next(this.rootStore.uiStore.BALANCE.value - this.rootStore.getBetAmount());\n        }\n\n        this.rootStore.domainStore.bet();\n        this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_RESPONSE_IN_AUTOPLAY);\n        Core.sounds.play('spinSound');\n    }\n\n    protected getAutoplayTime(): number {\n        let time: number = this.config.autoplayWinTime;\n\n        if (this.rootStore.uiStore.turboModeEnabled) {\n            time = this.config.autoplayWinTurboTime;\n        } else if (this.rootStore.uiStore.quickSpinEnabled) {\n            time = this.config.autoplayWinQuickTime;\n        }\n\n        const betResponse = this.rootStore.domainStore.betResponse;\n        if (betResponse) {\n            if (this.rootStore.isGreatWin) {\n                if (Core.hasFeature(Features.BIG_WIN)) {\n                    time = this.config.autoplayWinBigWinTime;\n                } else {\n                    time = this.config.autoplayWinCoinFeatureTime;\n                }\n            }\n        }\n        return time;\n    }\n\n    protected resetAutoState(): void {\n        this.rootStore.uiStore.autoPlayFromSettings = false;\n        this.view.infinitySign.visible = false;\n    }\n\n    protected onStopClicked(): void {\n        if (this.featureController.isFeatureMode || this.rootStore.domainStore.SPIN_MODE.value !== Features.AUTO_PLAY) {\n            this.resetAutoState();\n            return;\n        }\n        Core.sounds.play('stopAutoplaySound');\n        this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.next(0);\n        switch (this.rootStore.uiStore.STATE.value) {\n            case UIState.WAITING_FOR_RESPONSE_IN_AUTOPLAY:\n                if (this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value === 0) {\n                    this.rootStore.subjects.REELS_STOP_ALL.next();\n                }\n                break;\n            case UIState.WAITING_FOR_COLLECT_IN_AUTOPLAY:\n                this.rootStore.uiStore.CLEAR_BANG_UP.next();\n                this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_COLLECT);\n                break;\n            case UIState.WIN:\n                this.rootStore.uiStore.CLEAR_BANG_UP.next();\n                this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_COLLECT);\n                break;\n            default:\n        }\n        this.stopAutoplay(false);\n    }\n\n    /*\n     * In perfect case, we should just check for empty ACTIVE_FEATURE array, but\n     * but in reality, we have some features that do not get cleared from the array,\n     * so a quicker solution is to check for some specific features.\n     * */\n    protected isFeaturePreventingAutoplayToStart(): boolean {\n        let hasFeature = false;\n        const featuresToAvoid = [\n            Features.MYSTERY_JACKPOT,\n            Features.FREE_SPINS,\n            Features.FREE_SPINS_PICK,\n            Features.RESPIN,\n            Features.HOLD_RESPIN,\n            Features.BL_JACKPOT,\n            Features.GAKL_JACKPOT_V1,\n            Features.GAKL_JACKPOT_BASE,\n        ];\n        for (const feat of featuresToAvoid) {\n            hasFeature = this.rootStore.subjects.ACTIVE_FEATURE.value.includes(feat);\n            if (hasFeature) {\n                break;\n            }\n        }\n        return hasFeature;\n    }\n\n    protected onKeyReleased(e: KeyboardEvent): void {\n        if (e === null) {\n            return;\n        }\n        if (\n            e.code !== undefined &&\n            e.code === 'KeyA' &&\n            Core.configuration.mode === 'kiosk' &&\n            !this.isFeaturePreventingAutoplayToStart()\n        ) {\n            if (\n                this.rootStore.domainStore.SPIN_MODE.value !== Features.AUTO_PLAY &&\n                [UIState.IDLE, UIState.BONUS_IDLE, UIState.WAITING_FOR_COLLECT].includes(\n                    this.rootStore.uiStore.STATE.value as UIState,\n                )\n            ) {\n                this.onAutoPlayClicked();\n                return;\n            } else if (this.rootStore.domainStore.SPIN_MODE.value === Features.AUTO_PLAY) {\n                this.onStopClicked();\n                return;\n            }\n        }\n        if (this.rootStore.domainStore.SPIN_MODE.value !== Features.AUTO_PLAY) {\n            return;\n        }\n        if (\n            (e.code !== undefined && (e.code === 'Space' || e.code === 'Enter' || e.code === 'NumpadEnter')) ||\n            (e.keyCode !== undefined && (e.keyCode === 32 || e.keyCode === 13))\n        ) {\n            switch (this.rootStore.uiStore.STATE.value) {\n                case UIState.WAITING_FOR_RESPONSE_IN_AUTOPLAY:\n                    if (this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value === 0) {\n                        this.rootStore.subjects.REELS_STOP_ALL.next();\n                    }\n                    break;\n                case UIState.WIN:\n                    if (this.rootStore.uiStore.BANGUP_RUNNING.value) {\n                        this.rootStore.uiStore.CLEAR_BANG_UP.next();\n                    }\n                    break;\n            }\n        }\n    }\n\n    private stopAutoplayFromOutside(event): void {\n        if (event.data.command === 'stopAutoplay' && Core.configuration.gameKey !== '') {\n            this.stopAutoplay();\n            Log.debug('AUTOPLAY STOPPED', this.constructor.name);\n        }\n    }\n\n    private onAutoPlayStart(numberOfBets): void {\n        // Core.NO_SLEEP_ACTIVE.next(true);\n        // Log.debug('onAutoPlayStart NO SLEEP JS is :', Core.NO_SLEEP_ACTIVE.value);\n        Core.sounds.play('startAutoplaySound');\n        this.startAutoplay(numberOfBets);\n        PostMessageDispatcher.autoPlayStarted(numberOfBets);\n        Log.debug('AUTOPLAY STARTED', this.constructor.name);\n        this.rootStore.uiStore.BACKGROUND_SOUND_PLAY.next({ sound: 'backgroundMusic', ms: 800 });\n    }\n\n    private onCollectClicked(): void {\n        Timers.clearTimeout(this.timeoutId);\n        this.spin();\n    }\n\n    private onShowError(err: IErrorData): void {\n        if (err.type !== ErrorTypes.CONNECTION_ERROR && err.type !== ErrorTypes.CONFIRMATION) {\n            this.stopAutoplay();\n        }\n    }\n\n    private startAutoplay(numberOfBets: number): void {\n        this.rootStore.uiStore.currentTotalLoss = 0;\n        if (this.rootStore.uiStore.allRestrictionsApplied) {\n            this.rootStore.uiStore.balanceStartValue = this.rootStore.uiStore.BALANCE.value + this.getWinAmount();\n        }\n        if (numberOfBets === -1) {\n            this.view.infinitySign.visible = true;\n        }\n        if (this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value > 0) {\n            this.view.stopButton.state = ButtonStates.Disabled;\n        }\n        // this.rootStore.subjects.DISABLE_JACKPOT_STATS.next(true);\n        this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.next(numberOfBets);\n        this.rootStore.domainStore.SPIN_MODE.next(Features.AUTO_PLAY);\n        this.rootStore.domainStore.SPIN_MODE.prevValue = Features.AUTO_PLAY;\n        this.spin();\n    }\n\n    // AUTOPLAY STOP CONDITIONS\n    protected isBalanceDecreasedEnough(): boolean {\n        return (\n            this.rootStore.uiStore.balanceDecreaseValue > 0 &&\n            this.rootStore.uiStore.BALANCE.value + this.rootStore.uiStore.WIN.value.amount <=\n                this.rootStore.uiStore.balanceDecreaseValue &&\n            !this.featureController.isInGiftSpins\n        );\n    }\n\n    protected isBalanceIncreasedEnough(): boolean {\n        return (\n            this.rootStore.uiStore.balanceIncreaseValue > 0 &&\n            this.rootStore.uiStore.BALANCE.value + this.rootStore.uiStore.WIN.value.amount >\n                this.rootStore.uiStore.balanceIncreaseValue\n        );\n    }\n\n    protected isWinLimitReached(): boolean {\n        return (\n            !!this.rootStore.domainStore.betResponse.totalWinAmount &&\n            this.rootStore.uiStore.winLimitValue > 0 &&\n            this.getWinAmount() >= this.rootStore.uiStore.winLimitValue\n        );\n    }\n\n    protected isMaxLossReached(): boolean {\n        const maxLoss = this.rootStore.uiStore.maxTotalLossLimit;\n        const nextLoss =\n            this.rootStore.uiStore.currentTotalLoss +\n            this.rootStore.uiStore.SELECTED_BET.value * Core.SELECTED_DENOMINATION.value * this.rootStore.factor;\n        if (!maxLoss || maxLoss <= 0) {\n            return false;\n        }\n        return nextLoss > maxLoss;\n    }\n\n    protected isAutoPlaySpinsDepleted(): boolean {\n        return this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value === 0;\n    }\n\n    protected shouldStopAutoplay(): boolean {\n        return (\n            this.isBalanceDecreasedEnough() ||\n            this.isBalanceIncreasedEnough() ||\n            this.isWinLimitReached() ||\n            this.isAutoPlaySpinsDepleted() ||\n            this.isMaxLossReached()\n        );\n    }\n}\n","import { BackgroundMusic } from '@egt/background-sound';\nimport Core, { AnalyticsDispatcher, BaseController, PostMessageDispatcher, Timers, UserActionType } from '@egt/core';\nimport { DenominationPopupModes } from '@egt/denomination-popup';\nimport { SettingsTab } from '@egt/settings-popup';\nimport {\n    AnalyticsState,\n    BangupActionConsts,\n    BetResponse,\n    FeatureController,\n    Features,\n    ISlotConfiguration,\n    InitialSettings,\n    MessBarTypes,\n    RootStore,\n    ServerState,\n    SlotComponents,\n    UIState,\n} from '@egt/slot';\nimport { ButtonStates } from '@egt/ui-lib';\nimport { fromEvent } from 'rxjs';\nimport { filter, takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { IUIViewComponentConfigurationTurtle } from '../configuration/IUIViewComponentConfigurationTurtle';\nimport UIViewTurtle from '../views/UIViewTurtle';\n\n@injectable()\nexport default class UIViewManualControllerTurtle extends BaseController {\n    protected gameCanvasContainer: HTMLCanvasElement;\n    // protected noActivityTimeoutId: NodeJS.Timeout;\n    // protected spinTimeoutId: NodeJS.Timeout;\n    // protected spinButton: Button;\n    // protected skipButton: Button;\n    // protected spinSpeedButton: Sprite;\n    // protected stopButton: Button;\n    // protected ropeTextTween: any;\n    // protected spinButtonTween: any;\n    // protected skipButtonTween: any;\n    // protected stopButtonTween: any;\n    // protected spinButtonWidth: number;\n    // protected spinButtonHeight: number;\n    // protected skipButtonWidth: number;\n    // protected skipButtonHeight: number;\n    // protected stopButtonSizeWidth: number;\n    // protected stopButtonSizeHeight: number;\n    // private turboModeActiveTimer: boolean = false;\n\n    protected fastPlayNextSpin: any;\n    protected fastStopRequested: boolean = false;\n    protected settingsOpened: boolean = false;\n\n    private spinButtonOut = false;\n\n    private canClickPlusMinus: boolean = true;\n\n    constructor(\n        @inject('UIView') protected view: UIViewTurtle,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected config: ISlotConfiguration,\n        @inject('FeatureController') protected featureController: FeatureController,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('UIViewComponentConfiguration') protected componentConfiguration: IUIViewComponentConfigurationTurtle,\n    ) {\n        super(view);\n        this.gameCanvasContainer = document.getElementById('app-root') as HTMLCanvasElement;\n        this.attachEventListeners();\n    }\n\n    public destroy(): void {\n        super.destroy.apply(this, arguments);\n    }\n\n    public pulseSpin(value: boolean): void {\n        if (value) {\n            this.view.pulseSpin();\n        } else {\n            this.view.stopSpinPulsation();\n        }\n    }\n\n    protected onDenominationClicked(): void {\n        if (\n            Core.configuration.mode !== 'mobile' &&\n            Core.hasComponent(SlotComponents.DENOMINATION_POPUP, DenominationPopupModes.DEFAULT)\n        ) {\n            this.rootStore.uiStore.CLEAR_BANG_UP.next();\n            this.rootStore.uiStore.SELECTED_SETTINGS_TAB.next(SettingsTab.BET);\n            this.rootStore.subjects.OPEN_SETTINGS_POPUP.next();\n            return;\n        }\n        if (\n            this.rootStore.uiStore.denominations.length > 1 ||\n            !Core.hasComponent(SlotComponents.DENOMINATION_POPUP, DenominationPopupModes.DEFAULT)\n        ) {\n            this.rootStore.uiStore.CLEAR_BANG_UP.next();\n            this.rootStore.subjects.TOGGLE_DENOMINATION_POPUP.next();\n        } else {\n            this.rootStore.uiStore.CLEAR_BANG_UP.next();\n            this.rootStore.subjects.TOGGLE_BET_SETTINGS_POPUP.next();\n            this.rootStore.uiStore.SELECTED_SETTINGS_TAB.next(SettingsTab.BET);\n            // this.rootStore.subjects.OPEN_SETTINGS_POPUP.next();\n        }\n    }\n\n    protected onSpinClicked(): void {\n        if (\n            this.featureController.isFeatureMode ||\n            this.rootStore.domainStore.SPIN_MODE.value !== Features.MANUAL_SPIN ||\n            this.spinButtonOut\n        ) {\n            return;\n        }\n        this.resetSpinBtnSize();\n\n        switch (this.rootStore.uiStore.STATE.value) {\n            case UIState.IDLE:\n            case UIState.BONUS_IDLE:\n            case UIState.WAITING_FOR_COLLECT:\n                this.rootStore.uiStore.CLEAR_BANG_UP.next();\n                Timers.clearTimeout(this.view.spinTimeoutId);\n                this.spin();\n                break;\n        }\n    }\n\n    protected onStopButtonDown(): void {\n        this.view.onStopButtonDown();\n    }\n\n    protected onStopButtonUp(): void {\n        this.view.onStopButtonUp();\n    }\n\n    protected onSpinButtonDown(): void {\n        this.spinButtonOut = false;\n        this.setPopUpSpinBut();\n\n        if (\n            this.featureController.isFeatureMode ||\n            this.rootStore.domainStore.SPIN_MODE.value !== Features.MANUAL_SPIN\n        ) {\n            return;\n        }\n\n        this.resetStopBtnSize();\n        // this.rootStore.uiStore.turboModeDeactivated = false;\n        this.rootStore.subjects.CLOSE_ALL_POPUPS.next();\n        this.rootStore.subjects.CLOSE_BUY_BONUS_POPUP.next();\n\n        if (\n            !this.view.spinButton.enabled ||\n            (this.rootStore.uiStore.STATE.value !== UIState.IDLE &&\n                this.rootStore.uiStore.STATE.value !== UIState.BONUS_IDLE &&\n                this.rootStore.uiStore.STATE.value !== UIState.WAITING_FOR_COLLECT)\n        ) {\n            // this.destroySpinButtonAnimations();\n            this.deactivateTurboMode();\n            return;\n        }\n\n        this.view.onSpinButtonDown();\n\n        // this.rootStore.subjects.JACKPOT_STATS_POINTER.next(false);\n    }\n\n    protected setSpinButtonOutEvent(event): void {\n        const pos = event.data.global;\n        const safeBounds = this.view.spinButton.getBounds();\n        if (!safeBounds.contains(pos.x, pos.y)) {\n            this.setSpinButtonOut(event);\n        }\n    }\n\n    protected setSpinButtonOut(_event): void {\n        this.spinButtonOut = true;\n        this.onSpinButtonUp();\n    }\n\n    protected onSpinButtonUp(): void {\n        if (this.rootStore.subjects.KEY_DOWN.value !== null) {\n            return;\n        }\n        //console.log('BUTTON UP');\n        if (this.view.spinButtonTween) {\n            this.view.spinButtonTween.kill();\n        }\n        this.resetStopBtnSize();\n        this.view.destroyTimers();\n        this.setPopDownSpinBut();\n        this.deactivateTurboMode();\n        this.view.onSpinButtonUp();\n\n        // this.rootStore.subjects.JACKPOT_STATS_POINTER.next(true);\n    }\n\n    protected resetStopBtnSize(): void {\n        this.view.resetStopBtnSize();\n    }\n\n    protected resetSpinBtnSize(): void {\n        this.view.resetSpinBtnSize();\n    }\n\n    // protected resetSkipBtnSize(): void {\n    //     this.view.resetSkipBtnSize();\n    // }\n\n    protected setPopDownSpinBut(): void {\n        this.view.setPopDownSpinBut();\n    }\n\n    protected setPopDownSkipBut(): void {\n        this.view.setPopDownSkipBut();\n    }\n\n    protected destroyTimers(): void {\n        Timers.clearTimeout(this.view.spinTimeoutId);\n    }\n\n    protected onSpinButtonPopAnimComplete(): void {\n        if (\n            this.rootStore.uiStore.STATE.value === UIState.IDLE ||\n            this.rootStore.uiStore.STATE.value === UIState.BONUS_IDLE ||\n            this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT\n        ) {\n            this.rootStore.uiStore.fastSpinMode = true;\n            this.rootStore.uiStore.turboModeLastWin = 0;\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'spinSpeedButton',\n                actions: 'visible',\n                values: false,\n            });\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'spinSpeedButtonDisabled',\n                actions: 'visible',\n                values: true,\n            });\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'instaSpinsButton',\n\n                actions: 'enabled',\n\n                values: false,\n            });\n\n            // this.view.spinSpeedButton.visible = false;\n            // this.view.spinSpeedButtonDisabled.visible = true;\n            this.onSpinClicked();\n        }\n    }\n\n    protected deactivateTurboMode(): void {\n        // if (this.rootStore.uiStore.turboModeEnabled) {\n        //     this.rootStore.uiStore.turboModeDeactivated = this.rootStore.uiStore.WIN.value.amount > 0 ? false : true;\n        // }\n        this.rootStore.uiStore.turboModeEnabled = false;\n        this.rootStore.uiStore.fastSpinMode = false;\n        this.rootStore.uiStore.turboModeLastWin = 0;\n    }\n\n    protected setPopUpSpinBut(): void {\n        this.view.setPopUpSpinBut();\n    }\n\n    protected setPopUpSkipBut(): void {\n        this.view.setPopUpSkipBut();\n    }\n\n    protected killTurboTextTween(): void {\n        this.view.killRopeTextTween();\n    }\n\n    protected onStopClicked(): void {\n        if (\n            (this.featureController.isFeatureMode ||\n                this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value > 0 ||\n                this.rootStore.domainStore.SPIN_MODE.value !== Features.MANUAL_SPIN) &&\n            this.rootStore.domainStore.SERVER_STATE.value !== ServerState.MYSTERY\n        ) {\n            return;\n        }\n        switch (this.rootStore.uiStore.STATE.value) {\n            case UIState.WAITING_FOR_RESPONSE:\n                this.rootStore.subjects.REELS_STOP_ALL.next();\n                // this.rootStore.subjects.MODAL_PRESSED.next();\n                // this.view.stopButton.visible = true;\n                this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                    name: 'spinButton',\n                    actions: 'visible',\n                    values: false,\n                });\n                // this.view.spinButton.visible = false;\n                break;\n            case UIState.WAITING_FOR_COLLECT:\n                this.rootStore.uiStore.CLEAR_BANG_UP.next();\n                // this.rootStore.uiStore.STATE.next(UIState.IDLE);\n                break;\n        }\n    }\n\n    protected onSpinSpeedClicked(): void {\n        const currentSpeed = this.rootStore.subjects.SPIN_SPEED.value;\n        switch (currentSpeed) {\n            case 0:\n                Core.sounds.play('turboQuickOn');\n                this.rootStore.subjects.SPIN_SPEED.next(1);\n                this.rootStore.subjects.TOGGLE_QUICK_SPIN.next(true);\n                PostMessageDispatcher.fastPlayChange('Speed - 2');\n                AnalyticsDispatcher.incrementUserAction(UserActionType.SpeedModeUsed);\n                break;\n            case 1:\n                Core.sounds.play('turboQuickOn2');\n                this.rootStore.subjects.SPIN_SPEED.next(2);\n                this.rootStore.subjects.TOGGLE_QUICK_SPIN.next(false);\n                this.rootStore.uiStore.quickSpinEnabled = false;\n                this.rootStore.subjects.TOGGLE_TURBO_SPIN.next(true);\n                PostMessageDispatcher.fastPlayChange('Speed - 3');\n                AnalyticsDispatcher.incrementUserAction(UserActionType.SpeedModeUsed);\n\n                break;\n            case 2:\n                Core.sounds.play('turboQuickOff');\n                this.rootStore.subjects.SPIN_SPEED.next(0);\n                this.rootStore.subjects.TOGGLE_TURBO_SPIN.next(false);\n                this.rootStore.uiStore.turboModeLastWin = 0;\n                PostMessageDispatcher.fastPlayChange('Speed - 1');\n                AnalyticsDispatcher.incrementUserAction(UserActionType.SpeedModeUsed);\n                break;\n        }\n    }\n\n    protected onSpinSpeedChanged(speed: number): void {\n        this.view.onSpinSpeedChanged(speed);\n    }\n\n    protected attachEventListeners(): void {\n        // this.spinButton = this.view.spinButton;\n        // this.skipButton = this.view.skipButton;\n        // this.spinSpeedButton = this.view.spinSpeedButton;\n        // this.stopButton = this.view.stopButton;\n        // this.spinButtonWidth = this.spinButton.width;\n        // this.spinButtonHeight = this.spinButton.height;\n        // this.skipButtonWidth = this.skipButton.width;\n        // this.skipButtonHeight = this.skipButton.height;\n        // this.stopButtonSizeWidth = this.stopButton.width;\n        // this.stopButtonSizeHeight = this.stopButton.height;\n\n        this.view.stopButton.CLICK.pipe(\n            filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n            takeUntil(this.DESTROY),\n        ).subscribe(this.onStopClicked.bind(this));\n\n        this.view.spinButton.CLICK.pipe(\n            filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n            takeUntil(this.DESTROY),\n        ).subscribe(this.onSpinClicked.bind(this));\n\n        /*  this.view.spinButton.VALUE_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe((e) => {\n            this.rootStore.subjects.GET_UI_VIEW_COMPONENT_STATE.next({\n                name: 'spinButton',\n                property: e.property,\n                value: e.value,\n            });\n        }); */\n        if (this.view.instaSpinsButton) {\n            (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/ui-view/src/egt/modes/turtle/controllers/UIViewManualControllerTurtle.ts:365:13\",(this.view.instaSpinsButton),\"pointertap\"]), fromEvent(this.view.instaSpinsButton, 'pointertap'))\n                .pipe(\n                    filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n\n                    takeUntil(this.DESTROY),\n                )\n                .subscribe(this.onInstaSpinsClicked.bind(this));\n        }\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/ui-view/src/egt/modes/turtle/controllers/UIViewManualControllerTurtle.ts:374:9\",(this.view.spinSpeedButton),\"pointertap\"]), fromEvent(this.view.spinSpeedButton, 'pointertap'))\n            .pipe(\n                filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.onSpinSpeedClicked.bind(this));\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/ui-view/src/egt/modes/turtle/controllers/UIViewManualControllerTurtle.ts:380:9\",(this.view.spinButton),\"pointerdown\"]), fromEvent(this.view.spinButton, 'pointerdown'))\n            .pipe(\n                filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.onSpinButtonDown.bind(this));\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/ui-view/src/egt/modes/turtle/controllers/UIViewManualControllerTurtle.ts:386:9\",(this.view.spinButton),\"pointerup\"]), fromEvent(this.view.spinButton, 'pointerup'))\n            .pipe(\n                filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.onSpinButtonUp.bind(this));\n        fromEvent(this.view.spinButton, 'pointerout')\n            .pipe(\n                filter(\n                    (_x) =>\n                        !this.rootStore.subjects.KEY_DOWN.value &&\n                        (this.rootStore.uiStore.fastSpinMode || this.view.spinButtonTween !== null),\n                ),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.setSpinButtonOut.bind(this));\n\n        fromEvent(this.view.spinButton, 'pointermove')\n            .pipe(\n                filter(\n                    (_x) =>\n                        Core.configuration.mode === 'mobile' &&\n                        this.view.spinButton.state === ButtonStates.Pressed &&\n                        (this.rootStore.uiStore.fastSpinMode || this.view.spinButtonTween !== null),\n                ),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.setSpinButtonOutEvent.bind(this));\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/ui-view/src/egt/modes/turtle/controllers/UIViewManualControllerTurtle.ts:414:9\",(this.view.spinButton),\"pointerupoutside\"]), fromEvent(this.view.spinButton, 'pointerupoutside'))\n            .pipe(\n                filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.setSpinButtonOut.bind(this));\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/ui-view/src/egt/modes/turtle/controllers/UIViewManualControllerTurtle.ts:420:9\",(this.gameCanvasContainer),\"touchend\"]), fromEvent(this.gameCanvasContainer, 'touchend'))\n            .pipe(\n                filter((_x) => this.rootStore.uiStore.fastSpinMode),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.onSpinButtonUp.bind(this));\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/ui-view/src/egt/modes/turtle/controllers/UIViewManualControllerTurtle.ts:426:9\",(this.view.stopButton),\"pointerdown\"]), fromEvent(this.view.stopButton, 'pointerdown'))\n            .pipe(\n                filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.onStopButtonDown.bind(this));\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/ui-view/src/egt/modes/turtle/controllers/UIViewManualControllerTurtle.ts:432:9\",(this.view.stopButton),\"pointerup\"]), fromEvent(this.view.stopButton, 'pointerup'))\n            .pipe(\n                filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.onStopButtonUp.bind(this));\n        fromEvent(this.view.stopButton, 'pointerout')\n            .pipe(\n                filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.onStopButtonUp.bind(this));\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/ui-view/src/egt/modes/turtle/controllers/UIViewManualControllerTurtle.ts:444:9\",(this.view.stopButton),\"pointerupoutside\"]), fromEvent(this.view.stopButton, 'pointerupoutside'))\n            .pipe(\n                filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.onStopButtonUp.bind(this));\n        // PLUS AND MINUS BUTTONS\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/ui-view/src/egt/modes/turtle/controllers/UIViewManualControllerTurtle.ts:451:9\",(this.view.betPlusBtn),\"pointertap\"]), fromEvent(this.view.betPlusBtn, 'pointertap'))\n            .pipe(\n                filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.onIncreaseBet.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/components/slot/ui-view/src/egt/modes/turtle/controllers/UIViewManualControllerTurtle.ts:458:9\",(this.view.betMinusBtn),\"pointertap\"]), fromEvent(this.view.betMinusBtn, 'pointertap'))\n            .pipe(\n                filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.onDecreaseBet.bind(this));\n\n        fromEvent(window, 'blur')\n            .pipe(\n                filter((_x) => this.rootStore.uiStore.fastSpinMode),\n                takeUntil(this.DESTROY),\n            )\n            .subscribe(this.onSpinButtonUp.bind(this));\n\n        this.view.denominationButton.CLICK.pipe(\n            filter(\n                (_x) =>\n                    !this.rootStore.subjects.KEY_DOWN.value && this.rootStore.subjects.SHOW_JP_STATS.value.type === -1,\n            ),\n            takeUntil(this.DESTROY),\n        ).subscribe(this.onDenominationClicked.bind(this));\n\n        this.rootStore.uiStore.COLLECT_CLICKED.chainSubscribe(Features.MANUAL_SPIN, this.onCollectClicked.bind(this));\n\n        this.view.collectSmallButton.CLICK.pipe(\n            filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n            takeUntil(this.DESTROY),\n        ).subscribe(this.onCollectClicked.bind(this));\n\n        this.view.ON_SPIN_BUTTON_POP_ANIM_COMPLETE.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onSpinButtonPopAnimComplete.bind(this),\n        );\n\n        this.rootStore.subjects.REELS_STOPPED.chainSubscribe(Features.MANUAL_SPIN, this.onReelsStopped.bind(this));\n        this.rootStore.subjects.REELS_STOPPED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.sendAnalyticsData.bind(this),\n        );\n\n        this.rootStore.subjects.SEND_DEMO_CHOICE.pipe(takeUntil(this.DESTROY)).subscribe(this.spin.bind(this));\n\n        this.rootStore.subjects.REELS_STOP_ALL.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.fastStopRequested = true;\n        });\n        this.rootStore.subjects.START_MANUAL_SPIN.pipe(takeUntil(this.DESTROY)).subscribe(this.spin.bind(this));\n\n        this.rootStore.subjects.PULSATE_SPIN_BTN.pipe(takeUntil(this.DESTROY)).subscribe(this.pulseSpin.bind(this));\n\n        this.rootStore.subjects.STOP_PULSATE_SPIN_BTN.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.destroyTimers.bind(this),\n            this.view.destroyIntervals.bind(this),\n        );\n\n        this.rootStore.domainStore.BET.pipe(takeUntil(this.DESTROY)).subscribe(this.onBetResponse.bind(this));\n\n        this.rootStore.uiStore.STATE.pipe(takeUntil(this.DESTROY)).subscribe(this.onStateChanged.bind(this));\n        Core.TOUCH_CANCEL.pipe(takeUntil(this.DESTROY)).subscribe(this.onSpinButtonUp.bind(this));\n        this.rootStore.subjects.SPIN_SPEED.pipe(takeUntil(this.DESTROY)).subscribe(this.onSpinSpeedChanged.bind(this));\n        this.rootStore.subjects.STOP_FAST_PLAY.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onFastPlayStopped.bind(this),\n        );\n        this.rootStore.subjects.SPIN_SPEED_EXTERNAL.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onSpinSpeedClicked.bind(this),\n        );\n        this.rootStore.subjects.SETTINGS_POPUP_CLOSED.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.settingsOpened = false;\n        });\n\n        this.rootStore.subjects.SETTINGS_POPUP_OPENED.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.settingsOpened = true;\n        });\n\n        this.rootStore.uiStore.SELECTED_BET.pipe(takeUntil(this.DESTROY)).subscribe(this.onBetChanged.bind(this));\n        Core.SELECTED_DENOMINATION.pipe(takeUntil(this.DESTROY)).subscribe(this.onBetChanged.bind(this));\n\n        // for desktop - after exit fullscreen all pressed keys are lost (for chrome)\n        // https://jira.egt-digital.com/browse/ON-5392\n        if (Core.configuration.mode !== 'mobile') {\n            this.rootStore.subjects.KEY_UP.pipe(takeUntil(this.DESTROY)).subscribe(this.onKeyReleased.bind(this));\n\n            this.rootStore.subjects.KEY_DOWN.pipe(takeUntil(this.DESTROY)).subscribe(this.onKeyPressed.bind(this));\n\n            // when we are in iframe document fullscreenchange is not fired\n            // then we check resize event and size of the window / screen\n            if (Core.environment.inIframe()) {\n                Core.STAGE_RESIZE_END.pipe(\n                    filter((_x) => this.rootStore.uiStore.fastSpinMode),\n                    takeUntil(this.DESTROY),\n                ).subscribe((_e) => {\n                    // sometimes there are difference with 1px between screen.width and window.innerWidth in FS\n                    const isFullScreen = Math.abs(screen.width - window.innerWidth) < 2;\n                    // this is leave fullscrren mode in iframe\n                    if (!isFullScreen) {\n                        this.rootStore.subjects.RESET_KEY_EVENTS.next();\n                        this.rootStore.subjects.MODAL_PRESSED.next();\n                        this.onFastPlayStopped();\n                    }\n                });\n            }\n\n            fromEvent(document, 'fullscreenchange')\n                .pipe(\n                    filter((_x) => this.rootStore.uiStore.fastSpinMode),\n                    takeUntil(this.DESTROY),\n                )\n                .subscribe((_e) => {\n                    if (!Core.environment.isFullScreen()) {\n                        this.rootStore.subjects.RESET_KEY_EVENTS.next();\n                        this.rootStore.subjects.MODAL_PRESSED.next();\n                        this.onFastPlayStopped();\n                    }\n                });\n        } else {\n            Core.ORIENTATION.pipe(\n                filter((_x) => this.rootStore.uiStore.fastSpinMode),\n                takeUntil(this.DESTROY),\n            ).subscribe((_e) => {\n                this.onSpinButtonUp();\n                this.onFastPlayStopped();\n                const te = new TouchEvent('touchend');\n                window.dispatchEvent(te);\n            });\n        }\n        //  this.rootStore.uiStore.BANGUP_RUNNING.pipe(takeUntil(this.DESTROY)).subscribe(this.onBangupRunning.bind(this));\n    }\n\n    // WHY DO WE NEED THIS TO GAIN CONTROL OVER THE SPIN MODE - WE MAY BE IN FEATURE AND IT MAY BE STILL NOT FINISHED\n    // NEED REWORK\n    protected onBetResponse(): void {\n        this.fastStopRequested = false;\n        const betResponse: BetResponse = this.rootStore.domainStore.betResponse;\n        if (betResponse.state === ServerState.WIN || betResponse.state === ServerState.IDLE) {\n            if (\n                this.rootStore.domainStore.SPIN_MODE.prevValue === Features.MANUAL_SPIN &&\n                this.rootStore.domainStore.SPIN_MODE.value !== Features.FREE_SPINS &&\n                this.rootStore.domainStore.SPIN_MODE.value !== Features.RESPIN &&\n                this.rootStore.domainStore.SPIN_MODE.value !== Features.HIGH_CASH_FREE_SPINS &&\n                this.rootStore.domainStore.SPIN_MODE.value !== Features.BASE_FREE_SPINS &&\n                this.rootStore.domainStore.SPIN_MODE.value !== Features.GAKL_FEATURE_CHANCE\n            ) {\n                // Check if SPINMODE is Freespin because when you restore on last freespin round not to gain the SPIN_MODE\n                this.rootStore.domainStore.SPIN_MODE.next(Features.MANUAL_SPIN);\n            }\n        }\n    }\n\n    protected onCollectClicked(): void {\n        this.view.destroyTimers();\n        this.rootStore.uiStore.STATE.next(UIState.DISABLED);\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'collectSmallButton',\n            actions: 'enabled',\n            values: false,\n        });\n        // this.view.find('collectSmallButton').enabled = false;\n        this.rootStore.domainStore.collect();\n        this.rootStore.uiStore.COLLECT_CHANGED.next();\n    }\n    protected onInstaSpinsClicked(): void {\n        if (this.view.instaSpinsButton.enabled) {\n            Core.sounds.play('bpEnterBlitzPlay');\n\n            Core.BLITZ_PLAY_OPEN.next(true);\n        }\n    }\n\n    protected spin(): void {\n        if (this.fastPlayNextSpin) {\n            Timers.clearTimeout(this.fastPlayNextSpin);\n        }\n        this.view.killRopeTextTween();\n        this.fastStopRequested = false;\n        // this.rootStore.uiStore.SHOW_SETTINGS.next(false);\n        this.rootStore.subjects.CLOSE_ALL_POPUPS.next();\n        this.rootStore.subjects.CLOSE_BUY_BONUS_POPUP.next();\n        this.rootStore.uiStore.turboModeEnabled =\n            this.rootStore.subjects.TOGGLE_TURBO_SPIN.value || this.rootStore.uiStore.fastSpinMode;\n        this.rootStore.uiStore.quickSpinEnabled =\n            this.rootStore.subjects.TOGGLE_QUICK_SPIN.value && !this.rootStore.uiStore.fastSpinMode;\n        if (\n            this.rootStore.getBetAmount() > this.rootStore.uiStore.BALANCE.value + this.getWinAmount() &&\n            !this.featureController.isInGiftSpins\n        ) {\n            if (\n                this.rootStore.uiStore.WIN.value.amount === 0 ||\n                this.rootStore.uiStore.WIN.value.amount === undefined\n            ) {\n                this.rootStore.uiStore.STATE.next(UIState.IDLE);\n            } else {\n                this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_COLLECT);\n            }\n            this.rootStore.subjects.RESET_KEY_EVENTS.next();\n            this.setPopDownSpinBut();\n            this.deactivateTurboMode();\n\n            // this.rootStore.uiStore.STATE.next(UIState.BONUS_IDLE);\n            this.rootStore.subjects.SHOW_DIRECT_MESSAGEBAR_TEXT.next([\n                MessBarTypes.INSUFFICIENT,\n                Core.translator.translate('4813').toUpperCase().replace('. (##ERROR_CODE##)', ''),\n            ]);\n            PostMessageDispatcher.balanceTooLow();\n            if (this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT) {\n                this.onCollectClicked();\n            }\n\n            return;\n        }\n        if (this.rootStore.subjects.SHOW_DIRECT_MESSAGEBAR_TEXT.value) {\n            this.rootStore.subjects.SHOW_DIRECT_MESSAGEBAR_TEXT.next(false);\n        }\n        this.rootStore.subjects.BEFORE_SPIN.next();\n        this.rootStore.subjects.SPIN_STARTED.next();\n        // metrics: mark spin start for session aggregation\n        AnalyticsDispatcher.onSpinStarted({\n            orientation: Core.ORIENTATION.value.orientation,\n            desktop: Core.isDesktopMode,\n            spinMode: this.rootStore.domainStore.SPIN_MODE.value,\n            spinSpeed: this.rootStore.subjects.SPIN_SPEED?.value,\n        });\n        if (!this.featureController.isInGiftSpins) {\n            this.setBalance();\n        }\n        this.rootStore.domainStore.bet();\n        this.setSpinState();\n        Core.sounds.play('spinSound');\n        // Core.sounds.play(\n        //     Core.sounds.hasSound('fastSpinSound') && this.rootStore.uiStore.turboModeEnabled\n        //         ? 'fastSpinSound'\n        //         : 'spinSound',\n        // );\n        this.killTurboTextTween();\n\n        if (Core.hasComponent(SlotComponents.MULTILAYERED_BG_SOUND)) {\n            if (\n                Core.sounds.getAllSounds().some((sound) => sound.id === 'backgroundSounds') &&\n                Core.sounds.getNowPlayingSounds().includes('backgroundMusic')\n            ) {\n                const currentBackgroundSound: BackgroundMusic = this.rootStore.subjects.BG_SOUND_LAYER.value;\n                this.rootStore.uiStore.BACKGROUND_SOUND_PLAY.next({ sound: currentBackgroundSound, ms: 800 });\n            }\n        } else {\n            this.rootStore.uiStore.BACKGROUND_SOUND_PLAY.next({ sound: 'backgroundMusic', ms: 800 });\n        }\n    }\n\n    protected onReelsStopped(): void {\n        const betResponse: BetResponse = this.rootStore.domainStore.betResponse;\n        const win = this.calculateWin(betResponse);\n\n        if (this.rootStore.uiStore.fastSpinMode) {\n            this.handleFastSpinMode(win, betResponse);\n        } else {\n            this.handleNormalSpinMode(win, betResponse);\n        }\n    }\n\n    protected calculateWin(betResponse: BetResponse): number {\n        return betResponse.bonusGamesTotalWinAmount || betResponse.totalWinAmount;\n    }\n\n    protected handleFastSpinMode(win: number, betResponse: BetResponse): void {\n        if (this.rootStore.subjects.MAX_WIN_LIMIT_HIT.value) {\n            this.rootStore.subjects.MAX_WIN_LIMIT_MESSAGE.next('MAX_WIN.LIMIT_HIT');\n        }\n\n        this.updateWinState(win, Features.MANUAL_SPIN);\n\n        if (betResponse.entries.length > 0) {\n            this.activateTurboMode(betResponse);\n        } else {\n            this.spin();\n            this.updateBalance(betResponse.balance);\n        }\n    }\n\n    protected activateTurboMode(betResponse: BetResponse): void {\n        this.view.turboModeActiveTimer = true;\n        this.fastPlayNextSpin = Timers.setTimeout(() => {\n            this.view.turboModeActiveTimer = false;\n            if (this.rootStore.uiStore.fastSpinMode) {\n                this.spin();\n                this.updateBalance(betResponse.balance);\n            }\n        }, this.getFastSpinTime());\n    }\n\n    protected handleNormalSpinMode(win: number, betResponse: BetResponse): void {\n        this.updateWinState(win, Features.MANUAL_SPIN);\n\n        if (win > 0 && !this.rootStore.isUnfinishedCampaign) {\n            this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_COLLECT);\n        } else {\n            this.rootStore.uiStore.STATE.next(betResponse.state);\n        }\n    }\n\n    protected updateWinState(win: number, feature: Features): void {\n        const action = win > 0 ? BangupActionConsts.BANGUP : BangupActionConsts.SET;\n        this.rootStore.uiStore.WIN.next({ amount: win, action, feature });\n    }\n\n    protected updateBalance(balance: number): void {\n        this.rootStore.uiStore.BALANCE.next(balance);\n    }\n\n    protected sendAnalyticsData(): void {\n        if (this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value === 0) {\n            AnalyticsDispatcher.reelsStoppedAnalyticsEvent(\n                Core.configuration.gameKey,\n                AnalyticsState[this.rootStore.domainStore.SERVER_STATE.value],\n                Core.isDesktopMode,\n                Core.configuration.demo,\n                Core.ORIENTATION.value.orientation.toLowerCase(),\n                Core.configuration.mode,\n                Boolean(this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value),\n                this.fastStopRequested,\n                Core.environment.isFullScreen(), // full screen value is not correct when website is zoomed.\n                Core.LEFT_HAND_MODE.value,\n                this.rootStore.subjects.TOGGLE_QUICK_SPIN.value,\n                this.rootStore.subjects.TOGGLE_TURBO_SPIN.value,\n                this.rootStore.domainStore.SPIN_MODE.value,\n                Core.sounds.ON_SOUND_MUTED.value,\n                Core.BATTERY_SAVE_MODE.value,\n                false,\n                this.rootStore.uiStore.SELECTED_BET.value,\n                Core.SELECTED_DENOMINATION.value,\n                Core.PLAYER_BALANCE.value.currency,\n                this.rootStore.settings.factor,\n                Core.hasComponent(SlotComponents.BACKGROUND_SOUND)\n                    ? Core.sounds.ON_BACKGROUND_SOUNDS_MUTED.value || Core.sounds.ON_SOUND_MUTED.value\n                    : undefined,\n            );\n        }\n    }\n\n    /*  private onBangupRunning(): void {\n        if (\n            this.featureController.isFeatureMode ||\n            this.rootStore.domainStore.SPIN_MODE.value !== Features.MANUAL_SPIN\n        ) {\n            return;\n        }\n\n        if (!this.rootStore.uiStore.BANGUP_RUNNING.value) {\n            this.view.stopButton.visible = false;\n            this.spinButton.visible = true;\n            this.spinButton.enabled = true;\n            this.spinButton.state = ButtonStates.Normal;\n        }\n    } */\n\n    protected onStateChanged(): void {\n        this.killTurboTextTween();\n        this.resetSpinBtnSize();\n        this.resetStopBtnSize();\n        if (\n            (this.rootStore.uiStore.STATE.value === UIState.IDLE ||\n                this.rootStore.uiStore.STATE.value === UIState.BONUS_IDLE ||\n                this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT) &&\n            this.view.spinButton.enabled\n        ) {\n            this.view.createRopeTextTween();\n        }\n\n        /*  if ( // IT SEEMS THAT THIS IS CHANGED AND ALREADY IS DOING NOTHING\n            this.featureController.isFeatureMode ||\n            this.rootStore.domainStore.SPIN_MODE.value !== Features.MANUAL_SPIN\n        ) {\n            return;\n        } */\n    }\n\n    /*   private destroySpinButtonAnimations(): void { // NOT IN USE\n        this.destroyTimers();\n        if (this.spinButtonTween) {\n            this.spinButtonTween.kill();\n        }\n        if (this.stopButtonTween) {\n            this.stopButtonTween.kill();\n        }\n        this.setPopDownSpinBut();\n    } */\n\n    protected onFastPlayStopped(): void {\n        this.deactivateTurboMode();\n        if (this.rootStore.domainStore.SPIN_MODE.value === Features.MANUAL_SPIN) {\n            this.view.spinButton.state = ButtonStates.Normal;\n        }\n        this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(false);\n    }\n\n    protected onKeyPressed(e: KeyboardEvent): void {\n        if (\n            e &&\n            this.rootStore.uiStore.SHOW_SETTINGS.value &&\n            ['Space', 'Enter', 'NumpadEnter', 'KeyC', 'KeyV', 'KeyB', 'KeyN', 'KeyM'].indexOf(e.code) > -1\n        ) {\n            if (this.rootStore.subjects.SETTINGS_POPUP_OPENED) {\n                this.rootStore.subjects.CLOSE_SETTINGS_POPUP.next();\n                this.rootStore.subjects.RESET_AUTOPLAY_RESTRICTIONS.next();\n                Core.sounds.play('hideDenominationsSound');\n            }\n            return;\n        }\n\n        if (\n            e === null ||\n            Core.UI_BLOCKER.value ||\n            this.rootStore.subjects.TAB_OPENED.value ||\n            this.rootStore.domainStore.SPIN_MODE.value === Features.AUTO_PLAY\n        ) {\n            return;\n        }\n        if (this.view.skipButton.visible && this.view.skipButton.enabled) {\n            this.view.skipButton.onPointerDown();\n            this.setPopUpSkipBut();\n        }\n        if (\n            (e.code !== undefined && (e.code === 'Space' || e.code === 'Enter' || e.code === 'NumpadEnter')) ||\n            (e.keyCode !== undefined && (e.keyCode === 32 || e.keyCode === 13))\n        ) {\n            if (e.repeat) {\n                return;\n            }\n            if (this.view.spinButton.visible && this.view.spinButton.enabled) {\n                this.view.spinButton.onPointerDown();\n                this.onSpinButtonDown();\n                this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(true);\n            } else if (this.view.stopButton.visible) {\n                this.view.stopButton.onPointerDown();\n                this.onStopButtonDown();\n            }\n        }\n    }\n\n    protected onKeyReleased(e: KeyboardEvent): void {\n        if (\n            e &&\n            this.rootStore.uiStore.SHOW_SETTINGS.value &&\n            ['Space', 'Enter', 'NumpadEnter', 'KeyC', 'KeyV', 'KeyB', 'KeyN', 'KeyM'].indexOf(e.code) > -1\n        ) {\n            this.rootStore.subjects.CLOSE_SETTINGS_POPUP.next();\n            // this.rootStore.uiStore.SHOW_SETTINGS.next(false);\n            this.rootStore.subjects.TAB_OPENED.next(false);\n            return;\n        }\n\n        if (e === null || Core.UI_BLOCKER.value) {\n            return;\n        }\n        if (\n            ['Space', 'Enter', 'NumpadEnter'].indexOf(e.code) > -1 ||\n            (e.keyCode !== undefined && (e.keyCode === 32 || e.keyCode === 13))\n        ) {\n            if (this.rootStore.uiStore.fastSpinMode) {\n                this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                    name: 'stopButton',\n                    actions: 'enabled',\n                    values: true,\n                });\n                // this.view.spinButton.enabled = true;\n            }\n            if (this.view.spinButton.visible && this.view.spinButton.enabled) {\n                this.view.spinButton.onPointerOut();\n                if (this.rootStore.subjects.TAB_OPENED.value) {\n                    this.rootStore.subjects.CLOSE_SETTINGS_POPUP.next();\n                    this.rootStore.subjects.RESET_AUTOPLAY_RESTRICTIONS.next();\n                    return;\n                }\n                if (this.rootStore.uiStore.fastSpinMode) {\n                    this.onSpinButtonUp();\n                    this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(false);\n                    return;\n                }\n                if (this.rootStore.domainStore.SPIN_MODE.value === Features.MANUAL_SPIN) {\n                    this.onSpinClicked();\n                    this.rootStore.subjects.DISABLE_CAMPAIGN_WIDGET.next(false);\n                }\n            } else if (this.view.stopButton.visible) {\n                this.view.stopButton.onPointerOut();\n                this.onStopButtonUp();\n                this.onStopClicked();\n            } else if (this.view.skipButton.visible && this.view.skipButton.enabled) {\n                this.view.skipButton.onPointerOut();\n                this.setPopDownSkipBut();\n            }\n        }\n\n        if (['KeyC', 'KeyV', 'KeyB', 'KeyN', 'KeyM'].indexOf(e.code) > -1) {\n            if (this.view.stopButton.visible) {\n                this.view.stopButton.onPointerOut();\n                this.onStopButtonUp();\n                this.onStopClicked();\n            }\n        }\n\n        if (\n            ((e.code !== undefined && e.code === 'ArrowDown') || (e.keyCode !== undefined && e.keyCode === 40)) &&\n            !this.settingsOpened\n        ) {\n            if (\n                this.view.collectSmallButton.visible &&\n                this.view.collectSmallButton.enabled &&\n                (this.rootStore.uiStore.STATE.value === UIState.COLLECT_BEFORE_IDLE ||\n                    this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT)\n            ) {\n                this.onCollectClicked();\n            }\n        }\n        if (\n            Core.configuration.mode === 'kiosk' &&\n            e.keyCode !== undefined &&\n            (e.code === 'BracketLeft' || e.code === 'BracketRight')\n        ) {\n            if (e.code === 'BracketLeft') {\n                this.onDecreaseBet();\n            } else if (e.code === 'BracketRight') {\n                this.onIncreaseBet();\n            }\n        }\n    }\n\n    protected getFastSpinTime(): number {\n        let time: number = this.config.autoplayWinTurboTime;\n\n        const betResponse = this.rootStore.domainStore.betResponse;\n        if (betResponse) {\n            if (this.rootStore.isGreatWin) {\n                time = Core.hasFeature(Features.BIG_WIN) ? 0 : this.config.autoplayWinCoinFeatureTime;\n            }\n        }\n        return time;\n    }\n\n    protected getWinAmount(): number {\n        return this.rootStore.uiStore.WIN.value.amount ? this.rootStore.uiStore.WIN.value.amount : 0;\n    }\n\n    protected setBalance(): void {\n        switch (this.rootStore.uiStore.STATE.value) {\n            case UIState.WIN:\n            case UIState.WAITING_FOR_COLLECT:\n                this.rootStore.uiStore.BALANCE.next(\n                    this.rootStore.uiStore.BALANCE.value -\n                        this.rootStore.getBetAmount() +\n                        Number(this.rootStore.uiStore.WIN.value.amount),\n                    // cast to number because server send string and in some cases add the \"WIN.value.amount\" like a string at the end of balance\n                );\n                break;\n            default:\n                this.rootStore.uiStore.BALANCE.next(\n                    this.rootStore.uiStore.BALANCE.value - this.rootStore.getBetAmount(),\n                );\n                break;\n        }\n    }\n\n    protected setSpinState(): void {\n        this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_RESPONSE);\n    }\n\n    private onBetChanged(): void {\n        this.view.setLastBetButtonsState();\n        this.view.steFirsBetButtonsState();\n    }\n\n    private onDecreaseBet(): void {\n        if (!this.view.betMinusBtn.enabled) {\n            return;\n        }\n\n        const firstFiveBets = this.rootStore.uiStore.bets.slice(0, 5);\n        const currentVisibleBets = this.rootStore.uiStore.VISIBLE_BETS.value;\n        const isCurrentBetVisibleAndCentered =\n            currentVisibleBets.indexOf(this.rootStore.uiStore.SELECTED_BET.value) === 2;\n        const isCurrentBetVisibleAndFirst = currentVisibleBets.indexOf(this.rootStore.uiStore.SELECTED_BET.value) === 0;\n        const isBetSlideInProgress = this.rootStore.uiStore.STATE.value === UIState.SLIDING_BETS;\n\n        if (\n            !this.isAnyActiveComponentFrom(this.componentConfiguration.betUiGuards.blockBetSlideWhenActiveComponents) &&\n            !this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value &&\n            (isBetSlideInProgress ||\n                (!this.isTheSameBetsAsVisible(firstFiveBets, currentVisibleBets) &&\n                    (isCurrentBetVisibleAndCentered || isCurrentBetVisibleAndFirst)))\n        ) {\n            this.rootStore.uiStore.ANIMATE_BET_BTNS.next('slideLeft');\n        } else {\n            const bets: number[] = this.rootStore.settings.bets;\n            const betIndex = bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value);\n            const denominations: number[] = this.rootStore.uiStore.denominations;\n            const previousDenomIndex = denominations.indexOf(Core.SELECTED_DENOMINATION.value) - 1;\n\n            if (betIndex > 0) {\n                this.rootStore.uiStore.SELECTED_BET.next(bets[betIndex - 1]);\n            } else {\n                this.rootStore.uiStore.SELECTED_BET.next(bets[bets.length - 1]);\n\n                if (betIndex === 0 && denominations.length !== 0 && previousDenomIndex >= 0) {\n                    Core.SELECTED_DENOMINATION.next(denominations[previousDenomIndex]);\n                }\n            }\n\n            this.rootStore.uiStore.CURRENT_BET_LEVEL.next({\n                betLevel: this.rootStore.uiStore.SELECTED_BET.value,\n                denomLevel: Core.SELECTED_DENOMINATION.value,\n            });\n\n            this.rootStore.subjects.CHANGE_SELECTED_BET_BTN_EXTERNALLY.next({\n                betVal: this.rootStore.uiStore.SELECTED_BET.value,\n                changedFromPopUp:\n                    this.isAnyActiveComponentFrom(\n                        this.componentConfiguration.betUiGuards.markBetChangeAsFromPopupComponents,\n                    ) || this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value,\n            });\n        }\n        Core.sounds.play('changeBetSound');\n    }\n    private onIncreaseBet(): void {\n        if (!this.view.betPlusBtn.enabled) {\n            return;\n        }\n\n        const lastFiveBets = this.rootStore.uiStore.bets.slice(-5);\n        const currentVisibleBets = this.rootStore.uiStore.VISIBLE_BETS.value;\n        const isCurrentBetVisibleAndCentered =\n            currentVisibleBets.indexOf(this.rootStore.uiStore.SELECTED_BET.value) === 2;\n        const isCurrentBetVisibleAndLast = currentVisibleBets.indexOf(this.rootStore.uiStore.SELECTED_BET.value) === 4;\n        const isBetSlideInProgress = this.rootStore.uiStore.STATE.value === UIState.SLIDING_BETS;\n\n        if (\n            !this.isAnyActiveComponentFrom(this.componentConfiguration.betUiGuards.blockBetSlideWhenActiveComponents) &&\n            !this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value &&\n            (isBetSlideInProgress ||\n                (!this.isTheSameBetsAsVisible(lastFiveBets, currentVisibleBets) &&\n                    (isCurrentBetVisibleAndCentered || isCurrentBetVisibleAndLast)))\n        ) {\n            this.rootStore.uiStore.ANIMATE_BET_BTNS.next('slideRight');\n        } else {\n            const bets: number[] = this.rootStore.settings.bets;\n            const betIndex = bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value);\n            const denominations: number[] = this.rootStore.uiStore.denominations;\n            const nextDenomIndex = denominations.indexOf(Core.SELECTED_DENOMINATION.value) + 1;\n\n            if (betIndex < bets.length - 1) {\n                this.rootStore.uiStore.SELECTED_BET.next(bets[betIndex + 1]);\n            } else {\n                this.rootStore.uiStore.SELECTED_BET.next(bets[0]);\n\n                if (\n                    betIndex === bets.length - 1 &&\n                    denominations.length !== 0 &&\n                    nextDenomIndex <= denominations.length - 1\n                ) {\n                    Core.SELECTED_DENOMINATION.next(denominations[nextDenomIndex]);\n                }\n            }\n\n            this.rootStore.uiStore.CURRENT_BET_LEVEL.next({\n                betLevel: this.rootStore.uiStore.SELECTED_BET.value,\n                denomLevel: Core.SELECTED_DENOMINATION.value,\n            });\n\n            this.rootStore.subjects.CHANGE_SELECTED_BET_BTN_EXTERNALLY.next({\n                betVal: this.rootStore.uiStore.SELECTED_BET.value,\n                changedFromPopUp:\n                    this.isAnyActiveComponentFrom(\n                        this.componentConfiguration.betUiGuards.markBetChangeAsFromPopupComponents,\n                    ) || this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value,\n            });\n        }\n        Core.sounds.play('changeBetSound');\n    }\n\n    private isAnyActiveComponentFrom(configList: SlotComponents[]): boolean {\n        const active = this.rootStore.subjects.ACTIVE_COMPONENT.value;\n        return configList.some((component) => active.includes(component));\n    }\n\n    private isTheSameBetsAsVisible(bets: number[], visibleBets: number[]): boolean {\n        for (let i = 0; i < bets.length; i++) {\n            if (bets[i] === visibleBets[i]) continue;\n            return false;\n        }\n        return true;\n    }\n\n    private disablePlusMinusWhenSliding(): void {\n        this.canClickPlusMinus = false;\n        Timers.setTimeout(() => {\n            this.canClickPlusMinus = true;\n        }, 480);\n    }\n}\n","import { FeatureController, Features, ISlotConfiguration, InitialSettings, RootStore, ServerState } from '@egt/slot';\nimport { inject, injectable } from 'tsyringe';\nimport { IUIView } from '../../../IUIView';\nimport { IUIViewComponentConfigurationTurtle } from '../configuration/IUIViewComponentConfigurationTurtle';\nimport UIViewTurtle from './UIViewTurtle';\nimport { CascadeSubjects } from '@egt/cascade-slot';\nimport Core, { IOrientation } from '@egt/core';\nimport { distinctUntilChanged, takeUntil } from 'rxjs/operators';\nimport { BaseFreeSpinsFeature } from '@egt/base-free-spins';\n\n@injectable()\nexport default class CascadeUIViewTurtle extends UIViewTurtle implements IUIView {\n    private inFreeSpins: boolean = false;\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected config: ISlotConfiguration,\n        @inject('FeatureController') protected featureController: FeatureController,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('UIViewComponentConfiguration') protected componentConfiguration: IUIViewComponentConfigurationTurtle,\n        @inject('CascadeSubjects') protected cascadeSubjects: CascadeSubjects,\n    ) {\n        super(rootStore, config, featureController, settings, componentConfiguration);\n\n        const hasExtraFreeSpinComponent: boolean = (\n            Core.getGameFeatures().find((feature) => {\n                return feature.configurationName === 'BaseFreeSpinsFeature';\n            }) as BaseFreeSpinsFeature\n        )?.hasExtraFreeSpinComponent;\n\n        const isExtraFreeSpinPick: boolean = this.settings.state === ServerState.PICK;\n        const isStateInFs: boolean = this.settings.state === ServerState.FREESPIN;\n        const count: number = this.settings.settings.game.state.rounds?.filter((round) => round.type === 'FREESPIN')[0]\n            ?.count;\n        const remain = this.settings.settings.game.state.rounds?.filter((round) => round.type === 'FREESPIN')[0]\n            ?.remain;\n\n        if ((isStateInFs || (hasExtraFreeSpinComponent && isExtraFreeSpinPick)) && count !== remain) {\n            this.markFreeSpins(true);\n            this.setOrientation();\n        }\n\n        this.cascadeSubjects.CASCADE_INTRO_SHOWN.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.markFreeSpins(true);\n            this.repositionSpinAndStopButton();\n        });\n\n        this.cascadeSubjects.CASCADE_OUTRO_COVER_SCREEN.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.markFreeSpins(false);\n            this.setOrientation();\n        });\n\n        Core.ON_GAME_PAUSED.pipe(distinctUntilChanged(), takeUntil(this.DESTROY)).subscribe(() => {\n            this.setOrientation();\n        });\n    }\n\n    protected markFreeSpins(value: boolean): void {\n        this.inFreeSpins = value;\n    }\n\n    // protected onStateChanged(): void {\n    //     super.onStateChanged();\n    //     switch (this.rootStore.uiStore.STATE.value) {\n    //         case UIState.WAITING_FOR_RESPONSE:\n    //             if (!this.rootStore.uiStore.turboModeEnabled) {\n    //                 this.spinButton.enabled = false;\n    //                 this.spinButton.visible = false;\n    //                 this.stopButton.enabled = true;\n    //                 this.stopButton.visible = true;\n    //             }\n    //             break;\n    //     }\n    // }\n\n    protected setOrientation(_orientation?: IOrientation | undefined): void {\n        super.setOrientation(_orientation);\n        this.repositionSpinAndStopButton();\n    }\n\n    protected shouldMoveSpinAndStopButton(): boolean {\n        return !!this.componentConfiguration?.moveButtonsInFreeSpins?.move && !this.isGameHeldByFeature();\n    }\n\n    protected isGameHeldByFeature(): boolean {\n        return Core.ON_GAME_PAUSED.value !== Features.NONE;\n    }\n\n    protected repositionSpinAndStopButton(): void {\n        if (this.shouldMoveSpinAndStopButton() && this.inFreeSpins) {\n            this.spinButton.x += this.componentConfiguration.moveButtonsInFreeSpins.offsetX;\n            this.spinButton.y += this.componentConfiguration.moveButtonsInFreeSpins.offsetY;\n            this.stopButton.x += this.componentConfiguration.moveButtonsInFreeSpins.offsetX;\n            this.stopButton.y += this.componentConfiguration.moveButtonsInFreeSpins.offsetY;\n\n            if (this.spinSpeedIndicator) {\n                this.spinSpeedIndicator.x += this.componentConfiguration.moveButtonsInFreeSpins.offsetX;\n                this.spinSpeedIndicator.y += this.componentConfiguration.moveButtonsInFreeSpins.offsetY;\n            }\n        }\n    }\n}\n","import { BuyBonusModes } from '@egt/buy-bonus';\nimport Core, { FeatureFlags, IOrientation, Timers } from '@egt/core';\nimport {\n    FeatureController,\n    Features,\n    IDenomOptionButtonConfig,\n    ISlotConfiguration,\n    InitialSettings,\n    RootStore,\n    ServerState,\n    SlotComponents,\n    SpinSpeedIndicator,\n    UIState,\n} from '@egt/slot';\nimport { Button, ButtonShapes, ButtonStates, Text, TextAlign, TextConfig, ViewContainer } from '@egt/ui-lib';\nimport { gsap } from 'gsap';\nimport { Container, DisplayObject, Text as PixiText, Point, SimpleRope, Sprite, TextStyle } from 'pixi.js';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { IUIView } from '../../../IUIView';\nimport { IUIViewComponentConfigurationTurtle } from '../configuration/IUIViewComponentConfigurationTurtle';\nimport { IBlitzButtonTurtle } from '../interfaces/IBlitzButtonTurtle';\n\n@injectable()\nexport default class UIViewTurtle extends ViewContainer implements IUIView {\n    // Win and Balance value tweens\n    public balanceTween: any;\n    public winValueTween: any;\n    // this container is added to stage outside of this view because background of the UI should be with different z order\n    public mainPanelBackground: Container = new Container();\n\n    // UI Elements - top level.\n    // private mainPanel: ViewContainer;\n    public sidePanel: ViewContainer;\n\n    public spinButton: Button;\n    public betPlusBtn: Button;\n    public betMinusBtn: Button;\n    public spinSpeedButton: Sprite;\n    public spinSpeedButtonDisabled: Sprite;\n    public autoPlayButton: Button;\n    public denominationButton: Button;\n    public collectSmallButton: Button;\n    public stopButton: Button;\n    public skipButton: Button;\n    public spinSpeedIndicator: SpinSpeedIndicator;\n    // public turboAutoButton: ToggleButton;\n    // public quickAutoButton: ToggleButton;\n    public infinitySign: Sprite;\n    public ON_SPIN_BUTTON_POP_ANIM_COMPLETE = new Subject();\n\n    protected ropeTextTween: any;\n    public spinButtonTween: any;\n    public spinButtonSpecialTween: any;\n    public spinButtonSpecialTweenInterval: any;\n    public spinButtonSpecialTweenTimer: any;\n    protected noActivityTimeoutId: gsap.core.Tween;\n    public spinTimeoutId: gsap.core.Tween;\n\n    public turboModeActiveTimer: boolean = false;\n    public instaSpinsButton: IBlitzButtonTurtle;\n\n    public instaSpinsButtonMode: Sprite;\n\n    public ropeText: SimpleRope;\n    public spinBtnBonusText: PixiText;\n\n    private isLastBet: boolean;\n    private isFirstBet: boolean;\n\n    protected popButInterval: number = 5000;\n    protected spinSpeedText: Text;\n    protected spinSpeedTextDisabled: Text;\n\n    // Orientation independent constants.\n    protected autoplayCounterVerticalOffset: number = 8;\n\n    protected spinPulseInterval: any;\n    protected skipButtonTween: any;\n    protected stopButtonTween: any;\n\n    // Landscape and portrait mode.\n    protected positions: any;\n\n    // UI elements - side panel.\n    protected autoplayCounter: Text;\n    protected spinButtonAutoplayCounter: Text;\n    protected autoPlayTextSize = 30;\n    private instaSpins = false;\n\n    private elements: Map<string, ViewContainer | DisplayObject> = new Map<string, DisplayObject>();\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected config: ISlotConfiguration,\n        @inject('FeatureController') protected featureController: FeatureController,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('UIViewComponentConfiguration') protected componentConfiguration: IUIViewComponentConfigurationTurtle,\n    ) {\n        super();\n        this.name = 'UIViewTurtle';\n        this.interactive = false;\n\n        this.init();\n        this.enableUI(true);\n\n        this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onAutoplayBetCounterChanged.bind(this),\n        );\n\n        this.rootStore.subjects.ACTIVE_FEATURE.pipe(takeUntil(this.DESTROY)).subscribe(this.onActiveFeature.bind(this));\n        this.rootStore.subjects.ACTIVE_COMPONENT.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onActiveComponent.bind(this),\n        );\n        this.rootStore.subjects.SPIN_BUTTON_SPECIAL_TEXT_VISIBLE.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onSpinButtonSpecialTextVisible.bind(this),\n        );\n\n        this.rootStore.subjects.FEATURE_COMPLETE.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onFeatureComplete.bind(this),\n        );\n\n        this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onBuyBonusModeChanges.bind(this),\n        );\n\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n\n        this.rootStore.uiStore.STATE.pipe(takeUntil(this.DESTROY)).subscribe(this.onStateChanged.bind(this));\n        this.rootStore.subjects.BEFORE_SPIN.pipe(takeUntil(this.DESTROY)).subscribe(this.onBeforeSpin.bind(this));\n\n        Core.LEFT_HAND_MODE.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n        Core.UI_BLOCKER.pipe(takeUntil(this.DESTROY)).subscribe((isUiBlocked) => {\n            if (!this.featureController.isControlInFeature) {\n                this.spinSpeedButton.visible = !isUiBlocked;\n                this.spinSpeedButtonDisabled.visible = isUiBlocked;\n                this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                    name: 'instaSpinsButton',\n\n                    actions: 'enabled',\n\n                    values: !isUiBlocked && this.rootStore.domainStore.SPIN_MODE.value !== Features.AUTO_PLAY,\n                });\n            }\n        });\n\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.setProperties.bind(this),\n        );\n        this.rootStore.subjects.GET_UI_VIEW_COMPONENT_STATE.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.getChildProperty.bind(this),\n        );\n    }\n\n    public destroy(): void {\n        this.destroyIntervals();\n\n        if (this.balanceTween) {\n            this.balanceTween.totalProgress(1);\n            this.balanceTween.kill();\n            this.balanceTween = null;\n        }\n        if (this.winValueTween) {\n            this.winValueTween.totalProgress(1);\n            this.winValueTween.kill();\n            this.winValueTween = null;\n        }\n        this.destroyRopeText();\n        this.killRopeTextTween();\n        if (this.spinButtonTween) {\n            this.spinButtonTween.kill();\n            // @ts-ignore\n            this.spinButtonTween = null;\n        }\n        if (this.spinButtonSpecialTween) {\n            this.spinButtonSpecialTween.kill();\n            // @ts-ignore\n            this.spinButtonSpecialTween = null;\n        }\n        if (this.skipButtonTween) {\n            this.skipButtonTween.kill();\n            // @ts-ignore\n            this.skipButtonTween = null;\n        }\n        if (this.stopButtonTween) {\n            this.stopButtonTween.kill();\n            // @ts-ignore\n            this.stopButtonTween = null;\n        }\n        if (this.spinButton) {\n            this.spinButton.destroy();\n            // @ts-ignore\n            this.spinButton = null;\n        }\n        if (this.spinSpeedButton) {\n            this.spinSpeedButton.destroy();\n            // @ts-ignore\n            this.spinSpeedButton = null;\n        }\n        if (this.stopButton) {\n            this.stopButton.destroy();\n            // @ts-ignore\n            this.stopButton = null;\n        }\n\n        // @ts-ignore\n        this.spinButtonTween = null;\n        // @ts-ignore\n        this.spinButtonSpecialTween = null;\n        // @ts-ignore\n        this.skipButtonTween = null;\n\n        // @ts-ignore\n        this.stopButtonTween = null;\n        // @ts-ignore\n        // this.spinButtonWidth = null;\n        // @ts-ignore\n        this.spinButtonHeight = null;\n        // @ts-ignore\n        this.skipButtonHeight = null;\n        // @ts-ignore\n        this.skipButtonWidth = null;\n\n        if (this.spinSpeedIndicator) {\n            this.spinSpeedIndicator.destroy();\n            // @ts-ignore\n            this.spinSpeedIndicator = null;\n        }\n\n        Timers.clearTimeout(this.spinTimeoutId);\n        if (this.ON_SPIN_BUTTON_POP_ANIM_COMPLETE) {\n            this.ON_SPIN_BUTTON_POP_ANIM_COMPLETE.complete();\n            // @ts-ignore\n            this.ON_SPIN_BUTTON_POP_ANIM_COMPLETE = null;\n        }\n\n        this.elements.clear();\n        // @ts-ignore\n        this.elements = null;\n        super.destroy.apply(this, arguments);\n    }\n\n    public initialRender(): void {\n        //\n    }\n\n    public init(): void {\n        // Create buttons\n        this.instaSpins = Core.hasFeature(Features.BLITZ_PLAY);\n\n        const backgroundTextures = this.componentConfiguration.spinButtonPosition.useBackgroundTexture\n            ? [Core.assets.getAsset(this.componentConfiguration.spinButtonPosition.backgroundTexture).texture]\n            : undefined;\n        this.spinButton = new Button(\n            Core.assets.getAssets(this.componentConfiguration.spinButtonPosition.textures),\n            backgroundTextures,\n            ButtonShapes.Circle,\n            true,\n        );\n\n        this.spinButton.name = 'spinButton';\n        this.spinButton.pivot.set(this.spinButton.width / 2, this.spinButton.height / 2);\n\n        this.betPlusBtn = new Button(\n            Core.assets.getAssets(this.componentConfiguration.betPlusBtnPositions.textures),\n            undefined,\n            ButtonShapes.Circle,\n            false,\n            this.componentConfiguration.betPlusBtnPositions.hitPadding,\n        );\n        this.betPlusBtn.name = 'betPlusBtn';\n        this.betPlusBtn.pivot.set(this.betPlusBtn.width / 2, this.betPlusBtn.height / 2);\n        this.addChild(this.betPlusBtn);\n\n        this.betMinusBtn = new Button(\n            Core.assets.getAssets(this.componentConfiguration.betMinusBtnPositions.textures),\n            undefined,\n            ButtonShapes.Circle,\n            false,\n            this.componentConfiguration.betMinusBtnPositions.hitPadding,\n        );\n        this.betMinusBtn.name = 'betMinusBtn';\n        this.betMinusBtn.pivot.set(this.betMinusBtn.width / 2, this.betMinusBtn.height / 2);\n        this.addChild(this.betMinusBtn);\n\n        this.spinSpeedButton = new Sprite();\n\n        this.spinSpeedButton.name = 'spinSpeedButton';\n        this.spinSpeedButton.buttonMode = true;\n        this.spinSpeedButton.interactive = true;\n\n        this.spinSpeedButtonDisabled = new Sprite();\n        this.spinSpeedButtonDisabled.texture = Core.assets.getAsset('svgDisabledSpeed').texture;\n        this.spinSpeedButtonDisabled.name = 'spinSpeedButtonDisabled';\n        this.spinSpeedButtonDisabled.visible = false;\n        this.spinSpeedButtonDisabled.pivot.set(\n            this.spinSpeedButtonDisabled.width / 2,\n            this.spinSpeedButtonDisabled.height / 2,\n        );\n        if (this.componentConfiguration.spinSpeedTextProperties.display && !this.instaSpins) {\n            const spinSpeedTextTextConfig: TextConfig = new TextConfig();\n            const spinSpeedTextTextStyle = new TextStyle(this.componentConfiguration.spinSpeedTextProperties.style);\n            spinSpeedTextTextConfig.bounds.width = this.componentConfiguration.spinSpeedTextProperties.width;\n            spinSpeedTextTextConfig.bounds.height = this.componentConfiguration.spinSpeedTextProperties.height;\n            spinSpeedTextTextConfig.align = TextAlign.CENTER;\n            spinSpeedTextTextConfig.shouldFitInBounds = true;\n            this.spinSpeedText = new Text(\n                spinSpeedTextTextConfig,\n                Core.translator.translate('SPEED'),\n                spinSpeedTextTextStyle,\n            );\n            this.spinSpeedText.name = 'spinSpeedText';\n            this.spinSpeedText.pivot.set(\n                this.componentConfiguration.spinSpeedTextProperties.width / 2,\n                this.componentConfiguration.spinSpeedTextProperties.height / 2,\n            );\n            this.spinSpeedButton.addChild(this.spinSpeedText);\n\n            const spinSpeedTextTextConfigDisabled: TextConfig = new TextConfig();\n            spinSpeedTextTextConfigDisabled.bounds.width =\n                this.componentConfiguration.spinSpeedTextDisabledProperties.width;\n            spinSpeedTextTextConfigDisabled.bounds.height =\n                this.componentConfiguration.spinSpeedTextDisabledProperties.height;\n\n            const spinSpeedTextTextConfigDisabledStyle = new TextStyle(\n                this.componentConfiguration.spinSpeedTextDisabledProperties.style,\n            );\n            spinSpeedTextTextConfigDisabled.bounds.width =\n                this.componentConfiguration.spinSpeedTextDisabledProperties.width;\n            spinSpeedTextTextConfigDisabled.bounds.height =\n                this.componentConfiguration.spinSpeedTextDisabledProperties.height;\n            spinSpeedTextTextConfigDisabled.align = TextAlign.CENTER;\n            spinSpeedTextTextConfigDisabled.shouldFitInBounds = true;\n            this.spinSpeedTextDisabled = new Text(\n                spinSpeedTextTextConfigDisabled,\n                Core.translator.translate('SPEED'),\n                spinSpeedTextTextConfigDisabledStyle,\n            );\n            this.spinSpeedTextDisabled.name = 'spinSpeedTextDisabled';\n            this.spinSpeedTextDisabled.pivot.set(\n                this.componentConfiguration.spinSpeedTextDisabledProperties.width / 2,\n                this.componentConfiguration.spinSpeedTextDisabledProperties.height / 2,\n            );\n            this.spinSpeedButtonDisabled.addChild(this.spinSpeedTextDisabled);\n            this.spinSpeedTextDisabled.alpha = this.componentConfiguration.spinSpeedTextDisabledProperties.alpha;\n        }\n        this.autoPlayButton = new Button(\n            Core.assets.getAssets(this.componentConfiguration.autoPlayButtonPosition.textures),\n            undefined,\n            ButtonShapes.Rectangle,\n        );\n\n        this.autoPlayButton.name = 'autoPlayButton';\n        this.autoPlayButton.pivot.set(this.autoPlayButton.width / 2, this.autoPlayButton.height / 2);\n        if (!this.settings.autoplay) {\n            this.autoPlayButton.visible = false;\n        }\n        this.stopButton = new Button(\n            Core.assets.getAssets(this.componentConfiguration.stopButtonPosition.textures),\n            undefined,\n            ButtonShapes.Circle,\n        );\n        // this.stopButton = new Button([Core.assets.getAsset('svgAutoPlayStop').texture], undefined, ButtonShapes.Circle);\n\n        this.stopButton.pivot.set(this.stopButton.width / 2, this.stopButton.height / 2);\n        this.stopButton.name = 'stopButton';\n\n        this.skipButton = new Button(\n            [Core.assets.getAsset('svgSpinSkipAnimation').texture],\n            undefined,\n            ButtonShapes.Circle,\n        );\n        this.skipButton.pivot.set(this.skipButton.width / 2, this.skipButton.height / 2);\n        this.skipButton.name = 'skipButton';\n        this.skipButton.visible = false;\n        this.skipButton.enabled = false;\n\n        this.denominationButton = new Button(\n            Core.assets.getAssets(this.componentConfiguration.denominationButtonPosition.textures),\n            undefined,\n            ButtonShapes.Rectangle,\n        );\n        this.denominationButton.name = 'denominationButton';\n        this.denominationButton.pivot.set(this.denominationButton.width / 2, this.denominationButton.height / 2);\n\n        const autoplayTextConfig: TextConfig = new TextConfig();\n        const autoplayTextStyle: TextStyle = new TextStyle(this.componentConfiguration.autoplayTextProperties.style);\n\n        // const spinButtonAutoplayTextStyle: TextStyle = new TextStyle(\n        //     this.componentConfiguration.autoplayTextProperties.style,\n        // );\n\n        this.autoplayCounter = new Text(autoplayTextConfig, '0', autoplayTextStyle);\n        this.autoplayCounter.name = 'autoplayCounter';\n        this.infinitySign = new Sprite(Core.assets.getAsset('svgAutoPlayInfinity').texture);\n        this.infinitySign.visible = false;\n        this.infinitySign.pivot.set(this.infinitySign.width / 2, this.infinitySign.height / 2);\n        this.infinitySign.x = this.componentConfiguration.autoplayTextProperties.x;\n        this.infinitySign.y = this.componentConfiguration.autoplayTextProperties.y;\n        /*  this.spinButtonAutoplayCounter = new Text(autoplayTextConfig, '0', spinButtonAutoplayTextStyle);\n        this.spinButtonAutoplayCounter.name = 'spinButtonAutoplayCounter';\n        this.spinButtonAutoplayCounter.visible = false;\n */\n        this.collectSmallButton = new Button(\n            Core.assets.getAssets(this.componentConfiguration.collectSmallButtonPosition.textures),\n            undefined,\n            ButtonShapes.Rectangle,\n        );\n        this.collectSmallButton.name = 'collectSmallButton';\n        this.collectSmallButton.pivot.set(this.collectSmallButton.width / 2, this.collectSmallButton.height / 2);\n        // this.spinButton.addChild(this.spinButtonAutoplayCounter);\n\n        this.addChild(this.autoPlayButton);\n\n        this.addChild(this.denominationButton);\n        this.addChild(this.collectSmallButton);\n        this.addChild(this.spinButton);\n\n        // container.addChild(this.turboAutoButton);\n        // container.addChild(this.quickAutoButton);\n\n        this.addChild(this.skipButton);\n        if (this.instaSpins) {\n            const instaPadButton = new Sprite();\n\n            instaPadButton.texture = Core.assets.getAsset('blitzBackgroundButton').texture;\n            this.instaSpinsButton = new Sprite() as IBlitzButtonTurtle;\n\n            this.instaSpinsButtonMode = new Sprite();\n\n            this.instaSpinsButtonMode.texture = Core.assets.getAsset('blitzSpinButton').texture;\n\n            this.instaSpinsButton.name = 'instaSpinsButton';\n\n            this.instaSpinsButton.buttonMode = true;\n\n            this.instaSpinsButton.interactive = true;\n\n            this.instaSpinsButton.enabled = true;\n\n            this.instaSpinsButton.pivot.set(this.instaSpinsButton.width / 2, 0);\n\n            this.spinSpeedButton.texture = Core.assets.getAsset('blitzNormalSpeed').texture;\n\n            this.spinSpeedButton.pivot.set(this.spinSpeedButton.width - 5, this.spinSpeedButton.height / 2);\n\n            instaPadButton.pivot.set(instaPadButton.width / 2, instaPadButton.height / 2);\n\n            this.instaSpinsButtonMode.pivot.set(0, this.instaSpinsButtonMode.height / 2);\n\n            this.instaSpinsButtonMode.x = -4;\n\n            this.instaSpinsButton.addChild(this.instaSpinsButtonMode);\n            instaPadButton.x = 1;\n            this.instaSpinsButton.addChildAt(instaPadButton, 0);\n\n            this.addChild(this.instaSpinsButton);\n\n            this.spinSpeedButtonDisabled.texture = Core.assets.getAsset('blitzSpeedButtonDisabled').texture;\n\n            this.spinSpeedButtonDisabled.pivot.set(this.spinSpeedButton.width - 5, this.spinSpeedButton.height / 2);\n        } else {\n            this.spinSpeedButton.texture = Core.assets.getAsset('svgNormalSpeed').texture;\n\n            this.spinSpeedButton.pivot.set(this.spinSpeedButton.width / 2, this.spinSpeedButton.height / 2);\n        }\n\n        if (this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value === 0) {\n            this.addChild(this.spinSpeedButton);\n            this.addChild(this.spinSpeedButtonDisabled);\n\n            // this.ropeText.pivot.set(\n            //     this.ropeText.getLocalBounds().width / 2,\n            //     this.spinButton.getLocalBounds().height / 2,\n            // );\n        } else {\n            this.spinSpeedIndicator = new SpinSpeedIndicator(this.rootStore, this.config);\n            this.spinSpeedIndicator.interactive = true;\n            this.spinSpeedIndicator.name = 'spinSpeedIndicator';\n            this.spinSpeedIndicator.pivot.set(this.spinSpeedIndicator.width / 2, this.spinSpeedIndicator.height / 2);\n\n            this.addChild(this.spinSpeedIndicator);\n            this.stopButton = new Button(\n                Core.assets.getAssets(this.componentConfiguration.stopButtonPosition.textures),\n                undefined,\n                ButtonShapes.Circle,\n            );\n            this.stopButton.name = 'stopButton';\n        }\n        this.stopButton.addChild(this.autoplayCounter);\n        this.stopButton.addChild(this.infinitySign);\n        this.stopButton.pivot.set(this.stopButton.width / 2, this.stopButton.height / 2);\n        this.addChildAt(this.stopButton, 1);\n\n        // this.spinButtonWidth = this.spinButton.width;\n        // this.spinButtonHeight = this.spinButton.height;\n        // this.skipButtonWidth = this.skipButton.width;\n        // this.skipButtonHeight = this.skipButton.height;\n        // this.stopButtonSizeWidth = this.stopButton.width;\n        // this.stopButtonSizeHeight = this.stopButton.height;\n\n        if (\n            !Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS) &&\n            this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value === 0 &&\n            !Core.flags.isActive(FeatureFlags.HIDE_HOLD_AND_PLAY)\n        ) {\n            this.createRopeText('HOLD FOR FAST PLAY');\n            this.createRopeTextTween();\n        }\n\n        this.setOrientation();\n        this.children.forEach((child) => {\n            this.elements.set(child.name, child);\n        });\n\n        this.elements.set('autoplayCounter', this.autoplayCounter);\n    }\n\n    public enableUI(enableUI: boolean): void {\n        this.interactiveChildren = enableUI;\n    }\n    //// START///////////////////////////////////////\n\n    public pulseSpin(): void {\n        this.destroyIntervals();\n        this.destroyTimers();\n        this.spinPulseInterval = Timers.setInterval(() => {\n            this.spinButtonTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/ui-view/src/egt/modes/turtle/views/UIViewTurtle.ts:529:36\",null]), gsap.to(this.spinButton, {\n                duration: 0.5,\n                width: this.spinButton.width * 1.1,\n                height: this.spinButton.height * 1.1,\n                ease: 'power2.out',\n                repeat: 1,\n                onComplete: () => {\n                    this.resetSpinBtnSize();\n                },\n            }));\n        }, 6500);\n    }\n\n    public rotateSpinBtnArrows(): void {\n        // this.destroyIntervals();\n        // this.destroyTimers();\n        // this.spinPulseInterval = Timers.setInterval(() => {\n\n        this.spinButtonSpecialTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/ui-view/src/egt/modes/turtle/views/UIViewTurtle.ts:547:39\",null]), gsap.timeline({\n            onComplete: () => {\n                this.spinButtonSpecialTween.kill();\n                this.spinButtonSpecialTween = null;\n            },\n        }));\n        this.spinButtonSpecialTween\n            .to(this.spinButton.btnSprite, {\n                duration: 0.2,\n                angle: -20,\n                ease: 'power2.out',\n            })\n            .to(this.spinButton.btnSprite, {\n                duration: 0.4,\n                angle: 20,\n                ease: 'power2.out',\n            })\n            .to(this.spinButton.btnSprite, {\n                duration: 0.2,\n                angle: 0,\n                ease: 'power2.out',\n            });\n    }\n\n    public stopSpinPulsation(): void {\n        this.destroyIntervals();\n        this.destroyTimers();\n        this.resetSpinBtnSize();\n        this.onStopButtonUp();\n    }\n\n    public destroyTimers(): void {\n        Timers.clearTimeout(this.spinTimeoutId);\n    }\n\n    public destroyIntervals(): void {\n        if (this.spinPulseInterval) {\n            Timers.clearInterval(this.spinPulseInterval);\n        }\n    }\n\n    public onStopButtonDown(): void {\n        if (!this.stopButton.visible || !this.stopButton.enabled) {\n            return;\n        }\n        if (this.stopButtonTween) {\n            this.stopButtonTween.kill();\n        }\n        // this.stopButtonTween = gsap.timeline();\n        const scale = this.componentConfiguration.spinButtonPosition.scale || 1;\n        this.stopButton.scale.set(scale);\n        // this.stopButton.width = this.stopButtonSizeWidth;\n        // this.stopButton.height = this.stopButtonSizeHeight;\n        this.stopButtonTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/ui-view/src/egt/modes/turtle/views/UIViewTurtle.ts:600:32\",null]), gsap.to(this.stopButton.scale, {\n            duration: 0.1,\n            x: scale + 0.05,\n            y: scale + 0.05,\n        }));\n        this.resetSpinBtnSize();\n    }\n\n    public onStopButtonUp(): void {\n        if (this.stopButtonTween) {\n            this.stopButtonTween.kill();\n        }\n\n        this.stopButton.scale.set(this.componentConfiguration.spinButtonPosition.scale || 1);\n        this.resetSpinBtnSize();\n    }\n\n    public onSpinButtonDown(): void {\n        this.destroyIntervals();\n        this.destroyTimers();\n        if (\n            this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value > 0 ||\n            Core.flags.isActive(FeatureFlags.HIDE_HOLD_AND_PLAY)\n        ) {\n            return;\n        }\n        const scale = this.componentConfiguration.spinButtonPosition.scale || 1;\n        this.spinTimeoutId = Timers.setTimeout(() => {\n            // this.killRopeTextTween();\n            // this.spinButton.enabled = false;\n            this.spinButtonTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/ui-view/src/egt/modes/turtle/views/UIViewTurtle.ts:630:36\",null]), gsap.timeline({\n                onComplete: () => {\n                    this.ON_SPIN_BUTTON_POP_ANIM_COMPLETE.next();\n                },\n            }));\n            this.spinButtonTween\n                .to(this.spinButton.scale, {\n                    duration: 0.5,\n                    x: scale + 0.2,\n                    y: scale + 0.2,\n                    ease: 'power2.out',\n                })\n                .to(this.spinButton.scale, {\n                    duration: 0.1,\n                    x: scale,\n                    y: scale,\n                    ease: 'power2.out',\n                });\n            this.spinButtonTween.play();\n        }, 500);\n    }\n\n    public onSpinButtonUp(): void {\n        this.spinButton.state = ButtonStates.Normal;\n\n        if (this.turboModeActiveTimer && !this.rootStore.uiStore.turboModeEnabled) {\n            this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_COLLECT);\n            this.turboModeActiveTimer = false;\n        }\n    }\n\n    public resetStopBtnSize(): void {\n        if (this.stopButton) {\n            this.stopButton.scale.set(this.componentConfiguration.spinButtonPosition.scale || 1);\n        }\n    }\n\n    public resetSpinBtnSize(): void {\n        if (this.spinButton) {\n            this.spinButton.scale.set(this.componentConfiguration.spinButtonPosition.scale || 1);\n        }\n    }\n\n    public setPopDownSpinBut(): void {\n        this.stopButton.state = ButtonStates.Normal; // reset the state because some features set it to disabled and it is not updated sometimes\n        const scale = this.componentConfiguration.spinButtonPosition.scale || 1;\n        this.spinButtonTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/ui-view/src/egt/modes/turtle/views/UIViewTurtle.ts:676:32\",null]), gsap.to(this.spinButton.scale, {\n            duration: 0.1,\n            x: scale,\n            y: scale,\n            repeat: 0,\n            onComplete: () => {\n                if (this.ropeText?.alpha === 0) {\n                    this.killRopeTextTween();\n                    this.createRopeTextTween();\n                }\n            },\n        }));\n        if (this.ropeText?.alpha > 0) {\n            this.ropeText.alpha = 1;\n        }\n        if (this.spinBtnBonusText) {\n            this.spinBtnBonusText.alpha = 1;\n        }\n    }\n    public setPopDownSkipBut(): void {\n        const scale = this.componentConfiguration.spinButtonPosition.scale || 1;\n        this.skipButtonTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/ui-view/src/egt/modes/turtle/views/UIViewTurtle.ts:697:32\",null]), gsap.to(this.skipButton.scale, {\n            duration: 0.1,\n            x: scale,\n            y: scale,\n        }));\n    }\n\n    public setPopUpSpinBut(): void {\n        const dynamicScale = (this.componentConfiguration.spinButtonPosition.scale || 1) + 0.05;\n        this.spinButtonTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/ui-view/src/egt/modes/turtle/views/UIViewTurtle.ts:706:32\",null]), gsap.to(this.spinButton.scale, {\n            duration: 0.1,\n            x: dynamicScale,\n            y: dynamicScale,\n        }));\n        if (this.ropeText?.alpha > 0) {\n            this.ropeText.alpha = 0.4;\n        }\n        if (this.spinBtnBonusText?.alpha > 0) {\n            this.spinBtnBonusText.alpha = 0.4;\n        }\n    }\n\n    public setPopUpSkipBut(): void {\n        const dynamicScale = (this.componentConfiguration.spinButtonPosition.scale || 1) + 0.05;\n        this.skipButtonTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/ui-view/src/egt/modes/turtle/views/UIViewTurtle.ts:721:32\",null]), gsap.to(this.skipButton.scale, {\n            duration: 0.1,\n            x: dynamicScale,\n            y: dynamicScale,\n        }));\n    }\n\n    public killRopeTextTween(): void {\n        Timers.clearTimeout(this.noActivityTimeoutId);\n        if (this.ropeTextTween) {\n            this.ropeTextTween.kill();\n            this.ropeTextTween = null;\n            if (this.ropeText) {\n                this.ropeText.alpha = 0;\n            }\n        }\n    }\n\n    public createRopeTextTween(): void {\n        if (!this.ropeText) {\n            return;\n        }\n        const timeOut: number = this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value\n            ? 100\n            : this.popButInterval;\n        this.noActivityTimeoutId = Timers.setTimeout(() => {\n            if (\n                (this.rootStore.uiStore.STATE.value === UIState.IDLE ||\n                    this.rootStore.uiStore.STATE.value === UIState.BONUS_IDLE ||\n                    this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT) &&\n                this.spinButton.enabled\n            ) {\n                this.ropeTextTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/components/slot/ui-view/src/egt/modes/turtle/views/UIViewTurtle.ts:753:38\",null]), gsap.to(this.ropeText, {\n                    duration: 0.2,\n                    alpha: 1,\n                    ease: 'none',\n                }));\n            }\n        }, timeOut);\n    }\n\n    public onSpinSpeedChanged(speed: number): void {\n        const btnPrefix = this.instaSpins ? 'blitz' : 'svg';\n\n        switch (speed) {\n            case 0:\n                this.spinSpeedButton.texture = Core.assets.getAsset(btnPrefix + 'NormalSpeed').texture;\n                break;\n\n            case 1:\n                this.spinSpeedButton.texture = Core.assets.getAsset(btnPrefix + 'QuickSpeed').texture;\n                break;\n            case 2:\n                this.spinSpeedButton.texture = Core.assets.getAsset(btnPrefix + 'TurboSpeed').texture;\n                break;\n        }\n    }\n\n    private isNextBetOverMaxLimit(): boolean {\n        const bets = this.rootStore.uiStore.bets;\n        const currentBet = this.rootStore.uiStore.SELECTED_BET.value;\n\n        const currentIndex = bets.indexOf(currentBet);\n        if (currentIndex < 0) return false;\n\n        const nextIndex = currentIndex + 1;\n        if (nextIndex >= bets.length) return false;\n\n        const nextBet = bets[nextIndex];\n        const denom = Core.SELECTED_DENOMINATION.value;\n        const factor = this.rootStore.settings.factor;\n        const nextTotalBet = (nextBet * denom * factor) / 100;\n        const betLimit = this.getBetLimit();\n\n        if (betLimit === null) return false;\n\n        return nextTotalBet > betLimit;\n    }\n\n    private getBetLimit(): number | null {\n        const jurisdictionalLimit: number | null = this.rootStore.settings.maxBet ?? null;\n\n        const buyBonusLimit: number | null =\n            this.rootStore.settings.settings.settings?.clientSettings?.maxBetLimits &&\n            Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS)\n                ? (this.rootStore.settings.settings.settings.clientSettings.maxBetLimits[\n                      this.rootStore.settings.currency\n                  ] ?? null)\n                : null;\n\n        const buyBonusActivated = this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value === true;\n        const effectiveBuyBonusLimit = buyBonusActivated ? buyBonusLimit : null;\n\n        if (jurisdictionalLimit != null && effectiveBuyBonusLimit != null) {\n            return Math.min(jurisdictionalLimit, effectiveBuyBonusLimit);\n        }\n        if (jurisdictionalLimit != null) return jurisdictionalLimit;\n        if (effectiveBuyBonusLimit != null) return effectiveBuyBonusLimit;\n\n        return null;\n    }\n\n    public setLastBetButtonsState(): void {\n        const lastDenom: boolean =\n            this.rootStore.settings.denominations.indexOf(Core.SELECTED_DENOMINATION.value) ===\n            this.rootStore.settings.denominations.length - 1;\n        const lastBet: boolean =\n            this.rootStore.settings.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value) ===\n            this.rootStore.settings.bets.length - 1;\n        const isLastBet: boolean = lastDenom && lastBet;\n        const reachedMaxBet: boolean = isLastBet || this.isNextBetOverMaxLimit();\n        this.isLastBet = reachedMaxBet;\n        this.betPlusBtn.enabled = !reachedMaxBet;\n    }\n\n    public steFirsBetButtonsState(): void {\n        const firstDenom: boolean =\n            this.rootStore.settings.denominations.indexOf(Core.SELECTED_DENOMINATION.value) === 0;\n        const firstBet: boolean = this.rootStore.settings.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value) === 0;\n        const isFirstBet: boolean = firstDenom && firstBet;\n        this.isFirstBet = isFirstBet;\n        this.betMinusBtn.enabled = !isFirstBet;\n    }\n\n    //// END/////////\n\n    protected destroyRopeText(): void {\n        if (this.ropeText) {\n            this.ropeText.destroy({ children: true });\n            // @ts-ignore\n            this.ropeText = null;\n        }\n    }\n\n    private onActiveComponent(): void {\n        // if (this.spinBtnBonusText) {\n        //     this.spinBtnBonusText.visible = !this.rootStore.subjects.ACTIVE_COMPONENT.value.includes(\n        //         SlotComponents.DENOMINATION_POPUP,\n        //     );\n        // }\n    }\n\n    protected onActiveFeature(): void {\n        if (\n            this.rootStore.subjects.ACTIVE_FEATURE.value.includes(Features.CASCADE_RESPIN) ||\n            this.rootStore.subjects.ACTIVE_FEATURE.value.includes(Features.BASE_FREE_SPINS)\n        ) {\n            return;\n        }\n\n        if (\n            this.rootStore.subjects.ACTIVE_FEATURE.value.includes(Features.GAMBLE) ||\n            // this.rootStore.subjects.ACTIVE_FEATURE.value.includes(Features.BASE_FREE_SPINS) ||\n            this.rootStore.subjects.ACTIVE_FEATURE.value.includes(Features.FREE_SPINS) ||\n            this.rootStore.subjects.ACTIVE_FEATURE.value.includes(Features.CASH_HEAT)\n        ) {\n            this.betMinusBtn.visible = false;\n            this.betPlusBtn.visible = false;\n        } else {\n            this.betMinusBtn.visible = true;\n            this.betPlusBtn.visible = true;\n        }\n\n        this.setOrientation();\n    }\n\n    protected setOrientation(_orientation?: IOrientation): void {\n        this.x = this.componentConfiguration.uiViewPosition.x;\n        this.y = this.componentConfiguration.uiViewPosition.y;\n        this.denominationButton.x = this.componentConfiguration.denominationButtonPosition.x;\n        this.denominationButton.y = this.componentConfiguration.denominationButtonPosition.y;\n        this.denominationButton.scale.set(this.componentConfiguration.denominationButtonPosition.scale || 1);\n\n        this.betPlusBtn.x = this.componentConfiguration.betPlusBtnPositions.x;\n        this.betPlusBtn.y = this.componentConfiguration.betPlusBtnPositions.y;\n        this.betPlusBtn.scale.set(this.componentConfiguration.betPlusBtnPositions.scale);\n\n        this.betMinusBtn.x = this.componentConfiguration.betMinusBtnPositions.x;\n        this.betMinusBtn.y = this.componentConfiguration.betMinusBtnPositions.y;\n        this.betMinusBtn.scale.set(this.componentConfiguration.betMinusBtnPositions.scale);\n\n        this.collectSmallButton.x = this.componentConfiguration.collectSmallButtonPosition.x;\n        this.collectSmallButton.y = this.componentConfiguration.collectSmallButtonPosition.y;\n        this.collectSmallButton.scale.set(this.componentConfiguration.collectSmallButtonPosition.scale || 1);\n\n        this.autoPlayButton.x = this.componentConfiguration.autoPlayButtonPosition.x;\n        this.autoPlayButton.y = this.componentConfiguration.autoPlayButtonPosition.y;\n        this.autoPlayButton.scale.set(this.componentConfiguration.autoPlayButtonPosition.scale || 1);\n\n        if (this.instaSpins) {\n            this.instaSpinsButton.x = this.componentConfiguration.spinSpeedButtonPosition.x;\n            this.instaSpinsButton.y = this.componentConfiguration.spinSpeedButtonPosition.y;\n            this.instaSpinsButton.scale.set(this.componentConfiguration.spinSpeedButtonPosition.scale);\n        }\n\n        this.spinSpeedButton.x = this.componentConfiguration.spinSpeedButtonPosition.x;\n        this.spinSpeedButton.y = this.componentConfiguration.spinSpeedButtonPosition.y;\n        this.spinSpeedButton.scale.set(this.componentConfiguration.spinSpeedButtonPosition.scale || 1);\n\n        this.spinSpeedButtonDisabled.x = this.componentConfiguration.spinSpeedButtonPosition.x;\n        this.spinSpeedButtonDisabled.y = this.componentConfiguration.spinSpeedButtonPosition.y;\n        this.spinSpeedButtonDisabled.scale.set(this.componentConfiguration.spinSpeedButtonPosition.scale || 1);\n\n        this.spinButton.x = this.componentConfiguration.spinButtonPosition.x;\n        this.spinButton.y = this.componentConfiguration.spinButtonPosition.y;\n        this.spinButton.scale.set(this.componentConfiguration.spinButtonPosition.scale || 1);\n\n        this.stopButton.x = this.componentConfiguration.stopButtonPosition.x;\n        this.stopButton.y = this.componentConfiguration.stopButtonPosition.y;\n        this.stopButton.scale.set(this.componentConfiguration.stopButtonPosition.scale || 1);\n\n        this.skipButton.x = this.componentConfiguration.spinButtonPosition.x;\n        this.skipButton.y = this.componentConfiguration.spinButtonPosition.y;\n        this.skipButton.scale.set(this.componentConfiguration.spinButtonPosition.scale || 1);\n\n        if (this.componentConfiguration.spinSpeedTextProperties.display && !this.instaSpins) {\n            this.spinSpeedText.config.bounds.width = this.componentConfiguration.spinSpeedTextProperties.width;\n            this.spinSpeedText.config.bounds.height = this.componentConfiguration.spinSpeedTextProperties.height;\n            this.spinSpeedText.style = this.componentConfiguration.spinSpeedTextProperties.style;\n\n            this.spinSpeedText.pivot.set(\n                this.spinSpeedText.config.bounds.width / 2,\n                this.spinSpeedText.config.bounds.height / 2,\n            );\n\n            this.spinSpeedText.x = this.spinSpeedButton.texture.width / 2;\n            this.spinSpeedText.y = this.componentConfiguration.spinSpeedTextProperties.y;\n\n            this.spinSpeedTextDisabled.config.bounds.width =\n                this.componentConfiguration.spinSpeedTextDisabledProperties.width;\n            this.spinSpeedTextDisabled.config.bounds.height =\n                this.componentConfiguration.spinSpeedTextDisabledProperties.height;\n            this.spinSpeedTextDisabled.style = this.componentConfiguration.spinSpeedTextDisabledProperties.style;\n\n            this.spinSpeedTextDisabled.pivot.set(\n                this.spinSpeedTextDisabled.config.bounds.width / 2,\n                this.spinSpeedTextDisabled.config.bounds.height / 2,\n            );\n\n            this.spinSpeedTextDisabled.x = this.spinSpeedButtonDisabled.texture.width / 2;\n            this.spinSpeedTextDisabled.y = this.componentConfiguration.spinSpeedTextDisabledProperties.y;\n        }\n\n        if (this.spinSpeedIndicator) {\n            this.spinSpeedIndicator.x = this.componentConfiguration.minSpinTimeButtonPosition.x;\n            this.spinSpeedIndicator.y = this.componentConfiguration.minSpinTimeButtonPosition.y;\n            this.spinSpeedIndicator.scale.set(this.componentConfiguration.minSpinTimeButtonPosition.scale || 1);\n        }\n    }\n\n    protected createRopeText(ropeString: string): void {\n        const text = new PixiText(\n            Core.translator.translate(ropeString),\n            new TextStyle(this.componentConfiguration.ropeTextProperties.style),\n        );\n\n        text.updateText(true);\n        const radius = this.componentConfiguration.ropeTextProperties.radius;\n        const maxRopePoints = this.componentConfiguration.ropeTextProperties.maxRopePoints;\n        const step = Math.PI / maxRopePoints;\n        const resolution = this.componentConfiguration.ropeTextProperties.resolution;\n        if (resolution > 1) {\n            text.resolution = resolution;\n            text.updateText(true);\n        }\n\n        const spr = new Sprite(text.texture);\n\n        let ropePoints = maxRopePoints - Math.round((text.texture.width / (radius * Math.PI)) * maxRopePoints);\n        ropePoints /= 2;\n\n        const points: any[] = [];\n        for (let i = maxRopePoints - ropePoints; i > ropePoints; i--) {\n            const x = radius * Math.cos(step * i);\n            const y = radius * Math.sin(step * i);\n            points.push(new Point(x, -y));\n        }\n\n        const rope = new SimpleRope(spr.texture, points);\n        rope.alpha = 0;\n        this.ropeText = rope;\n        this.ropeText.name = 'ropeText';\n\n        this.spinButton.addChild(this.ropeText);\n        this.ropeText.x = this.componentConfiguration.ropeTextProperties.x;\n        this.ropeText.y = this.componentConfiguration.ropeTextProperties.y;\n        this.elements.set('ropeText', this.ropeText);\n    }\n\n    protected createDenominationOptionButtonConfig(): IDenomOptionButtonConfig {\n        const texturesArr = this.componentConfiguration.denominationButtonPosition.textures;\n        const config = {\n            currency: this.rootStore.uiStore.currency,\n            denominations: this.rootStore.uiStore.denominations,\n            textures: Core.assets.getAssets(texturesArr),\n            shape: ButtonShapes.Circle,\n            denominationTitleTextStyle:\n                this.componentConfiguration.denominationOptionProperties.denominationTitleTextStyles,\n\n            denominationTextStyle: this.componentConfiguration.denominationOptionProperties.denominationTextStyles,\n\n            denominationTitleTextFontOffset:\n                this.componentConfiguration.denominationOptionProperties.denominationTitleTextFontOffset,\n            denominationTextVerticalOffset:\n                this.componentConfiguration.denominationOptionProperties.denominationTextVerticalOffset || 0,\n            denominationTextHorizontalOffset:\n                this.componentConfiguration.denominationOptionProperties.denominationTextHorizontalOffset || 0,\n            denominationTitleTextVerticalOffset:\n                this.componentConfiguration.denominationOptionProperties.denominationTitleTextVerticalOffset || 0,\n            haveText: this.componentConfiguration.denominationOptionProperties.haveText,\n        };\n        return config;\n    }\n\n    protected onStateChanged(): void {\n        // Features and GiftSpins to handle Buttons states\n        if (this.featureController.isControlInFeature) {\n            return;\n        }\n\n        switch (this.rootStore.uiStore.STATE.value) {\n            case UIState.IDLE:\n                this.spinButton.visible = true;\n                this.spinButton.enabled = true;\n                this.spinButton.state = ButtonStates.Normal;\n                this.spinSpeedButton.visible = true;\n                this.betPlusBtn.enabled = !this.isLastBet;\n                this.betMinusBtn.enabled = !this.isFirstBet;\n\n                if (this.instaSpinsButton) {\n                    this.instaSpinsButtonMode.texture = !this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED\n                        .value\n                        ? Core.assets.getAsset('blitzSpinButton').texture\n                        : Core.assets.getAsset('blitzSpinButtonDisabled').texture;\n                    this.instaSpinsButton.visible = true;\n                    this.instaSpinsButton.enabled =\n                        !this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value;\n                }\n\n                if (this.ropeText) {\n                    this.ropeText.visible = true;\n                } else {\n                    // Quick dirty fix, the whole logic about the rope text should be refactored.\n                    // ON-123471\n                    if (\n                        !this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value &&\n                        this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value === 0 &&\n                        !Core.flags.isActive(FeatureFlags.HIDE_HOLD_AND_PLAY)\n                    ) {\n                        this.createRopeText('HOLD FOR FAST PLAY');\n                        this.createRopeTextTween();\n                    }\n                }\n                if (this.spinBtnBonusText) {\n                    this.spinBtnBonusText.alpha = 1;\n                }\n                this.spinSpeedButtonDisabled.visible = false;\n                // this.spinButton.state = ButtonStates.Normal;\n                if (this.settings.autoplay === false) {\n                    this.autoPlayButton.visible = false;\n                    this.autoPlayButton.enabled = false;\n                } else {\n                    this.autoPlayButton.visible = true;\n                    this.autoPlayButton.enabled = true;\n                }\n                // this.turboAutoButton.visible = false;\n                // this.turboAutoButton.enabled = false;\n                // this.quickAutoButton.visible = false;\n                // this.quickAutoButton.enabled = false;\n                this.stopButton.visible = false;\n                this.skipButton.visible = false;\n                //  this.spinButtonAutoplayCounter.visible = false;\n                this.denominationButton.visible = true;\n                this.denominationButton.enabled = true;\n                this.collectSmallButton.visible = false;\n                break;\n            case UIState.BONUS_SUMMARY:\n                this.spinButton.visible = false;\n                this.spinSpeedButton.visible = false;\n                if (this.instaSpinsButton) {\n                    this.instaSpinsButton.visible = false;\n                }\n\n                this.spinSpeedButtonDisabled.visible = false;\n                this.autoPlayButton.visible = false;\n                this.betPlusBtn.enabled = false;\n                this.betMinusBtn.enabled = false;\n                // this.turboAutoButton.visible = false;\n                // this.quickAutoButton.visible = false;\n                this.stopButton.visible = false;\n                this.skipButton.visible = false;\n                // this.spinButtonAutoplayCounter.visible = false;\n                this.denominationButton.visible = false;\n                this.collectSmallButton.visible = false;\n                if (this.ropeText) {\n                    this.ropeText.visible = false;\n                }\n\n                break;\n\n            // remove this case if not needed after gift spins protocol changes\n            // applied and gift spins state machine is done\n            case UIState.COLLECT_BEFORE_IDLE:\n                this.betPlusBtn.enabled = !this.isLastBet;\n                this.betMinusBtn.enabled = !this.isFirstBet;\n                this.spinButton.visible = false;\n                this.autoPlayButton.visible = false;\n                // this.turboAutoButton.visible = false;\n                // this.quickAutoButton.visible = false;\n                this.stopButton.visible = false;\n                this.skipButton.visible = false;\n                // this.spinButtonAutoplayCounter.visible = false;\n                this.denominationButton.visible = false;\n                this.collectSmallButton.visible = false;\n                this.spinSpeedButtonDisabled.visible = false;\n                this.spinSpeedButton.visible = false;\n                if (this.instaSpinsButton) {\n                    this.instaSpinsButton.visible = false;\n                }\n\n                break;\n            case UIState.WAITING_FOR_RESPONSE:\n                this.betPlusBtn.enabled = false;\n                this.betMinusBtn.enabled = false;\n                this.spinButton.visible =\n                    (this.rootStore.uiStore.fastSpinMode || this.rootStore.uiStore.turboModeEnabled) &&\n                    this.rootStore.domainStore.SPIN_MODE.value === Features.MANUAL_SPIN;\n                this.spinButton.enabled = this.spinButton.visible && !this.rootStore.subjects.KEY_DOWN.value;\n                // this.spinButton.state = ButtonStates.Disabled;\n                //  this.spinButtonAutoplayCounter.visible = false;\n                if (this.settings.autoplay === false) {\n                    this.autoPlayButton.visible = false;\n                    this.autoPlayButton.enabled = false;\n                } else {\n                    this.autoPlayButton.visible = true;\n                    this.autoPlayButton.enabled = false;\n                }\n                if (this.instaSpinsButton) {\n                    this.instaSpinsButtonMode.texture = Core.assets.getAsset('blitzSpinButtonDisabled').texture;\n                    this.instaSpinsButton.visible = true;\n                    this.instaSpinsButton.enabled = false;\n                }\n\n                // this.turboAutoButton.visible = false;\n                // this.quickAutoButton.visible = false;\n                this.stopButton.visible = !this.spinButton.visible;\n                this.stopButton.enabled = this.stopButton.visible;\n                this.spinButton.enabled = true;\n                this.denominationButton.visible = true;\n                this.denominationButton.enabled = false;\n                this.skipButton.visible = false;\n                this.collectSmallButton.visible = false;\n                if (this.ropeText) {\n                    this.ropeText.visible = true;\n                }\n                // if (this.spinBtnBonusText) {\n                //     this.spinBtnBonusText.alpha = 1;\n                // }\n                break;\n            case UIState.WAITING_FOR_RESPONSE_IN_AUTOPLAY:\n                this.betPlusBtn.enabled = false;\n                this.betMinusBtn.enabled = false;\n                this.spinButton.visible = false;\n                if (this.settings.autoplay === false) {\n                    this.autoPlayButton.visible = false;\n                    this.autoPlayButton.enabled = false;\n                } else {\n                    this.autoPlayButton.visible = true;\n                    this.autoPlayButton.enabled = false;\n                }\n                if (this.instaSpinsButton) {\n                    this.instaSpinsButtonMode.texture = Core.assets.getAsset('blitzSpinButtonDisabled').texture;\n                    this.instaSpinsButton.visible = true;\n                    this.instaSpinsButton.enabled = false;\n                }\n\n                // this.turboAutoButton.visible = true;\n                // this.turboAutoButton.enabled = true;\n                // this.turboAutoButton.selected = this.rootStore.uiStore.turboModeEnabled;\n                // this.quickAutoButton.visible = true;\n                // this.quickAutoButton.enabled = true;\n                // this.quickAutoButton.selected = this.rootStore.subjects.TOGGLE_QUICK_SPIN.value;\n                this.stopButton.visible = true;\n                this.stopButton.enabled = true;\n                this.skipButton.visible = false;\n                // this.spinButtonAutoplayCounter.visible = true;\n                this.autoplayCounter.visible = this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value !== -1;\n                this.denominationButton.visible = true;\n                this.denominationButton.enabled = false;\n                this.collectSmallButton.visible = false;\n                break;\n\n            case UIState.WIN:\n                if (this.settings.autoplay === false) {\n                    this.betPlusBtn.enabled = !this.isLastBet;\n                    this.betMinusBtn.enabled = !this.isFirstBet;\n                } else {\n                    this.betPlusBtn.enabled = false;\n                    this.betMinusBtn.enabled = false;\n                }\n                this.spinButton.visible = true;\n                this.spinButton.enabled = true;\n                this.spinSpeedButton.visible = true;\n                this.spinSpeedButtonDisabled.visible = false;\n                if (this.instaSpinsButton) {\n                    this.instaSpinsButton.visible = true;\n                }\n\n                // this.spinButton.state = ButtonStates.Disabled;\n                this.autoPlayButton.visible = false;\n                this.stopButton.visible = false;\n                this.skipButton.visible = false;\n                this.denominationButton.visible = false;\n                // this.spinButtonAutoplayCounter.visible = false;\n                if (this.ropeText) {\n                    this.ropeText.visible = true;\n                }\n                if (this.spinBtnBonusText) {\n                    this.spinBtnBonusText.alpha = 1;\n                }\n                // this.turboAutoButton.visible = false;\n                // this.turboAutoButton.enabled = false;\n                // this.quickAutoButton.visible = false;\n                // this.quickAutoButton.enabled = false;\n                if (\n                    this.rootStore.domainStore.SPIN_MODE.value === Features.AUTO_PLAY\n                    // ||\n                    // this.rootStore.domainStore.SPIN_MODE.value === Features.FREE_SPINS\n                ) {\n                    this.stopButton.visible = true;\n                    this.stopButton.enabled = true;\n                    // this.spinButtonAutoplayCounter.visible = false;\n                    this.autoplayCounter.visible = this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value !== -1;\n                    this.spinButton.visible = false;\n                    this.denominationButton.visible = true;\n                    this.denominationButton.enabled = false;\n                    if (this.settings.autoplay === false) {\n                        this.autoPlayButton.visible = false;\n                        this.autoPlayButton.enabled = false;\n                    } else {\n                        this.autoPlayButton.visible = true;\n                        this.autoPlayButton.enabled = false;\n                    }\n                    // this.turboAutoButton.visible =\n                    //     this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value !== 0 ? true : false;\n                    // this.turboAutoButton.enabled =\n                    //     this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value !== 0 ? true : false;\n                    // this.quickAutoButton.visible =\n                    //     this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value !== 0 ? true : false;\n                    // this.quickAutoButton.enabled =\n                    //     this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value !== 0 ? true : false;\n                }\n\n                break;\n\n            case UIState.WAITING_FOR_COLLECT:\n                this.betPlusBtn.enabled = !this.isLastBet;\n                this.betMinusBtn.enabled = !this.isFirstBet;\n                this.stopButton.visible = false; // this.rootStore.uiStore.BANGUP_RUNNING.value;\n                this.stopButton.enabled = this.stopButton.visible;\n                this.spinButton.visible = !this.stopButton.visible;\n                this.skipButton.visible = false;\n                this.spinButton.enabled = this.spinButton.visible;\n                if (this.spinButton.visible) {\n                    this.spinButton.state = ButtonStates.Normal;\n                }\n                if (this.spinBtnBonusText && this.spinButton.visible) {\n                    this.spinBtnBonusText.alpha = 1;\n                }\n                if (this.instaSpinsButton) {\n                    this.instaSpinsButtonMode.texture = !this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED\n                        .value\n                        ? Core.assets.getAsset('blitzSpinButton').texture\n                        : Core.assets.getAsset('blitzSpinButtonDisabled').texture;\n                    this.instaSpinsButton.visible = true;\n                    this.instaSpinsButton.enabled =\n                        !this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value;\n                }\n\n                this.spinSpeedButton.visible = true;\n                this.spinSpeedButtonDisabled.visible = false;\n                // this.spinButton.state = ButtonStates.Normal;\n                this.collectSmallButton.visible = true;\n                this.collectSmallButton.enabled = true;\n                this.denominationButton.visible = false;\n                this.autoPlayButton.visible = false;\n                if (!Core.hasFeature(Features.GAMBLE) && this.settings.autoplay === true) {\n                    this.autoPlayButton.visible = true;\n                    this.autoPlayButton.enabled = false;\n                }\n                // this.turboAutoButton.visible = false;\n                // this.turboAutoButton.enabled = false;\n                // this.quickAutoButton.visible = false;\n                // this.quickAutoButton.enabled = false;\n                break;\n            case UIState.WAITING_FOR_COLLECT_IN_AUTOPLAY:\n                this.betPlusBtn.enabled = false;\n                this.betMinusBtn.enabled = false;\n                this.stopButton.visible = true;\n                this.stopButton.enabled = true;\n                this.spinButton.visible = false;\n                this.spinSpeedButton.visible = true;\n                this.spinSpeedButtonDisabled.visible = false;\n                this.skipButton.visible = false;\n                if (this.instaSpinsButton) {\n                    this.instaSpinsButton.visible = true;\n                }\n\n                //  this.spinButtonAutoplayCounter.visible = false;\n                this.autoplayCounter.visible = this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.value !== -1;\n                // this.turboAutoButton.visible = true;\n                // this.turboAutoButton.enabled = true;\n                // this.quickAutoButton.visible = true;\n                // this.quickAutoButton.enabled = true;\n                break;\n\n            case UIState.WAITING_FOR_STATE_CHANGE:\n                this.betPlusBtn.enabled = false;\n                this.betMinusBtn.enabled = false;\n                this.spinButton.visible = false;\n                this.spinSpeedButton.visible = false;\n                this.spinSpeedButtonDisabled.visible = false;\n                if (this.instaSpinsButton) {\n                    this.instaSpinsButton.visible = false;\n                }\n\n                this.autoPlayButton.visible = false;\n                this.stopButton.visible = false;\n                this.skipButton.visible = false;\n                //  this.spinButtonAutoplayCounter.visible = false;\n                this.denominationButton.visible = false;\n                this.collectSmallButton.visible = false;\n                break;\n            case UIState.DISABLED:\n            case UIState.SLIDING_BETS:\n                this.betPlusBtn.enabled = false;\n                this.betMinusBtn.enabled = false;\n                this.spinButton.enabled = false;\n                this.autoPlayButton.enabled = false;\n                this.stopButton.enabled = false;\n                this.skipButton.enabled = false;\n                this.denominationButton.enabled = false;\n                this.collectSmallButton.enabled = false;\n                if (this.instaSpinsButton) {\n                    //this.instaSpinsButtonMode.texture = Core.assets.getAsset('blitzSpinButton').texture;\n                    this.instaSpinsButtonMode.texture = Core.assets.getAsset('blitzSpinButtonDisabled').texture;\n                    this.instaSpinsButton.visible = true;\n                    this.instaSpinsButton.enabled = false;\n                }\n\n                if (this.ropeText) {\n                    this.ropeText.visible = false;\n                }\n                if (this.spinBtnBonusText) {\n                    this.spinBtnBonusText.alpha = 0.4;\n                }\n                break;\n        }\n        if (this.instaSpinsButton) {\n            this.instaSpinsButton.buttonMode = this.instaSpinsButton.enabled;\n        }\n    }\n\n    protected onAutoplayBetCounterChanged(autoplayBetCounter: number): void {\n        if (autoplayBetCounter < 0 || this.rootStore.domainStore.SERVER_STATE.value === ServerState.FREESPIN) {\n            this.autoplayCounter.visible = false;\n            // this.spinButtonAutoplayCounter.visible = false;\n            this.rootStore.uiStore.autoPlayFromSettings = false;\n        } else if (this.rootStore.uiStore.autoPlayFromSettings) {\n            this.autoplayCounter.visible = true;\n            //  this.spinButtonAutoplayCounter.text = autoplayBetCounter.toString();\n            this.autoplayCounter.text = autoplayBetCounter.toString();\n            //  this.autoplayCounter.x = (this.spinButton.width - this.autoplayCounter.width) / 2;\n            //   this.spinButtonAutoplayCounter.x = (this.spinButton.width - this.spinButtonAutoplayCounter.width) / 2;\n        } else {\n            this.autoplayCounter.visible = true;\n            this.autoplayCounter.text = autoplayBetCounter.toString();\n            //  this.autoplayCounter.x = (this.spinButton.width - this.autoplayCounter.width) / 2;\n        }\n        if (autoplayBetCounter < 1) {\n            this.autoplayCounter.visible = false;\n            //  this.spinButtonAutoplayCounter.visible = false;\n        }\n        this.autoplayCounter.pivot.set(this.autoplayCounter.width / 2, this.autoplayCounter.textBounds.height / 2);\n        this.autoplayCounter.x = this.componentConfiguration.autoplayTextProperties.x;\n        this.autoplayCounter.y = this.componentConfiguration.autoplayTextProperties.y;\n    }\n\n    private setProperties(val): void {\n        // do not change autoplay buttton if autoplay is not enabled\n        if (val.name === 'autoPlayButton' && this.settings.autoplay === false) {\n            return;\n        }\n        if (val.name === 'instaSpinsButton' && this.instaSpins) {\n            const actions = Array.isArray(val.actions) ? val.actions : [val.actions];\n            if (actions.indexOf('enabled') > -1) {\n                const enabled = val.values && !this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value;\n                this.instaSpinsButtonMode.texture = enabled\n                    ? Core.assets.getAsset('blitzSpinButton').texture\n                    : Core.assets.getAsset('blitzSpinButtonDisabled').texture;\n                this.instaSpinsButton.enabled = enabled;\n                this.instaSpinsButton.buttonMode = enabled;\n            }\n            if (actions.indexOf('visible') > -1) {\n                this.instaSpinsButton.visible = val.values;\n            }\n            return;\n        }\n\n        const found = this.elements.get(val.name);\n        if (found) {\n            /*  if (val.update !== undefined) {\n                found['sendUpdate'] = val.update;\n            } */\n            if (Array.isArray(val.actions)) {\n                let i = 0;\n                val.actions.forEach((action) => {\n                    found[action] =\n                        val.values[i] !== undefined\n                            ? val.values[i]\n                            : Array.isArray(val.values)\n                              ? val.values[0]\n                              : val.values;\n                    i++;\n                });\n            } else {\n                found[val.actions] = val.values;\n            }\n            // found['sendUpdate'] = true;\n        }\n    }\n\n    private getChildProperty(val): void {\n        if (this[val.name] && val.value === undefined && this[val.name][val.property] !== undefined) {\n            this.rootStore.subjects.GET_UI_VIEW_COMPONENT_STATE.next({\n                name: val.name,\n                value: this[val.name][val.property],\n            });\n        }\n    }\n\n    private onBuyBonusModeChanges(): void {\n        if (!Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS)) {\n            return;\n        }\n        if (this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value) {\n            this.spinButton.setTextures(\n                Core.assets.getAssets(this.componentConfiguration.spinButtonPosition.texturesSpecial),\n            );\n            this.spinButton.setBackgroundTextures([\n                Core.assets.getAsset(this.componentConfiguration.spinButtonPosition.backgroundTextureSpecial).texture,\n            ]);\n            this.stopButton.setTextures(\n                Core.assets.getAssets(this.componentConfiguration.stopButtonPosition.texturesSpecial),\n            );\n            this.spinBtnArrowsRotation();\n            this.skipButton.setTextures(Core.assets.getAssets(['svgSpinSkipAnimationButtonSpecial']));\n\n            // this.ropeText.tint = Number(\n            //     this.componentConfiguration.ropeTextProperties.activeBuyBonusColor.toString().replace('#', '0x'),\n            // );\n            if (this.spinBtnBonusText) {\n                this.spinBtnBonusText.tint = Number(\n                    this.componentConfiguration.ropeTextProperties.activeBuyBonusColor.toString().replace('#', '0x'),\n                );\n            }\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'instaSpinsButton',\n                actions: 'enabled',\n                values: false,\n            });\n        } else {\n            if (\n                this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value === 0 &&\n                !Core.flags.isActive(FeatureFlags.HIDE_HOLD_AND_PLAY)\n            ) {\n                this.killRopeTextTween();\n                this.destroyRopeText();\n                this.createRopeText('HOLD FOR FAST PLAY');\n                this.createRopeTextTween();\n                // this.ropeText.tint = Number(\n                //     this.componentConfiguration.ropeTextProperties.style.fill.toString().replace('#', '0x'),\n                // );\n                if (this.spinBtnBonusText) {\n                    this.spinBtnBonusText.tint = Number(\n                        this.componentConfiguration.ropeTextProperties.style.fill.toString().replace('#', '0x'),\n                    );\n                }\n            }\n            this.spinButton.setTextures(Core.assets.getAssets(this.componentConfiguration.spinButtonPosition.textures));\n            this.spinButton.setBackgroundTextures([\n                Core.assets.getAsset(this.componentConfiguration.spinButtonPosition.backgroundTexture).texture,\n            ]);\n            this.stopButton.setTextures(Core.assets.getAssets(this.componentConfiguration.stopButtonPosition.textures));\n            this.skipButton.setTextures(Core.assets.getAssets(['svgSpinSkipAnimation']));\n            this.clearSpinBtnArrowAnim();\n            this.destroySpinBtnText();\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'instaSpinsButton',\n                actions: 'enabled',\n                values: true,\n            });\n        }\n\n        this.setLastBetButtonsState();\n    }\n\n    private onSpinButtonSpecialTextVisible(visible: boolean): void {\n        this.killRopeTextTween();\n        // this.createRopeTextTween();\n        this.destroyRopeText();\n        // this.createRopeText(_bonusText);\n        if (!this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value) {\n            return;\n        }\n        if (this.spinBtnBonusText) {\n            this.spinBtnBonusText.visible = visible;\n            return;\n        }\n\n        this.spinBtnBonusText = new PixiText(\n            Core.translator.translate('EXTENDED_MULTIPLE.BUY_BONUS.START_BONUS'),\n            new TextStyle(this.componentConfiguration.spinBtnBonusTextStyle.style),\n        );\n        this.spinBtnBonusText.x = this.componentConfiguration.spinBtnBonusTextStyle.x;\n        this.spinBtnBonusText.y = this.componentConfiguration.spinBtnBonusTextStyle.y;\n        this.spinBtnBonusText.pivot.set(this.spinBtnBonusText.width / 2, this.spinBtnBonusText.height / 2);\n        this.spinBtnBonusText.visible = visible;\n        if (this.spinBtnBonusText.width > this.spinButton.width - 70) {\n            this.spinBtnBonusText.scale.set((this.spinButton.width - 70) / this.spinBtnBonusText.width);\n        }\n        this.spinButton.addChild(this.spinBtnBonusText);\n    }\n\n    private destroySpinBtnText(): void {\n        if (this.spinBtnBonusText) {\n            this.spinButton.removeChild(this.spinBtnBonusText);\n            this.spinBtnBonusText.destroy();\n            // @ts-ignore\n            this.spinBtnBonusText = null;\n        }\n    }\n\n    private clearSpinBtnArrowAnim(): void {\n        if (this.spinButtonSpecialTweenTimer) {\n            Timers.clearTimeout(this.spinButtonSpecialTweenTimer);\n            this.spinButtonSpecialTweenTimer = null;\n        }\n        if (this.spinButtonSpecialTweenInterval) {\n            Timers.clearInterval(this.spinButtonSpecialTweenInterval);\n            this.spinButtonSpecialTweenInterval = null;\n        }\n        if (this.spinButtonSpecialTween) {\n            this.spinButtonSpecialTween.totalProgress(1);\n        }\n    }\n\n    private onBeforeSpin(): void {\n        this.clearSpinBtnArrowAnim();\n    }\n\n    private onFeatureComplete(): void {\n        this.clearSpinBtnArrowAnim();\n        this.spinBtnArrowsRotation();\n    }\n\n    private spinBtnArrowsRotation(): void {\n        if (this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value) {\n            this.spinButtonSpecialTweenTimer = Timers.setTimeout(() => {\n                this.rotateSpinBtnArrows();\n            }, 700);\n            this.spinButtonSpecialTweenInterval = Timers.setInterval(() => {\n                this.rotateSpinBtnArrows();\n            }, 10000);\n        }\n    }\n}\n","// Leaf import, not the '@egt/core' barrel: this module is evaluated inside the slot chunk while Core.ts\n// is still mid-evaluation, and FEATURE_FLAG_GROUPS reads the enum at module scope (see Core.ts import notes).\nimport { FeatureFlags } from 'core/src/egt/core/enums/FeatureFlags';\n\n/** A fixed display group of flags rendered as one section of read-only checkboxes. */\nexport interface IFeatureFlagGroupDef {\n    /** Exact header text rendered above the group. */\n    readonly label: string;\n    /** Ordered flags shown in this group; values are FeatureFlags enum members only. */\n    readonly flags: readonly FeatureFlags[];\n}\n\n/**\n * Single source of truth for which flags appear in which group and in what order.\n * Flag identities come exclusively from the FeatureFlags enum; no string literals are redefined,\n * so an identifier absent from the enum cannot be expressed here and therefore cannot be rendered.\n */\nexport const FEATURE_FLAG_GROUPS: readonly IFeatureFlagGroupDef[] = [\n    {\n        label: 'Feature Flags',\n        flags: [\n            FeatureFlags.ALLOW_GAMBLE,\n            FeatureFlags.ALLOW_TOURNAMENTS,\n            FeatureFlags.ALLOW_PRIZE_POPS,\n            FeatureFlags.ALLOW_GIFT_SPINS,\n            FeatureFlags.ALLOW_BRANDING,\n            FeatureFlags.ALLOW_AUTOPLAY_POPUP,\n            FeatureFlags.ALLOW_DENOMINATION_POPUP,\n            FeatureFlags.ALLOW_CUSTOM,\n            FeatureFlags.USE_TONE_JS,\n            FeatureFlags.USE_PIXI_7,\n            FeatureFlags.USE_IOS_HAND_CURSOR,\n            FeatureFlags.USE_ONE_DENOM,\n            FeatureFlags.USE_LEGACY_CUSTOM,\n        ],\n    },\n    {\n        label: 'Legacy Feature Flags',\n        flags: [\n            FeatureFlags.USE_DEFAULT_BET_ON_LOAD,\n            FeatureFlags.USE_PAYTABLE_ON_LOAD,\n            FeatureFlags.USE_NUMERIC_AUTOPLAY,\n            FeatureFlags.USE_AUTOPLAY,\n            FeatureFlags.USE_SA_FEATURE,\n        ],\n    },\n    {\n        label: 'Restrictive Flags',\n        flags: [\n            FeatureFlags.HIDE_HOLD_AND_PLAY,\n            FeatureFlags.HIDE_JACKPOT,\n            FeatureFlags.HIDE_BUY_BONUS,\n            FeatureFlags.HIDE_DOUBLE_CHANCE,\n        ],\n    },\n] as const;\n","import Core, { FeatureFlags } from '@egt/core';\n\n/** Fallback text when a flag has no usable description (Requirement 4.2: 1–200 chars). */\nexport const FALLBACK_DESCRIPTION = 'No description available for this flag.';\n\n/** True for null, undefined, empty, or whitespace-only strings (Requirements 3.6, 4.3). */\nfunction isBlank(value: string | null | undefined): boolean {\n    return value == null || value.trim().length === 0;\n}\n\n/**\n * Resolve a single flag's description from `Core.flags.get(flag).description`, never mutating the\n * store and never throwing. A throw (unknown/unregistered flag) or a blank description resolves to\n * the fallback, so the affordance stays interactive for every flag (Requirements 4.1, 4.4, 4.5).\n *\n * Mirrors the per-flag isolation pattern of `resolveFlagState.ts`: the `try/catch` keeps a single\n * throwing flag from interrupting resolution of the remaining flags (Requirements 3.3, 3.6, 4.1).\n */\nexport function resolveFlagDescription(flag: FeatureFlags): string {\n    try {\n        const description = Core.flags.get(flag).description;\n        return isBlank(description) ? FALLBACK_DESCRIPTION : description;\n    } catch {\n        return FALLBACK_DESCRIPTION;\n    }\n}\n","import Core, { FeatureFlags } from '@egt/core';\n\n/**\n * A single flag's checked state resolved from `Core.flags`, ready for read-only rendering.\n * Pure, framework-free data so the resolution logic is independent of React.\n */\nexport interface IResolvedFlag {\n    /** Enum member identity (Requirement 6.5). */\n    flag: FeatureFlags;\n    /** Visible label equals the enum key (Requirement 2.5). */\n    label: string;\n    /** True iff the flag is registered AND active (Requirement 3.1–3.3, 5.2). */\n    checked: boolean;\n    /** True when isActive threw for this flag (Requirement 3.6). */\n    errored: boolean;\n    /** Resolved description (fallback-applied, always non-blank) for the description tooltip (Requirements 2.3, 3.3). */\n    description: string;\n}\n\n/**\n * Resolve a single flag's checked state by reading `Core.flags.isActive`, never mutating the store.\n *\n * `isActive` already encodes: active registered flag → `true`; registered-but-inactive → `false`;\n * unregistered-but-valid → `false` (Requirement 3.1–3.3, 5.2). The `try/catch` isolates a throw to\n * this one flag so the rest of the tab still renders (Requirement 3.6, 5.1, 5.4).\n *\n * Resolves only the checked-state projection (`description` is owned by the tab layer via\n * `resolveFlagDescription`), so the return type omits `description` from `IResolvedFlag`.\n */\nexport function resolveFlagState(flag: FeatureFlags): Omit<IResolvedFlag, 'description'> {\n    try {\n        return { flag, label: flag, checked: Core.flags.isActive(flag), errored: false };\n    } catch {\n        // Throw isolates to this one flag: unchecked + flagged as unreadable.\n        return { flag, label: flag, checked: false, errored: true };\n    }\n}\n","import BaseFeature from 'core/src/egt/core/BaseFeature';\nimport BaseFeatures from 'core/src/egt/core/enums/BaseFeatures';\nimport { Lifecycle } from 'tsyringe';\nimport CustomResultController from './controller/CustomResultController';\nimport CustomResultView from './view/CustomResultView';\n\nexport default class CustomResultFeature extends BaseFeature {\n    public featureType = BaseFeatures.CUSTOM_RESULT;\n    private view: CustomResultView | null;\n    private controller: CustomResultController | null;\n\n    // private gameSettings: any;\n\n    constructor() {\n        super();\n    }\n\n    public onRegisterDependencies(container: any): void {\n        super.onRegisterDependencies(container);\n        // super.onRegisterDependencies(container);\n\n        if (!this.dependencyContainer.isRegistered('CustomResultView')) {\n            this.dependencyContainer.register(\n                'CustomResultView',\n                { useClass: CustomResultView },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n        if (!this.dependencyContainer.isRegistered('CustomResultController')) {\n            this.dependencyContainer.register(\n                'CustomResultController',\n                { useClass: CustomResultController },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n    }\n\n    public onResolveDependencies(_container: any): void {\n        this.view = this.dependencyContainer.resolve('CustomResultView');\n        this.controller = this.dependencyContainer.resolve('CustomResultController');\n    }\n\n    public onInitComplete(): void {\n        this.controller?.startFeature();\n    }\n\n    public destroy(): void {\n        this.controller?.destroy();\n        this.view = null;\n        this.controller = null;\n    }\n}\n","import Core from '@egt/core';\nimport BaseController from 'core/src/egt/core/BaseController';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport CustomResultView from '../view/CustomResultView';\n\n@injectable()\nexport default class CustomResultController extends BaseController {\n    public ready: () => Promise<void>;\n\n    constructor(@inject('CustomResultView') protected view: CustomResultView) {\n        super(view);\n    }\n    public destroy(): void {\n        super.destroy();\n    }\n\n    public startFeature(): void {\n        this.view.init();\n        this.view.openBut.onclick = () => {\n            this.openHolder();\n        };\n\n        this.view.fastFBut.onclick = () => {\n            if (Core.stage.ticker.speed === 1) {\n                Core?.devTools?.speedUp();\n                this.view.fastFBut.classList.add('red');\n            } else {\n                Core?.devTools?.speedReset();\n                this.view.fastFBut.classList.remove('red');\n            }\n        };\n\n        this.view.tabsArray.forEach((tab, index) => {\n            tab.button.onclick = () => {\n                this.toggleTabs(index);\n            };\n        });\n\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n        Core.MEDIA_INFO_UPDATED.pipe(takeUntil(this.DESTROY)).subscribe(this.resizeView.bind(this));\n    }\n\n    public openHolder(): void {\n        this.view.toggleHolder();\n    }\n    public setOrientation(): void {\n        this.view.setOrientation();\n    }\n\n    public resizeView(): void {\n        this.view.resizeView();\n    }\n\n    public toggleTabs(index): void {\n        this.view.toggleTab(index);\n    }\n}\n","import { Subject } from 'rxjs';\n\nexport default class CustomResultContentView {\n    public readonly DESTROY: Subject<void> = new Subject<void>();\n    constructor(public view: HTMLDivElement) {\n        //\n    }\n    public resizeView(): void {\n        // Implement\n    }\n\n    public destroy(): void {\n        this.DESTROY.next();\n        this.DESTROY.complete();\n        // @ts-ignore;\n        this.DESTROY = null;\n\n        if (this.view) {\n            this.view.remove();\n            this.view.innerHTML = '';\n            // @ts-ignore\n            this.view = null;\n        }\n        // Implement\n    }\n}\n","import Core, { Log } from '@egt/core';\nimport axios from 'axios';\nimport { Subject } from 'rxjs';\nimport { injectable } from 'tsyringe';\nimport CustomResultContentView from './CustomResultContentView';\n\n@injectable()\nexport default class CustomResultView {\n    public name: string;\n    public readonly DESTROY: Subject<void> = new Subject<void>();\n\n    public openBut: HTMLDivElement;\n    public fastFBut: HTMLDivElement;\n    public soundsVersionList: HTMLElement;\n    public title = 'Custom result view';\n    public tabsArray: any[] = [];\n    public tabsHolder: HTMLDivElement;\n    public contentHolder: HTMLDivElement;\n    public customViewHolder: HTMLDivElement;\n    public elementsAdded: boolean = false;\n    public contentView: CustomResultContentView;\n\n    public closed: boolean = true;\n\n    private subscribtiion: any;\n\n    constructor() {\n        this.subscribtiion = Core.ON_GAME_UNLOADED.subscribe(this.destroy.bind(this));\n    }\n    public init(): void {\n        this.generateForm();\n    }\n\n    public destroy(): void {\n        this.subscribtiion.complete();\n        // @ts-ignore\n        this.subscribtiion = null;\n        let divHolder = document.getElementById('customViewHolder');\n        if (divHolder) {\n            divHolder.innerHTML = '';\n            document.body.removeChild(divHolder);\n            // @ts-ignore\n            divHolder = null;\n        }\n        if (this.openBut) {\n            this.openBut.onclick = null;\n            this.openBut.remove();\n            this.openBut.innerHTML = '';\n            // @ts-ignore\n            this.openBut = null;\n        }\n\n        if (this.fastFBut) {\n            this.fastFBut.onclick = null;\n            this.fastFBut.remove();\n            this.fastFBut.innerHTML = '';\n            // @ts-ignore\n            this.fastFBut = null;\n        }\n        if (this.title) {\n            // @ts-ignore\n            this.title = null;\n        }\n\n        if (this.tabsArray.length) {\n            this.tabsArray.forEach((tab) => {\n                tab.button.onclick = null;\n                // tab?.remove();\n                tab = null;\n            });\n\n            this.tabsArray = [];\n            // @ts-ignore\n            this.tabsArray = null;\n        }\n\n        if (this.tabsHolder) {\n            this.tabsHolder.remove();\n            this.tabsHolder.innerHTML = '';\n            // @ts-ignore\n            this.tabsHolder = null;\n        }\n\n        if (this.contentHolder) {\n            this.contentHolder.remove();\n            this.contentHolder.innerHTML = '';\n            // @ts-ignore\n            this.contentHolder = null;\n        }\n\n        if (this.customViewHolder) {\n            this.customViewHolder.remove();\n            this.customViewHolder.innerHTML = '';\n            // @ts-ignore\n            this.customViewHolder = null;\n        }\n        if (this.elementsAdded) {\n            this.elementsAdded = false;\n            // @ts-ignore\n            this.elementsAdded = null;\n        }\n\n        if (this.contentView) {\n            this.contentView.destroy();\n            // @ts-ignore\n            this.contentView = null;\n        }\n        if (this.DESTROY) {\n            this.DESTROY.complete();\n            // @ts-ignore\n            this.DESTROY = null;\n        }\n        // super.destroy();\n    }\n\n    private getUrlParamValue(param: string): string {\n        const url = new URL(window.location.href);\n        return url.searchParams.get(param) || '';\n    }\n\n    /**\n     * Get the sound version path, trying to fetch them on remote first.\n     */\n    private async getSoundVersionListPath(): Promise<string> {\n        const timestamp = Date.now();\n        const originalPath =\n            '/assets/' + Core.configuration.gameKey + '/sounds/versions.json?' + Core.hash + '&time=' + timestamp;\n        if (Core.customResourcesHost && this.getUrlParamValue('replaceAssets') === 'true') {\n            try {\n                const remotePath = (window as any).ssi.CustomResourcesHost + originalPath;\n                const response = await fetch(remotePath, { method: 'HEAD' });\n                if (response.ok) {\n                    return remotePath;\n                } else {\n                    return originalPath;\n                }\n            } catch (_err) {\n                return originalPath;\n            }\n        } else {\n            return originalPath;\n        }\n    }\n\n    /**\n     * Generates a list of sound versions by fetching data from a JSON file.\n     */\n    private genereteSoundVersionList(): void {\n        this.getSoundVersionListPath().then((path) => {\n            return axios\n                .get(path)\n                .then((response) => {\n                    // Handle response\n                    this.createListFromVersions(response.data);\n                    // console.log(response.data);\n                })\n                .catch((_err) => {\n                    Core.localStorage.removeSetting('overwriteSounds');\n                    // Handle errors\n                    Log.warn(\n                        `[SOUND]: ../assets/${Core.configuration.gameKey}/sounds/versions.json was not found `,\n                        this.constructor.name,\n                        _err,\n                    );\n                });\n        });\n    }\n\n    /**\n     * Creates a select element based on the provided object and handles event listeners\n     * @param {Object} obj - Object containing versions data\n     * @returns void\n     */\n\n    private createListFromVersions(obj): void {\n        this.soundsVersionList = this.createSelectElement();\n        const readFromStorage = Core.localStorage.readSetting('overwriteSounds');\n        let selectedOption = false;\n\n        Object.entries(obj).forEach(([key]) => {\n            const option = document.createElement('option');\n            option.value = key;\n            option.text = key;\n\n            if (readFromStorage?.option === key) {\n                option.selected = true;\n                selectedOption = true;\n            }\n\n            this.soundsVersionList.appendChild(option);\n        });\n\n        if (!selectedOption) {\n            const defaultVersion = Object.keys(obj)[0];\n            this.fetchDataAndReload(defaultVersion, obj);\n        }\n\n        this.soundsVersionList.onchange = (event) => {\n            // @ts-ignore\n            this.fetchDataAndReload(event.target.value, obj);\n        };\n\n        document.getElementById('app-root')?.insertAdjacentElement('afterbegin', this.soundsVersionList);\n    }\n\n    private createSelectElement(): HTMLSelectElement {\n        const soundsVersionList = document.createElement('select');\n        soundsVersionList.id = 'soundsVersion';\n        return soundsVersionList;\n    }\n    /**\n     * Fetches data and reloads the page based on the provided version and object.\n     * @param {string} version - The version to fetch data for.\n     * @param {Object} obj - The object containing the paths.\n     * @returns {Promise<void>} - A promise that resolves once the data is fetched and the page is reloaded.\n     */\n    private async fetchDataAndReload(version, obj): Promise<void> {\n        const pathToOverwrite = obj[version].path;\n\n        try {\n            const results = await axios.get(pathToOverwrite.split('.mp3').join('.json?') + Core.hash);\n            const jsonData = results.data;\n\n            Core.localStorage.writeSetting('overwriteSounds', {\n                option: version,\n                path: pathToOverwrite,\n                sprite: jsonData.sprite,\n            });\n\n            location.reload();\n        } catch (error) {\n            Log.error(error, this.constructor.name, error);\n            Core.localStorage.removeSetting('overwriteSounds');\n        }\n    }\n\n    public generateForm(): void {\n        if (!this.customViewHolder) {\n            this.customViewHolder = document.createElement('div') as HTMLDivElement;\n            this.customViewHolder.id = 'customViewHolder';\n            this.openBut = document.createElement('div') as HTMLDivElement;\n            this.openBut.className = 'openBut';\n            this.openBut.innerHTML = 'Custom';\n            // this.openBut.appendChild()\n\n            this.genereteSoundVersionList();\n\n            this.fastFBut = document.createElement('div') as HTMLDivElement;\n            this.fastFBut.className = 'fastFBut';\n            this.fastFBut.innerHTML = 'Speed Up';\n            if (Core.environment.isIOSScrollLayout() && !Core.configuration.multiplayer) {\n                this.customViewHolder.style.top = '25vh';\n            }\n            this.customViewHolder.insertAdjacentElement('afterbegin', this.openBut);\n            this.customViewHolder.insertAdjacentElement('afterbegin', this.fastFBut);\n            document.body.insertAdjacentElement('afterbegin', this.customViewHolder);\n        }\n\n        this.tabsHolder = document.createElement('div') as HTMLDivElement;\n        this.tabsHolder.className = 'tabs hide-scrollbar';\n        this.customViewHolder.appendChild(this.tabsHolder);\n\n        this.contentHolder = document.createElement('div') as HTMLDivElement;\n        this.contentHolder.className = 'content hide-scrollbar';\n        this.contentHolder.style.overflowY = 'scroll';\n\n        this.customViewHolder.appendChild(this.contentHolder);\n    }\n\n    public generateTabs(): void {\n        const tabSettings = document.createElement('span') as HTMLDivElement;\n        tabSettings.innerText = 'Settings';\n        tabSettings.className = 'tab';\n        this.tabsHolder.appendChild(tabSettings);\n        this.tabsArray.push({ action: this.setContentSettings.bind(this), button: tabSettings, type: 'Settings' });\n    }\n\n    public setOrientation(): void {\n        this.resizeView();\n    }\n\n    public resizeView(): void {\n        this.contentView?.resizeView();\n    }\n\n    public setContentSettings(): void {\n        //\n    }\n\n    public setContentOthers(): void {\n        const title = document.createElement('span') as HTMLDivElement;\n        title.innerText = 'Comming soon ...';\n        title.className = 'tabInnerTitle';\n        this.contentHolder.appendChild(title);\n    }\n\n    public toggleTab(index): void {\n        this.tabsArray.forEach((tab) => {\n            tab.button.className = 'tab';\n        });\n        this.tabsArray[index].button.className = 'tab active';\n        this.tabsArray[index].action();\n    }\n\n    public clearContent(): void {\n        this.contentHolder.innerHTML = '';\n    }\n\n    public toggleHolder(): void {\n        if (this.closed) {\n            this.customViewHolder.style.left = '0';\n            this.openBut.style.right = '0';\n            this.fastFBut.style.right = '0';\n        } else {\n            this.customViewHolder.style.left = '-100%';\n            this.openBut.style.right = '-23px';\n            this.fastFBut.style.right = '-23px';\n        }\n        this.closed = !this.closed;\n    }\n}\n","import CustomResultFeature from './custom-result/CustomResultFeature';\n\nimport CustomResultController from './custom-result/controller/CustomResultController';\nimport CustomResultContentView from './custom-result/view/CustomResultContentView';\nimport CustomResultView from './custom-result/view/CustomResultView';\nimport(\n    /* webpackChunkName: \"features/custom-result-styles\" */\n\n    './custom-result/styles.js'\n);\nexport { CustomResultController, CustomResultView, CustomResultContentView };\nexport default CustomResultFeature;\n","import GLHook from './GLHook';\nimport TextureHook from './TextureHook';\n\nexport default class BaseHooks {\n    protected _drawCalls: number = -1;\n    protected _maxDeltaDrawCalls: number = -1;\n    protected glhook?: GLHook;\n    protected texturehook?: TextureHook;\n\n    // biome-ignore lint/suspicious/noEmptyBlockStatements: <explanation>\n    constructor() {}\n\n    public attach(gl: any): void {\n        this.glhook = new GLHook(gl);\n        this.texturehook = new TextureHook(gl);\n    }\n\n    public get drawCalls(): number {\n        if (this.glhook && this.glhook.isInit) {\n            return this.glhook.drawPasses;\n        }\n        return -1;\n    }\n\n    public get maxDeltaDrawCalls(): number {\n        return this._maxDeltaDrawCalls;\n    }\n\n    public get deltaDrawCalls(): number {\n        if (this._drawCalls === -1) {\n            this._drawCalls = this.drawCalls;\n            return 0;\n        }\n\n        const dc: number = this.drawCalls;\n        const delta: number = dc - this._drawCalls;\n        this._drawCalls = dc;\n\n        this._maxDeltaDrawCalls = Math.max(this._maxDeltaDrawCalls, delta);\n        return delta;\n    }\n\n    public get maxTextureCount(): number {\n        if (this.texturehook && this.texturehook.isInit) {\n            return this.texturehook.maxTexturesCount;\n        }\n        return 0;\n    }\n\n    public get texturesCount(): number {\n        if (this.texturehook && this.texturehook.isInit) {\n            return this.texturehook.currentTextureCount;\n        }\n\n        return 0;\n    }\n    public reset(): void {\n        this._maxDeltaDrawCalls = -1;\n        this._drawCalls = -1;\n\n        if (this.glhook) {\n            this.glhook.reset();\n        }\n        if (this.texturehook) {\n            this.texturehook.reset();\n        }\n    }\n\n    public release(): void {\n        if (this.glhook) {\n            this.glhook.release();\n        }\n        if (this.texturehook) {\n            this.texturehook.release();\n        }\n    }\n}\n","import Core, { IDeveloperTools, IEnvironment } from '@egt/core';\nimport MetricsDebugPanel from '../../../../../src/egt/core/metrics/MetricsDebugPanel';\nimport gsap from 'gsap';\n\nimport { TestConsoleViewer } from '../';\nimport LeakRadar from './leak-radar/LeakRadar';\nimport MediaInfoViewer from './MediaInfoViewer';\nimport { Subject } from 'rxjs';\n\n// @injectable()\nexport default class DeveloperTools implements IDeveloperTools {\n    public consoleViewer: TestConsoleViewer;\n    public OPEN_CUSTOM_SCALER: Subject<any> = new Subject();\n\n    private showConsole: boolean = false;\n    private showMediaInfo: boolean = false;\n    private showFpsInfo: boolean = false;\n    private showMetricsDebug: boolean = false;\n    private mediaInfoViewer: MediaInfoViewer;\n    // private performanceViewer: PerfomanceViewer;\n\n    constructor(private _environment: IEnvironment) {\n        Core.MEDIA_INFO_UPDATED.subscribe((data) => {\n            this.mediaInfoViewer.update(data);\n        });\n        // Core.PERFORMANCE_METRICS.pipe(sampleTime(100)).subscribe((data) => {\n        //     // optional — the legacy viewer is no longer constructed (see init())\n        //     this.performanceViewer?.update(data);\n        // });\n        // Core.ON_SERVER_RESPONSE.subscribe(data => {\n        //     this.consoleView.update(data);\n        // });\n\n        // @ts-ignore\n        window.Core = Core;\n    }\n\n    public init(): void {\n        this.mediaInfoViewer = new MediaInfoViewer(this._environment);\n        // Runtime Stats replaced this meter, so the viewer is no longer built:\n        // it injects a #perf-info div that only its own toggle used to hide (so\n        // it would now sit on top of the game), and it costs 10Hz of DOM writes\n        // for a panel nobody reads. The class and its CSS are untouched —\n        // restore the legacy meter by uncommenting the line below and the one in\n        // toggleFpsInfo().\n        // this.performanceViewer = new PerfomanceViewer();\n        // this.consoleViewer = new TestConsoleViewer();\n        this.toggleMediaInfo(this.showMediaInfo);\n        this.toggleFpsInfo(this.showFpsInfo);\n        this.toggleConsole(this.showConsole);\n        this.toggleMetricsDebug(this.showMetricsDebug);\n        if (Core.configuration.devTools) {\n            // Prepares the (hidden) Leak Radar panel; the probes install lazily\n            // on first open (key \"L\", the custom-scaler button, or the URL flag).\n            LeakRadar.instance.init();\n            this.attachListeners();\n            // ?leakRadar=1 opens it right away — the way to use it on a real\n            // phone, where there is no keyboard for the \"L\" hotkey. Watching the\n            // loading phase is also exactly when iOS pressure spikes.\n            if (this.hasLeakRadarUrlFlag()) {\n                LeakRadar.instance.show();\n            }\n        }\n    }\n\n    public toggleLeakRadar(): void {\n        LeakRadar.instance.toggle();\n    }\n\n    /** True when the URL contains ?leakRadar / ?runtimeStats (case-insensitive, unless =0/false/off/no). */\n    private hasLeakRadarUrlFlag(): boolean {\n        try {\n            let on = false;\n            new URLSearchParams(window.location.search).forEach((value, key) => {\n                const k = key.toLowerCase();\n                if ((k === 'leakradar' || k === 'runtimestats') && !/^(0|false|off|no)$/i.test(value || '')) {\n                    on = true;\n                }\n            });\n            return on;\n        } catch (_e) {\n            return false;\n        }\n    }\n\n    public toggleMediaInfo(isOpened: boolean): void {\n        if (isOpened) {\n            this.mediaInfoViewer.show();\n        } else {\n            this.mediaInfoViewer.hide();\n        }\n    }\n\n    public toggleFpsInfo(isOpened: boolean): void {\n        // The FPS toggle now drives Runtime Stats (Leak Radar) instead of the\n        // legacy #perf-info meter. The old PerformanceViewer stays fully wired\n        // (constructed above and fed by PERFORMANCE_METRICS) — to bring it back,\n        // restore the original line:\n        // document.getElementById('perf-info')?.style.setProperty('display', isOpened ? 'block' : ' none');\n        if (isOpened) {\n            LeakRadar.instance.show();\n        } else {\n            LeakRadar.instance.hide();\n        }\n    }\n\n    public toggleAnimSpeedButton(isOpened: boolean): void {\n        (document.getElementsByClassName('fastFBut')?.[0] as HTMLElement)?.style.setProperty(\n            'display',\n            isOpened ? 'block' : ' none',\n        );\n    }\n\n    public toggleConsole(isOpened: boolean): void {\n        if (isOpened) {\n            if (!this.consoleViewer) {\n                this.consoleViewer = new TestConsoleViewer();\n                this.consoleViewer.show();\n            }\n        } else if (this.consoleViewer) {\n            this.consoleViewer.hide();\n        }\n    }\n\n    public toggleMetricsDebug(isOpened: boolean): void {\n        if (isOpened) {\n            MetricsDebugPanel.attach();\n        } else {\n            MetricsDebugPanel.destroy();\n        }\n    }\n    public getSlotCustomResultContext(options: any, numberOfReels: number): any {\n        return {\n            'gamble.skip': true,\n            'demo.request': true,\n            'demo.custom': true,\n            // 'demo.custom.pick': true,\n            // 'demo.custom.respin': true,\n            // 'demo.custom.respin.pos': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19],\n            'demo.custom.reels': options,\n            'demo.custom.positions': new Array(numberOfReels).fill(1),\n        };\n    }\n\n    public getScratchCustomResultContext(options: {\n        playerSymbols: number[];\n        winningSymbols: number[];\n        winingValues: number[];\n    }): any {\n        const playerSymbols: Array<{ amount: number; symbol: number }> = [];\n        for (let i: number = 0; i < options.playerSymbols.length; i++) {\n            playerSymbols.push({\n                amount: options.winingValues[i] * Core.SELECTED_DENOMINATION.value,\n                symbol: options.playerSymbols[i],\n            });\n        }\n\n        return {\n            'demo.request': true,\n            'demo.custom.winningSymbols': options.winningSymbols,\n            'demo.custom.playerSymbols': playerSymbols,\n        };\n    }\n\n    /**\n     * Speeds up the global timeline\n     * should be used only for dev\n     */\n    public speedUp() {\n        gsap.globalTimeline.timeScale(5);\n        Core.stage.ticker.speed = 5;\n    }\n    private setSpeed = (speed: number) => {\n        if (gsap?.globalTimeline) {\n            gsap.globalTimeline.timeScale(speed);\n        }\n        if (Core?.stage?.ticker) {\n            Core.stage.ticker.speed = speed;\n        }\n    };\n\n    /**\n     * Resets the global timeline\n     * should be used only for dev\n     */\n    public speedReset = () => {\n        this.setSpeed(1);\n    };\n\n    protected onKeyDown: (event: KeyboardEvent) => void = ({ code, repeat }) => {\n        if (repeat) {\n            return;\n        }\n\n        switch (code) {\n            case 'KeyF':\n                this.setSpeed(5);\n                break;\n            case 'KeyG':\n                this.setSpeed(0.1);\n                break;\n            case 'KeyD':\n                gsap.ticker.tick();\n                gsap.ticker.sleep();\n                break;\n            case 'KeyL':\n                LeakRadar.instance.toggle();\n                break;\n        }\n    };\n\n    protected onKeyUp: (event: KeyboardEvent) => void = ({ code }) => {\n        if (code === 'KeyF' || code === 'KeyG') {\n            this.speedReset();\n        }\n    };\n\n    private attachListeners(): void {\n        window.removeEventListener('keydown', this.onKeyDown);\n        window.removeEventListener('keyup', this.onKeyDown);\n        // window.removeEventListener('blur', this.speedReset);\n\n        window.addEventListener('keydown', this.onKeyDown);\n        window.addEventListener('keyup', this.onKeyUp);\n        // window.addEventListener('blur', this.speedReset);\n    }\n}\n","import { Log } from '@egt/core';\n\nexport default class GLHook {\n    public drawPasses: number = 0;\n    public isInit: boolean = false;\n\n    private gl: any;\n\n    constructor(_gl?: any) {\n        if (_gl) {\n            if (_gl.__proto__.drawElements) {\n                this.gl = _gl;\n                this.realGLDrawElements = _gl.__proto__.drawElements;\n\n                // replace to new function\n                _gl.__proto__.drawElements = this.fakeGLdrawElements.bind(this);\n                this.isInit = true;\n\n                Log.debug('[GLHook] GL was Hooked!', this.constructor.name);\n            }\n        } else {\n            Log.error(\"[GLHook] GL can't be NULL\", this.constructor.name);\n        }\n    }\n    public reset(): void {\n        this.drawPasses = 0;\n    }\n\n    public release(): void {\n        if (this.isInit) {\n            this.gl.__proto__.drawElements = this.realGLDrawElements;\n            Log.debug('[GLHook] Hook was removed!', this.constructor.name);\n        }\n\n        this.isInit = false;\n    }\n    // biome-ignore lint/suspicious/noEmptyBlockStatements: <explanation>\n    private realGLDrawElements = (): void => {};\n\n    private fakeGLdrawElements(mode: any, count: any, type: any, offset: any): void {\n        this.drawPasses++;\n        this.realGLDrawElements.call(this.gl, mode, count, type, offset);\n    }\n}\n","import { DomHelpers, IEnvironment, IMediaInfoData } from '@egt/core';\n\n// // Polyfill\n// // @ts-ignore\n// if (!Math.gcd) {\n//     // @ts-ignore\n//     Math.gcd = (n: number, m: number) => {\n//         let r = 0;\n\n//         while (n !== 0) {\n//             r = m % n;\n//             m = n;\n//             n = r;\n//         }\n\n//         return m;\n//     };\n// }\n\nexport default class MediaInfoViewer {\n    private _rootContainer: HTMLElement;\n    private _textContainer: HTMLDivElement;\n    private _data: IMediaInfoData;\n\n    constructor(private _environment: IEnvironment) {\n        this._createContainer();\n    }\n\n    public destroy(): void {\n        if (this._rootContainer) {\n            // @ts-ignore\n            this._rootContainer = null;\n        }\n        if (this._textContainer) {\n            // @ts-ignore\n            this._textContainer = null;\n        }\n        if (this._data) {\n            // @ts-ignore\n            this._data = null;\n        }\n    }\n\n    public update(event): void {\n        this._data = event;\n        this._textContainer.innerHTML = this._getText();\n    }\n\n    public show(): void {\n        this._rootContainer.className = this._rootContainer.className.replace('hidden', '').trim();\n    }\n\n    public hide(): void {\n        this.show(); // to ensure we do not duplicate the style class\n        this._rootContainer.className += ' hidden';\n    }\n\n    private _createContainer(): void {\n        // root container\n        this._rootContainer = DomHelpers.getElementOrCreateNew('media-info', 'div');\n        this._rootContainer.className = 'media-info';\n\n        // close button\n        const closeBtn = document.createElement('button');\n        closeBtn.innerHTML = '[x]';\n        closeBtn.className = 'media-info-close-button button';\n        closeBtn.title = 'close';\n        closeBtn.onclick = this.hide.bind(this);\n        this._rootContainer.appendChild(closeBtn);\n\n        // info text\n        this._textContainer = document.createElement('div');\n        this._rootContainer.appendChild(this._textContainer);\n    }\n\n    private _getText(): string {\n        // @ts-ignore\n        // const stageInitialGCD: any = Math.gcd(this._data.display.stage.width, this._data.display.stage.height);\n        const browser: any = this._environment.getBrowser();\n        const os: any = this._environment.getOS();\n        const fullscreen: any = this._environment.isFullScreenSupported();\n        return (\n            `` +\n            `<div>[devicePixelRatio]: <span style=\"color:greenyellow\">${window.devicePixelRatio}</span></div>` +\n            `<div>[app.view]: <span style=\"color:greenyellow\">${this._data.display.view.width}x${this._data.display.view.height}</span></div>` +\n            `<div>[app.screen]: <span style=\"color:greenyellow\">${this._data.display.screen.width}x${this._data.display.screen.height}</div>` +\n            `<div>[current]:<span style=\"color:greenyellow\"> ${this._data.display.stage.currentWidth}x${this._data.display.stage.currentHeight}</span></div>` +\n            `<div>[scale]: <span style=\"color:greenyellow\">(${this._data.display.stage.scaleX}, ${this._data.display.stage.scaleY})</span></div>` +\n            `<div>[scaling]: <span style=\"color:greenyellow\">${this._data.display.stage.scaling}</span></div>` +\n            `<div>[alignment]:<span style=\"color:greenyellow\"> ${this._data.display.stage.alignment}</span></div>` +\n            `<div>[orientation]: <span style=\"color:greenyellow\">${this._data.display.stage.orientation}</span></div>` +\n            `<div>[browser]: <span style=\"color:greenyellow\">${browser.name} ${browser.major}</span></div>` +\n            `<div>[full screen]: <span style=\"color:greenyellow\">${fullscreen}</span></div>` +\n            `<div>[os]: <span style=\"color:greenyellow\">${os.name} ${os.version}</span></div>`\n        );\n    }\n}\n","// @ts-ignore (it's a peer dependency)\nimport { Log } from '@egt/core';\nimport { Renderer } from 'pixi.js';\nimport BaseHooks from './BaseHooks';\n\nexport default class PIXIHooks extends BaseHooks {\n    constructor(app: any) {\n        super();\n\n        if (!app) {\n            Log.error(\"PIXI Application can't passed or NULL\", this.constructor.name);\n            return;\n        }\n\n        if (app.renderer instanceof Renderer) {\n            this.attach(app.renderer.gl);\n\n            const start_textures = app.renderer.texture._managedTextures;\n\n            if (start_textures && this.texturehook) {\n                Log.debug('[PIXI Hooks] Collect used textures:', this.constructor.name, start_textures.length);\n                for (let i = 0; i < start_textures.length; ++i) {\n                    const txr = start_textures[i];\n                    const gltextures = txr._glTextures;\n\n                    for (let j = 0; j < gltextures.length; ++j) {\n                        if (gltextures[j].gl === app.renderer.gl) {\n                            this.texturehook.registerTexture(gltextures[j].texture);\n                        }\n                    }\n                }\n            }\n        } else {\n            Log.error('[PIXI Hook]Canvas renderer is not allowed', this.constructor.name);\n        }\n    }\n}\n","import Core, { DomHelpers } from '@egt/core';\nimport { ViewContainer } from '@egt/ui-lib';\nimport { fromEvent } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\n// import { Graphics, Text as PixiText, TextStyle } from 'pixi.js';\nimport { injectable } from 'tsyringe';\n\nimport JsonViewer from '../../../dev_assets/json-viewer.js';\n\n@injectable()\nexport default class TestConsoleViewer extends ViewContainer {\n    private _rootContainer: HTMLElement;\n    private _textContainer: HTMLDivElement;\n    private currentData: number = 0;\n    private maximumData: number = 2000;\n\n    public input: string;\n    public clearButton;\n    public _buttonContainer: HTMLDivElement;\n    public closeButton;\n    public dragButton;\n    public plusWidthButton;\n    public minusWidthButton;\n    private sizeIncrease: number = 4;\n    private heightConsole: number;\n\n    constructor() {\n        super();\n        this.createConsole();\n        this.setOrientation();\n        this.draggableConsole();\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n    }\n\n    public jsonLog(data, style, _isObject, datatext): void {\n        const tmp = {\n            message: data,\n            style,\n            value: datatext,\n        };\n\n        const dataTextStringified = JSON.stringify(tmp);\n        if (!this._rootContainer || this._rootContainer.className.includes(`hidden`)) {\n            return;\n        } else {\n            // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n            const jsonViewer = new JsonViewer({\n                container: this._textContainer,\n                data: dataTextStringified,\n                theme: 'dark',\n                expand: false,\n            });\n        }\n        if (dataTextStringified) {\n            this._textContainer.style.display = 'block';\n            this.currentData++;\n            if (this.currentData > this.maximumData) {\n                if (this._textContainer.firstChild) {\n                    this._textContainer.removeChild(this._textContainer.firstChild);\n                    this.currentData--;\n                }\n            }\n        }\n    }\n\n    public log(data, style): void {\n        this._textContainer.innerHTML += `<p style =\"${style}\">${data}</p>`;\n    }\n\n    /**\n     * Scroll the console up to the latest added element\n     */\n    updateScroll() {\n        this._textContainer.scrollTop = this._textContainer.scrollHeight;\n    }\n\n    public hideText(): void {\n        const today = new Date();\n        const time = today.getHours() + ':' + today.getMinutes() + ':' + today.getSeconds();\n        this._textContainer.innerHTML = '<b>' + time + '</b> ' + 'Console Has Been Cleared' + '<br><br>';\n        this.currentData = 0;\n    }\n\n    public setOrientation(): void {\n        if (Core.ORIENTATION.value.isPortrait) {\n            this.sizeIncrease = 6;\n            this._rootContainer.style.width = `${this.sizeIncrease}0%`;\n            this._rootContainer.style.top = '250px';\n            this._rootContainer.style.left = '100px';\n        } else if (Core.ORIENTATION.value.isLandscape) {\n            this.sizeIncrease = 4;\n            this._rootContainer.style.top = '180px';\n            this._rootContainer.style.left = '200px';\n            this._rootContainer.style.width = `${this.sizeIncrease}0%`;\n        }\n    }\n\n    public destroy(): void {\n        if (this._textContainer) {\n            this._textContainer.remove();\n            this._textContainer.innerHTML = '';\n            // @ts-ignore\n            this._textContainer = null;\n        }\n    }\n\n    public show(): void {\n        this._rootContainer.className = this._rootContainer.className.replace('consoleHidden', '').trim();\n        if (this._textContainer.innerHTML === '') {\n            this._textContainer.style.display = 'none';\n        }\n    }\n\n    public hide(): void {\n        this.show();\n        this._rootContainer.className += ' consoleHidden';\n    }\n\n    public enlarge(): void {\n        this.sizeIncrease = this.sizeIncrease + 1;\n        this._rootContainer.style.width = `${this.sizeIncrease}0%`;\n    }\n\n    public reduce(): void {\n        this.sizeIncrease = this.sizeIncrease - 1;\n        this._rootContainer.style.width = `${this.sizeIncrease}0%`;\n    }\n\n    private createConsole(): void {\n        // root container\n        this._rootContainer = DomHelpers.getElementOrCreateNew('console', 'div');\n        this._rootContainer.className = 'console';\n        this._rootContainer.getElementsByClassName('console');\n        this._rootContainer.style.width = `${this.sizeIncrease}0%`;\n        this._rootContainer.style.height = `40%`;\n\n        // buttonContainer\n\n        this._buttonContainer = DomHelpers.getElementOrCreateNew('buttonDiv', 'div');\n        this._buttonContainer.className = 'buttonDiv';\n        this._buttonContainer.getElementsByClassName('buttonDiv');\n\n        // closeButton\n\n        this.closeButton = document.createElement('button');\n        this.closeButton.innerHTML = 'EXIT';\n        this.closeButton.className = 'console-button close-button';\n        this.closeButton.title = 'close';\n        this.closeButton.onclick = this.hide.bind(this);\n        this._buttonContainer.appendChild(this.closeButton);\n\n        // clearButton\n\n        this.clearButton = document.createElement('button');\n        this.clearButton.innerHTML = 'CLEAR';\n        this.clearButton.className = 'console-button clear-info-button';\n        this.clearButton.title = 'close';\n        this.clearButton.onclick = this.hideText.bind(this);\n        this._buttonContainer.appendChild(this.clearButton);\n\n        // + button\n\n        this.plusWidthButton = document.createElement('button');\n        this.plusWidthButton.innerHTML = '+';\n        this.plusWidthButton.className = 'console-button plus-width-button';\n        this.plusWidthButton.title = 'width';\n\n        this.plusWidthButton.onclick = this.enlarge.bind(this);\n        this._buttonContainer.appendChild(this.plusWidthButton);\n\n        // - button\n\n        this.minusWidthButton = document.createElement('button');\n        this.minusWidthButton.innerHTML = '-';\n        this.minusWidthButton.className = 'console-button minus-width-button';\n        this.minusWidthButton.title = 'width';\n\n        this.minusWidthButton.onclick = this.reduce.bind(this);\n        this._buttonContainer.appendChild(this.minusWidthButton);\n\n        // drag button\n\n        this.dragButton = document.createElement('button');\n        this.dragButton.innerHTML = 'DRAG';\n        this.dragButton.className = 'console-button console-info-drag-button';\n        this.dragButton.setAttribute(`draggable`, `true`);\n        this.dragButton.title = 'drag';\n\n        this._buttonContainer.appendChild(this.dragButton);\n\n        // textContainer\n        this._textContainer = document.createElement('div');\n        this._rootContainer.appendChild(this._textContainer);\n        this._rootContainer.appendChild(this._buttonContainer);\n    }\n\n    private draggableConsole(): void {\n        this._rootContainer.id = 'console';\n\n        document.body.insertAdjacentElement('afterbegin', this._rootContainer);\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        let x;\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        let y;\n        fromEvent(this._rootContainer, 'dragstart').subscribe((e: any) => {\n            y = e.pageY;\n            x = e.pageX;\n        });\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/core/features/dev-tools/src/egt/dev-tools/TestConsoleViewer.ts:209:9\",(this.dragButton),\"touchstart\"]), fromEvent(this.dragButton, 'touchstart')).subscribe((e: any) => {\n            const evt = typeof e.originalEvent === 'undefined' ? e : e.originalEvent;\n            const touch = evt.touches[0] || evt.changedTouches[0];\n            y = touch.clientY;\n            x = touch.clientX;\n        });\n        fromEvent(this.dragButton, 'touchmove').subscribe((e: any) => {\n            const evt = typeof e.originalEvent === 'undefined' ? e : e.originalEvent;\n            // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n            const touch = evt.touches[0] || evt.changedTouches[0];\n            const touchLocation = e.targetTouches[0];\n            if (Core.ORIENTATION.value.isLandscape) {\n                this.heightConsole = (Core.display.screen.height / 100) * 40;\n                e.preventDefault();\n                e.stopPropagation();\n                this._rootContainer.style.top =\n                    touchLocation.pageY - this.heightConsole + this.dragButton.style.height / 2 + 'px';\n                this._rootContainer.style.left = touchLocation.pageX + this.dragButton.style.width / 2 + 'px';\n            } else {\n                this.heightConsole = (Core.display.screen.height / 100) * 40;\n                e.preventDefault();\n                e.stopPropagation();\n                this._rootContainer.style.top = touchLocation.pageY - this.heightConsole + 'px';\n                // @ts-ignore\n                this._rootContainer.style.left = touchLocation.pageX + 'px';\n            }\n            if (this._textContainer.style.display === 'none') {\n                this._rootContainer.style.top = touchLocation.pageY + this.dragButton.style.height / 2 + 'px';\n            }\n        });\n        fromEvent(document.body, 'dragover').subscribe((e: DragEvent) => {\n            if (Core.ORIENTATION.value.isLandscape) {\n                this.heightConsole = (Core.display.screen.height / 100) * 40;\n                e.preventDefault();\n                e.stopPropagation();\n                this._rootContainer.style.top = e.clientY - this.heightConsole + 'px';\n                this._rootContainer.style.left = e.clientX + 'px';\n            } else {\n                this.heightConsole = (Core.display.screen.height / 100) * 40;\n                e.preventDefault();\n                e.stopPropagation();\n                this._rootContainer.style.top = e.clientY - this.heightConsole + 'px';\n                this._rootContainer.style.left = e.clientX + 'px';\n            }\n            if (this._textContainer.style.display === 'none') {\n                this._rootContainer.style.top = e.clientY + this.dragButton.style.height / 2 + 'px';\n            }\n        });\n    }\n}\n","import { Log } from '@egt/core';\n\nexport default class TextureHook {\n    public get currentTextureCount(): number {\n        return this.createdTextures.length;\n    }\n    public createdTextures: any[] = [];\n    public maxTexturesCount: number = 0;\n\n    public isInit: boolean = false;\n\n    private gl: any;\n\n    constructor(_gl?: any) {\n        if (_gl) {\n            if (_gl.__proto__.createTexture) {\n                this.gl = _gl;\n                this.realGLCreateTexture = _gl.__proto__.createTexture;\n                this.realGLDeleteTexture = _gl.__proto__.deleteTexture;\n                // replace to new function\n                _gl.__proto__.createTexture = this.fakeGLCreateTexture.bind(this);\n                _gl.__proto__.deleteTexture = this.fakeGLDeleteTexture.bind(this);\n\n                this.isInit = true;\n\n                Log.debug('[TextureHook] GL was Hooked!', this.constructor.name);\n            }\n        } else {\n            Log.error(\"[TextureHook] GL can't be NULL\", this.constructor.name);\n        }\n    }\n\n    public registerTexture(texture: any): void {\n        this.createdTextures.push(texture); // ++;\n        this.maxTexturesCount = Math.max(this.createdTextures.length, this.maxTexturesCount);\n    }\n    public reset(): void {\n        this.createdTextures = new Array<any>();\n        this.maxTexturesCount = 0;\n    }\n    public release(): void {\n        if (this.isInit) {\n            this.gl.__proto__.createTexture = this.realGLCreateTexture;\n            this.gl.__proto__.deleteTexture = this.realGLDeleteTexture;\n\n            Log.debug('[TextureHook] Hook was removed!', this.constructor.name);\n        }\n\n        this.isInit = false;\n    }\n\n    // biome-ignore lint/suspicious/noEmptyBlockStatements: <explanation>\n    private realGLCreateTexture = (): void => {};\n    // biome-ignore lint/suspicious/noEmptyBlockStatements: <explanation>\n    private realGLDeleteTexture = (): void => {};\n\n    private fakeGLCreateTexture(): any {\n        const texture = this.realGLCreateTexture.call(this.gl);\n        this.registerTexture(texture);\n        return texture;\n    }\n\n    private fakeGLDeleteTexture(texture: any): void {\n        const index: number = this.createdTextures.indexOf(texture);\n        if (index > -1) {\n            this.createdTextures.splice(index, 1);\n        }\n\n        this.realGLDeleteTexture.call(this.gl, texture);\n    }\n}\n","import { BaseTexture, Container, Renderer, RenderTexture, Texture } from 'pixi.js';\nimport { appTrace, firstAppFrame } from './stackUtil';\n\n/**\n * Captures *where* leaking objects come from, with no call-site changes.\n *\n * PIXI ships as ESM, so `new Sprite()` cannot be intercepted (the binding is\n * read-only). But two things CAN be patched reliably because they mutate a\n * property on a shared object rather than rebinding an import:\n *   - `Container.prototype.addChild` / `addChildAt` — every on-screen display\n *     object passes through here, so we stamp it with the app frame that put it\n *     in the scene. That line is exactly where its lifecycle is managed.\n *   - texture factories (`Texture.from`, `BaseTexture.from`, `generateTexture`,\n *     `RenderTexture.create`) — these catch generated/canvas textures (e.g. a\n *     PIXI.Text's internal `Texture.from(canvas)`), which have no file name.\n *\n * Each tracked object gets two hidden props: `__lrSite` (\"File.ts:line\") and\n * `__lrTrace` (a few app frames). Reading them costs nothing; the OrphanTracker\n * and the texture census surface them. Stamping only happens while capture is\n * on (panel open / recording) and only once per object.\n */\nexport default class CreationProbe {\n    private static _installed = false;\n    private _capture = false;\n\n    public setCapture(on: boolean): void {\n        this._capture = on;\n    }\n\n    public install(): void {\n        if (CreationProbe._installed) {\n            return;\n        }\n        CreationProbe._installed = true;\n\n        this._wrapAddChild(Container.prototype, 'addChild');\n        this._wrapAddChild(Container.prototype, 'addChildAt');\n\n        this._wrapFactory(Texture, 'from');\n        this._wrapFactory(Texture, 'fromURL');\n        this._wrapFactory(Texture, 'fromBuffer');\n        this._wrapFactory(BaseTexture, 'from');\n        this._wrapFactory(RenderTexture, 'create');\n        // generateTexture lives on AbstractRenderer.prototype but is reachable\n        // (inherited) from Renderer.prototype; shadowing it here is fine.\n        this._wrapFactory(Renderer.prototype, 'generateTexture');\n    }\n\n    /** addChild(...children) / addChildAt(child, index): stamp the child args. */\n    private _wrapAddChild(proto: any, method: string): void {\n        const original = proto[method];\n        if (typeof original !== 'function' || original.__lrWrapped) {\n            return;\n        }\n        const self = this;\n        // Named function expression: with external source maps the stack shows\n        // only \"bundle.js\" paths, so the frame must be recognisable by NAME\n        // (\"Container.__lrProbe [as addChild]\") for stackUtil to skip it.\n        const wrapped = function __lrProbe(this: any, ...args: any[]): any {\n            if (self._capture) {\n                const stack = new Error().stack;\n                for (let i = 0; i < args.length; i++) {\n                    self._stamp(args[i], stack);\n                }\n            }\n            return original.apply(this, args);\n        };\n        (wrapped as any).__lrWrapped = true;\n        proto[method] = wrapped;\n    }\n\n    /** Static/instance factory returning a Texture-like: stamp the result. */\n    private _wrapFactory(holder: any, method: string): void {\n        const original = holder?.[method];\n        if (typeof original !== 'function' || original.__lrWrapped) {\n            return;\n        }\n        const self = this;\n        // Named so stackUtil can skip this frame by name on bundle-only stacks.\n        const wrapped = function __lrProbe(this: any, ...args: any[]): any {\n            const result = original.apply(this, args);\n            if (self._capture && result) {\n                const stack = new Error().stack;\n                if (typeof result.then === 'function') {\n                    // async factory (Texture.fromURL) — stamp once it resolves\n                    (result as Promise<any>).then(\n                        (v) => self._stamp(v, stack),\n                        () => undefined,\n                    );\n                } else {\n                    self._stamp(result, stack);\n                }\n            }\n            return result;\n        };\n        (wrapped as any).__lrWrapped = true;\n        holder[method] = wrapped;\n    }\n\n    private _stamp(obj: any, stack?: string): void {\n        if (!obj || typeof obj !== 'object') {\n            return;\n        }\n        try {\n            if (!obj.__lrSite) {\n                obj.__lrSite = firstAppFrame(stack);\n                obj.__lrTrace = appTrace(stack, 4);\n            }\n            // Propagate to the BaseTexture: factories mostly return Texture\n            // wrappers, but the texture census enumerates BaseTextures — without\n            // this the site never reaches the cache and rows show bare pixiids.\n            const bt = obj.baseTexture;\n            if (bt && typeof bt === 'object' && !bt.__lrSite) {\n                bt.__lrSite = obj.__lrSite;\n                bt.__lrTrace = obj.__lrTrace;\n            }\n        } catch (_e) {\n            // never let instrumentation break rendering\n        }\n    }\n}\n","import gsap from 'gsap';\nimport { ISuspect } from './LeakRadarTypes';\nimport { firstAppFrame } from './stackUtil';\n\ninterface ISiteMeta {\n    site: string;\n    createdAt: number;\n}\n\n/**\n * Instruments the GSAP singleton ONCE so every tween/timeline created anywhere\n * in any package is stamped with the source location that created it. No call\n * site has to change - everyone imports the same `gsap` instance.\n *\n * Live animations are then read directly from `gsap.globalTimeline`, so there is\n * no register/unregister bookkeeping to keep in sync: when GSAP completes or\n * kills an animation it leaves the global timeline and disappears from our count\n * automatically. The classic leak (a tween/timeline tied to a destroyed view\n * that is never killed) shows up as a count that keeps climbing and never\n * returns to the baseline.\n */\nexport default class GsapProbe {\n    private static _installed = false;\n\n    /** Creation metadata, keyed weakly so it never keeps animations alive. */\n    private _meta: WeakMap<object, ISiteMeta> = new WeakMap();\n\n    /** Stack capture is only done while the panel is active (it is not free). */\n    private _capture = false;\n\n    public setCapture(on: boolean): void {\n        this._capture = on;\n    }\n\n    /** Patch the gsap factory methods (idempotent across the whole app). */\n    public install(): void {\n        if (GsapProbe._installed) {\n            return;\n        }\n        GsapProbe._installed = true;\n\n        const root: any = gsap as any;\n        const factory = ['to', 'from', 'fromTo', 'timeline', 'delayedCall'];\n        factory.forEach((m) => this._wrap(root, m));\n        // Note: tl.to()/tl.from() return the timeline (for chaining), not the\n        // child tween, so there is nothing useful to stamp on the Timeline\n        // prototype. Nested tweens are instead attributed to their parent\n        // timeline's creation site at sample() time (see below).\n    }\n\n    /**\n     * Read every live tween + timeline from the global timeline and group them\n     * by creation site.\n     */\n    public sample(): { tweens: number; timelines: number; suspects: ISuspect[] } {\n        const now = Date.now();\n        let tweens = 0;\n        let timelines = 0;\n        const groups = new Map<string, { count: number; oldest: number }>();\n\n        let children: any[] = [];\n        try {\n            // getChildren(nested, includeTweens, includeTimelines)\n            children = (gsap as any).globalTimeline.getChildren(true, true, true) || [];\n        } catch (_e) {\n            children = [];\n        }\n\n        for (let i = 0; i < children.length; i++) {\n            const child = children[i];\n            const isTimeline = typeof child.getChildren === 'function';\n            if (isTimeline) {\n                timelines++;\n            } else {\n                tweens++;\n            }\n\n            // Direct meta, else inherit the parent timeline's creation site so\n            // tweens added via tl.to(...) are attributed to where the timeline\n            // was built rather than dumped into an \"unknown\" bucket.\n            let meta = this._meta.get(child);\n            if (!meta && child.parent) {\n                meta = this._meta.get(child.parent);\n            }\n            const site = meta ? meta.site : '(unknown / pre-capture)';\n            const createdAt = meta ? meta.createdAt : now;\n\n            const g = groups.get(site) || { count: 0, oldest: now };\n            g.count++;\n            g.oldest = Math.min(g.oldest, createdAt);\n            groups.set(site, g);\n        }\n\n        const suspects: ISuspect[] = Array.from(groups.entries())\n            .map(([key, v]) => ({ key, label: key, count: v.count, oldestMs: now - v.oldest }))\n            .sort((a, b) => b.count - a.count);\n\n        return { tweens, timelines, suspects };\n    }\n\n    private _wrap(obj: any, method: string): void {\n        const original = obj[method];\n        if (typeof original !== 'function' || (original as any).__lrWrapped) {\n            return;\n        }\n        const self = this;\n        // Named so stackUtil can skip this frame by name on bundle-only stacks.\n        const wrapped = function __lrProbe(this: any, ...args: any[]): any {\n            const result = original.apply(this, args);\n            if (self._capture && result && typeof result === 'object') {\n                try {\n                    if (!self._meta.has(result)) {\n                        self._meta.set(result, { site: self._site(), createdAt: Date.now() });\n                    }\n                } catch (_e) {\n                    // never let instrumentation break an animation\n                }\n            }\n            return result;\n        };\n        (wrapped as any).__lrWrapped = true;\n        obj[method] = wrapped;\n    }\n\n    /** First app frame that created this animation. */\n    private _site(): string {\n        return firstAppFrame(new Error().stack);\n    }\n}\n","import Core, { Log } from '@egt/core';\nimport { Sprite } from 'pixi.js';\nimport CreationProbe from './CreationProbe';\nimport GsapProbe from './GsapProbe';\nimport LeakRadarPanel from './LeakRadarPanel';\nimport { ORPHAN_GRACE_MS } from './OrphanTracker';\nimport SceneCensus from './SceneCensus';\nimport { ILeakBaseline, ILeakSample, ISuspect, ISuspectSets } from './LeakRadarTypes';\n\nconst SAMPLE_MS = 400;\nconst HISTORY = 120;\n\n/**\n * Rough per-page memory budgets for the pressure gauge. iOS Safari reloads a\n * tab (\"a problem repeatedly occurred\") when its total footprint — GPU\n * textures being the usual driver for WebGL games — exceeds a device-dependent\n * jetsam limit; ~300 MB of VRAM is a conservative floor for older devices.\n * Desktop browsers tolerate far more, so the gauge is informational there.\n */\nconst IOS_VRAM_BUDGET_MB = 300;\nconst DESKTOP_VRAM_BUDGET_MB = 1000;\nconst HEAP_BUDGET_MB = 1600;\n\n/**\n * Orchestrates the runtime leak detector: installs the GSAP probe, samples the\n * scene + texture census + live GSAP animations on an interval, keeps a rolling\n * history for the sparklines, manages the baseline/diff workflow and drives the\n * visual panel. Exposed on `window.LeakRadar` for console use.\n */\nexport default class LeakRadar {\n    private static _instance: LeakRadar | null = null;\n\n    public static get instance(): LeakRadar {\n        if (!LeakRadar._instance) {\n            LeakRadar._instance = new LeakRadar();\n        }\n        return LeakRadar._instance;\n    }\n\n    private _probe = new GsapProbe();\n    private _creation = new CreationProbe();\n    private _census = new SceneCensus();\n    private _panel: LeakRadarPanel | null = null;\n    private _history: ILeakSample[] = [];\n    private _suspects: ISuspectSets = { component: [], gsap: [], texture: [], orphan: [] };\n    private _baseline: ILeakBaseline | null = null;\n    private _timer: number | null = null;\n    private _initialized = false;\n    /** Latest IPerfData from the engine stream (draw calls, GL texture counts). */\n    private _perf: any = null;\n\n    /** Install the GSAP probe and build the panel (safe to call repeatedly). */\n    public init(): void {\n        if (this._initialized) {\n            return;\n        }\n        this._initialized = true;\n        // Build the (hidden) panel only. The GSAP/PIXI probes are installed\n        // lazily in show()/setBaseline(), so a dev build that never opens the\n        // panel pays no addChild/gsap patching overhead at all.\n        this._panel = new LeakRadarPanel({\n            setBaseline: () => this.setBaseline(),\n            clearBaseline: () => this.clearBaseline(),\n            logReport: () => this.logReport(),\n            hide: () => this.hide(),\n        });\n        (window as any).LeakRadar = this;\n        (window as any).RuntimeStats = this;\n        // Reuse the engine's perf stream — the exact numbers the legacy fps\n        // meter showed (draw calls + GL texture counts come from the GL hook\n        // installed by Stage when devTools is on).\n        try {\n            (Core as any).PERFORMANCE_METRICS?.subscribe((data: any) => {\n                this._perf = data;\n            });\n        } catch (_e) {\n            // stream unavailable (e.g. multiplayer) — those cards just stay 0\n        }\n        Log.debug('[LeakRadar] ready — press \"L\" or call window.LeakRadar.show()', 'LeakRadar');\n    }\n\n    /** Patch GSAP + PIXI on first use (idempotent) — keeps overhead at zero until\n     *  the panel is actually opened. */\n    private _ensureInstalled(): void {\n        this._probe.install();\n        this._creation.install();\n    }\n\n    public toggle(): void {\n        this.init();\n        if (this._panel!.visible) {\n            this.hide();\n        } else {\n            this.show();\n        }\n    }\n\n    public show(): void {\n        this.init();\n        this._ensureInstalled();\n        this._panel!.show();\n        this._probe.setCapture(true);\n        this._creation.setCapture(true);\n        this._start();\n    }\n\n    public hide(): void {\n        this._panel?.hide();\n        // Keep sampling in the background only while a baseline diff is active.\n        if (!this._baseline) {\n            this._probe.setCapture(false);\n            this._creation.setCapture(false);\n            this._stop();\n        }\n    }\n\n    /** Freeze the current state; everything is then shown as a delta against it. */\n    public setBaseline(): void {\n        this.init();\n        this._ensureInstalled();\n        if (this._history.length === 0) {\n            this._sample();\n        }\n        const sample = this._history[this._history.length - 1];\n        this._baseline = {\n            at: Date.now(),\n            sample: { ...sample },\n            component: toMap(this._suspects.component, (s) => s.count),\n            gsap: toMap(this._suspects.gsap, (s) => s.count),\n            texture: toMap(this._suspects.texture, (s) => Math.round((s.bytes || 0) / 1024)),\n            orphan: toMap(this._suspects.orphan, (s) => s.count),\n        };\n        this._probe.setCapture(true);\n        this._creation.setCapture(true);\n        this._start();\n        Log.debug('[LeakRadar] baseline set', 'LeakRadar');\n    }\n\n    public clearBaseline(): void {\n        this._baseline = null;\n        if (this._panel && !this._panel.visible) {\n            this._probe.setCapture(false);\n            this._creation.setCapture(false);\n            this._stop();\n        }\n    }\n\n    /** Print an AI-pasteable JSON report of the current leaks to the console. */\n    public logReport(): void {\n        const latest = this._history[this._history.length - 1];\n        if (!latest) {\n            return;\n        }\n        const report = {\n            note: 'Leak Radar report. \"leftover\" = detached display objects (removed from the stage, never destroyed, still referenced); positive \"delta\" = accumulated since the baseline. In each \"path\" the first function created/added the object (inner ← outer); rely on function names, line numbers are bundle-relative. \"vramMB\" = estimated GPU memory (uploaded textures + framebuffers + canvas); \"pressure\" = % of a device memory budget — sustained >80% on iOS risks Safari reloading the page.',\n            game: (Core as any).configuration?.gameKey,\n            live: latest,\n            deltaSinceBaseline: this._baseline ? diffSample(latest, this._baseline.sample) : null,\n            leftover: this._suspects.orphan.slice(0, 25).map((s) => suspectEntry(s, this._baseline?.orphan)),\n            gsap: this._suspects.gsap.slice(0, 25).map((s) => suspectEntry(s, this._baseline?.gsap)),\n            textures: this._suspects.texture.slice(0, 25).map((s) => ({\n                source: s.label,\n                count: s.count,\n                MB: Math.round(((s.bytes || 0) / (1024 * 1024)) * 100) / 100,\n                createdIn: s.site,\n                path: s.trace,\n            })),\n            components: this._suspects.component\n                .slice(0, 25)\n                .map((s) => ({ component: s.label, instances: s.count, visuals: s.detail || 0 })),\n        };\n        // biome-ignore lint/suspicious/noConsole: dev-only leak report, devTools mode\n        console.log('📊 Runtime Stats report — copy the JSON below and paste it to your AI assistant:');\n        // biome-ignore lint/suspicious/noConsole: dev-only leak report, devTools mode\n        console.log(JSON.stringify(report, null, 2));\n    }\n\n    /** Full machine-readable snapshot (history + suspects + baseline). */\n    public exportJSON(): string {\n        return JSON.stringify({ history: this._history, suspects: this._suspects, baseline: this._baseline }, null, 2);\n    }\n\n    // ----------------------------------------------------------- internals\n\n    private _start(): void {\n        if (this._timer !== null) {\n            return;\n        }\n        this._sample();\n        this._timer = window.setInterval(() => this._sample(), SAMPLE_MS);\n    }\n\n    private _stop(): void {\n        if (this._timer !== null) {\n            window.clearInterval(this._timer);\n            this._timer = null;\n        }\n    }\n\n    private _sample(): void {\n        const scene = this._census.walk();\n        const tex = this._census.textures();\n        const orphans = this._census.orphans();\n        const gpu = this._census.gpu();\n        const g = this._probe.sample();\n        const heapMB = this._heapMB();\n        const perf: any = this._perf || {};\n\n        const sample: ILeakSample = {\n            t: Date.now(),\n            fps: this._fps(),\n            heapMB,\n            nodes: scene.nodes,\n            orphans: orphans.count,\n            sprites: scene.sprites,\n            texts: scene.texts,\n            graphics: scene.graphics,\n            spine: scene.spine,\n            containers: scene.containers,\n            textures: tex.count,\n            textureMB: tex.mb,\n            vramMB: gpu.vramMB,\n            pressure: this._pressure(gpu.vramMB, heapMB),\n            drawCalls: perf.drawCalls || 0,\n            peakDrawCalls: perf.peakDrawCalls || 0,\n            glTextures: perf.texturesCount || 0,\n            peakGlTextures: perf.peakTexturesCount || 0,\n            noSleep: (Core as any).noSleep?.isEnabled ? 1 : 0,\n            tweens: g.tweens,\n            timelines: g.timelines,\n        };\n\n        this._history.push(sample);\n        if (this._history.length > HISTORY) {\n            this._history.shift();\n        }\n\n        this._suspects = {\n            component: this._census.componentSuspects(scene),\n            gsap: g.suspects,\n            texture: tex.suspects,\n            orphan: orphans.suspects,\n        };\n\n        this._panel?.render(this._history, this._suspects, this._baseline);\n    }\n\n    private _fps(): number {\n        const ticker: any = (Core as any).stage?.app?.ticker;\n        return ticker && typeof ticker.FPS === 'number' ? Math.round(ticker.FPS) : 0;\n    }\n\n    private _heapMB(): number {\n        const mem: any = (performance as any).memory;\n        return mem && mem.usedJSHeapSize ? Math.round((mem.usedJSHeapSize / (1024 * 1024)) * 10) / 10 : 0;\n    }\n\n    /**\n     * % of the device memory budget in use — the \"how close to an iOS reload\n     * am I\" gauge. Driven by the VRAM estimate (works everywhere, and GPU\n     * memory is what kills WebGL tabs on iOS) and by the JS heap where the\n     * browser exposes it (Chrome only; iOS Safari hides it, so there VRAM is\n     * the signal). >100 means over the budget.\n     */\n    private _pressure(vramMB: number, heapMB: number): number {\n        let ios = false;\n        try {\n            ios = !!(Core as any).environment?.isMobileIos?.();\n        } catch (_e) {\n            ios = false;\n        }\n        const vramBudget = ios ? IOS_VRAM_BUDGET_MB : DESKTOP_VRAM_BUDGET_MB;\n        const ratio = Math.max(vramMB / vramBudget, heapMB > 0 ? heapMB / HEAP_BUDGET_MB : 0);\n        return Math.round(ratio * 100);\n    }\n\n    /**\n     * Programmatic sanity check that the radar matches reality (takes ~4s):\n     *  1) a removed AND destroyed sprite must NOT be reported as leftover;\n     *  2) a removed-but-still-referenced sprite MUST appear once past the\n     *     grace period;\n     *  3) destroying it must clear it from the report immediately.\n     * Run from the console: `await LeakRadar.selfTest()`.\n     */\n    public async selfTest(): Promise<boolean> {\n        this.init();\n        this._ensureInstalled();\n        this._probe.setCapture(true);\n        this._creation.setCapture(true);\n        const root: any = (Core as any).stage?.app?.stage;\n        if (!root) {\n            // biome-ignore lint/suspicious/noConsole: dev-only self-test\n            console.warn('🛰 [LeakRadar] self-test aborted — stage not ready yet');\n            return false;\n        }\n        const countMine = (): number =>\n            this._census\n                .orphans()\n                .suspects.reduce((n, s) => (s.label.indexOf('LRSelfTestSprite') === 0 ? n + s.count : n), 0);\n\n        // 1. destroyed objects must vanish immediately\n        const destroyed = new LRSelfTestSprite();\n        root.addChild(destroyed);\n        this._census.walk();\n        root.removeChild(destroyed);\n        destroyed.destroy();\n        this._census.walk();\n        const destroyedHidden = countMine() === 0;\n\n        // 2. detached-but-referenced objects must appear once past the grace period\n        const leaked = new LRSelfTestSprite();\n        root.addChild(leaked);\n        this._census.walk();\n        root.removeChild(leaked); // kept alive by this closure — a real leak\n        await new Promise((resolve) => window.setTimeout(resolve, ORPHAN_GRACE_MS + 700));\n        this._census.walk();\n        const leakDetected = countMine() > 0;\n\n        // 3. ...and disappear the moment they are destroyed\n        leaked.destroy();\n        const clearedOnDestroy = countMine() === 0;\n\n        const pass = destroyedHidden && leakDetected && clearedOnDestroy;\n        // biome-ignore lint/suspicious/noConsole: dev-only self-test\n        console.log(\n            `🛰 Leak Radar self-test ${pass ? '✅ PASSED' : '❌ FAILED'}\\n` +\n                `   destroyed sprite is not reported: ${destroyedHidden ? '✅' : '❌'}\\n` +\n                `   leaked sprite detected after ${ORPHAN_GRACE_MS / 1000}s grace: ${leakDetected ? '✅' : '❌'}\\n` +\n                `   destroy clears it immediately: ${clearedOnDestroy ? '✅' : '❌'}`,\n        );\n        return pass;\n    }\n}\n\n/** Marker class so the self-test can find its own sprites in the report. */\nclass LRSelfTestSprite extends Sprite {}\n\nfunction toMap(rows: ISuspect[], pickValue: (s: ISuspect) => number): Record<string, number> {\n    const m: Record<string, number> = {};\n    for (const r of rows) {\n        m[r.key] = pickValue(r);\n    }\n    return m;\n}\n\nfunction diffSample(latest: ILeakSample, base: ILeakSample): Record<string, number> {\n    return {\n        heapMB: Math.round((latest.heapMB - base.heapMB) * 10) / 10,\n        nodes: latest.nodes - base.nodes,\n        orphans: latest.orphans - base.orphans,\n        sprites: latest.sprites - base.sprites,\n        texts: latest.texts - base.texts,\n        graphics: latest.graphics - base.graphics,\n        spine: latest.spine - base.spine,\n        containers: latest.containers - base.containers,\n        textures: latest.textures - base.textures,\n        textureMB: Math.round((latest.textureMB - base.textureMB) * 10) / 10,\n        vramMB: Math.round((latest.vramMB - base.vramMB) * 10) / 10,\n        pressure: latest.pressure - base.pressure,\n        drawCalls: latest.drawCalls - base.drawCalls,\n        glTextures: latest.glTextures - base.glTextures,\n        tweens: latest.tweens - base.tweens,\n        timelines: latest.timelines - base.timelines,\n    };\n}\n\nfunction suspectEntry(s: ISuspect, baseMap?: Record<string, number>): Record<string, string | number> {\n    const base = baseMap ? baseMap[s.key] || 0 : null;\n    const out: Record<string, string | number> = { object: s.label, count: s.count };\n    if (base !== null) {\n        out.delta = s.count - base;\n    }\n    if (s.site) {\n        out.createdIn = s.site;\n    }\n    if (s.trace) {\n        out.path = s.trace;\n    }\n    return out;\n}\n","import { ILeakBaseline, ILeakSample, ISuspect, ISuspectSets, MetricKey, SuspectKind } from './LeakRadarTypes';\n\n/** Callbacks the panel needs from the orchestrator. */\nexport interface ILeakRadarController {\n    setBaseline(): void;\n    clearBaseline(): void;\n    logReport(): void;\n    hide(): void;\n}\n\ninterface ICardRefs {\n    value: HTMLSpanElement;\n    delta: HTMLSpanElement;\n    poly: SVGPolylineElement;\n}\n\ninterface ICardDef {\n    key: MetricKey;\n    label: string;\n    /** Higher is better (do not flag growth as a leak), e.g. FPS. */\n    good?: boolean;\n    fmt?: (n: number) => string;\n    /** Full-sample value renderer (e.g. \"current / peak\" pairs). */\n    text?: (latest: ILeakSample) => string;\n    /** Suppress the Δ-vs-baseline badge (booleans, flags). */\n    noDelta?: boolean;\n    /** Hover tooltip explaining what the metric means. */\n    help?: string;\n}\n\nconst SVG_NS = 'http://www.w3.org/2000/svg';\nconst SPARK_W = 74;\nconst SPARK_H = 20;\nconst WINDOW = 120;\n\nconst CARDS: ICardDef[] = [\n    { key: 'fps', label: 'FPS', good: true, help: 'Frames per second (renderer ticker).' },\n    {\n        key: 'heapMB',\n        label: 'Heap MB',\n        fmt: (n) => (n > 0 ? String(Math.round(n)) : '—'),\n        help: 'JS heap in use. Chrome only — iOS Safari hides it (shows \"—\"), use VRAM/iOS press there.',\n    },\n    { key: 'nodes', label: 'Nodes', help: 'Display objects currently attached to the scene graph.' },\n    {\n        key: 'orphans',\n        label: 'Detached',\n        help: 'Removed from the stage but never destroyed and still referenced somewhere (a tween, array, closure). Listed per creation site in the Leftover tab. The longer one stays here, the more certain it is a leak — freshly removed objects get a short grace period and GC-collected ones drop out on their own.',\n    },\n    { key: 'sprites', label: 'Sprites', help: 'Sprites attached to the scene.' },\n    { key: 'texts', label: 'Texts', help: 'Text / BitmapText objects attached to the scene.' },\n    { key: 'graphics', label: 'Graphics', help: 'Graphics (shapes) attached to the scene.' },\n    { key: 'spine', label: 'Spine', help: 'Spine animations attached to the scene.' },\n    { key: 'containers', label: 'Containers', help: 'Structural containers (incl. custom views).' },\n    { key: 'textures', label: 'Textures', help: 'Live BaseTextures in the PIXI cache.' },\n    { key: 'textureMB', label: 'Tex MB', fmt: (n) => n.toFixed(1), help: 'Memory of the cached textures.' },\n    {\n        key: 'vramMB',\n        label: 'VRAM MB',\n        fmt: (n) => String(Math.round(n)),\n        help: 'Estimated GPU memory: uploaded textures + framebuffers + canvas. The usual driver of iOS Safari page reloads — watch this while loading and during features.',\n    },\n    {\n        key: 'pressure',\n        label: 'iOS press',\n        fmt: (n) => `${Math.round(n)}%`,\n        help: 'How close the page is to the device memory budget (VRAM vs ~300MB on iOS, plus JS heap where visible). Sustained >80% risks Safari killing/reloading the tab — reduce texture sizes or destroy features earlier.',\n    },\n    {\n        key: 'drawCalls',\n        label: 'Draw calls',\n        text: (s) => `${Math.round(s.drawCalls)}/${Math.round(s.peakDrawCalls)}`,\n        help: 'Draw calls per frame — current / peak (GL hook, the same numbers as the legacy fps meter).',\n    },\n    {\n        key: 'glTextures',\n        label: 'GL tex',\n        text: (s) => `${Math.round(s.glTextures)}/${Math.round(s.peakGlTextures)}`,\n        help: 'Textures alive on the GPU — current / peak (GL hook counts, like the legacy fps meter).',\n    },\n    { key: 'tweens', label: 'GSAP Tw', help: 'Live GSAP tweens on the global timeline.' },\n    { key: 'timelines', label: 'GSAP Tl', help: 'Live GSAP timelines on the global timeline.' },\n    {\n        key: 'noSleep',\n        label: 'No-sleep',\n        fmt: (n) => (n ? 'on' : 'off'),\n        noDelta: true,\n        help: 'Whether NoSleep is keeping the screen awake.',\n    },\n];\n\nconst TABS: { kind: SuspectKind; label: string; help?: string }[] = [\n    { kind: 'component', label: 'Components', help: 'Live instances per custom view class.' },\n    { kind: 'gsap', label: 'GSAP', help: 'Live animations grouped by the function that created them.' },\n    {\n        kind: 'texture',\n        label: 'Textures',\n        help: 'Live textures by source file, or by creator/user for generated ones.',\n    },\n    {\n        kind: 'orphan',\n        label: 'Leftover',\n        help: 'Detached-but-alive objects grouped by the function that created them — click a row to print the full path.',\n    },\n];\n\n/**\n * The visual overlay. Built once, then updated in place every sample so it is\n * cheap to keep open. Three things make a leak obvious at a glance:\n *  - sparklines: a line that climbs and never falls is accumulation;\n *  - Δ-since-baseline: mark a baseline at idle, act, return to idle - anything\n *    that did not return to 0 is the leak;\n *  - Top suspects: the component / gsap site / texture driving the growth.\n */\nexport default class LeakRadarPanel {\n    private _root!: HTMLDivElement;\n    private _summary!: HTMLDivElement;\n    private _rec!: HTMLSpanElement;\n    private _body!: HTMLDivElement;\n    private _tableBody!: HTMLDivElement;\n    private _help!: HTMLDivElement;\n    private _detail!: HTMLDivElement;\n    private _mini!: HTMLDivElement;\n    private _mFps!: HTMLSpanElement;\n    private _mDc!: HTMLSpanElement;\n    private _mVram!: HTMLSpanElement;\n    private _mPress!: HTMLSpanElement;\n    private _mDet!: HTMLSpanElement;\n    private _cards: Map<MetricKey, ICardRefs> = new Map();\n    private _activeTab: SuspectKind = 'component';\n    private _collapsed = false;\n    private _maximized = false;\n    private _mode: 'full' | 'mini' = 'full';\n    private _everShown = false;\n\n    constructor(private _ctrl: ILeakRadarController) {\n        this._injectStyle();\n        this._build();\n    }\n\n    public get visible(): boolean {\n        return this._root.style.display !== 'none' || this._mini.style.display !== 'none';\n    }\n\n    public show(): void {\n        // On a touch device default to the ultra-compact strip so the panel\n        // does not cover the game; expand on demand by tapping it.\n        if (!this._everShown && window.matchMedia?.('(pointer: coarse)').matches) {\n            this._mode = 'mini';\n        }\n        this._everShown = true;\n        this._setMini(this._mode === 'mini');\n    }\n\n    public hide(): void {\n        this._root.style.display = 'none';\n        this._mini.style.display = 'none';\n    }\n\n    public toggle(): void {\n        if (this.visible) {\n            this.hide();\n        } else {\n            this.show();\n        }\n    }\n\n    /** Update every widget from the latest history + suspects + baseline. */\n    public render(history: ILeakSample[], suspects: ISuspectSets, baseline: ILeakBaseline | null): void {\n        if (history.length === 0) {\n            this._renderRec(baseline);\n            return;\n        }\n        const latest = history[history.length - 1];\n        if (this._mini.style.display !== 'none') {\n            this._renderMini(latest, baseline);\n            return;\n        }\n        if (!this.visible || this._collapsed) {\n            this._renderRec(baseline);\n            return;\n        }\n\n        for (const def of CARDS) {\n            const refs = this._cards.get(def.key);\n            if (!refs) {\n                continue;\n            }\n            const value = latest[def.key];\n            refs.value.textContent = def.text ? def.text(latest) : def.fmt ? def.fmt(value) : String(Math.round(value));\n            if (def.key === 'pressure') {\n                refs.value.style.color = value >= 90 ? '#ff5b5b' : value >= 70 ? '#ffb04d' : '';\n            }\n\n            // Delta vs baseline.\n            if (baseline && !def.noDelta) {\n                const base = baseline.sample[def.key];\n                const d = value - base;\n                refs.delta.textContent = formatDelta(d, def.fmt);\n                refs.delta.className = 'lr-delta ' + deltaClass(d, def.good);\n            } else {\n                refs.delta.textContent = '';\n                refs.delta.className = 'lr-delta';\n            }\n\n            this._renderSparkline(refs.poly, history, def);\n        }\n\n        this._renderSummary(latest, baseline);\n        this._renderRec(baseline);\n        this._renderTable(suspects, baseline);\n    }\n\n    // ---------------------------------------------------------------- build\n\n    private _build(): void {\n        this._root = document.createElement('div');\n        this._root.id = 'leak-radar';\n        this._root.style.display = 'none';\n\n        // Header --------------------------------------------------------\n        const header = el('div', 'lr-header');\n        const title = el('span', 'lr-title');\n        title.textContent = '📊 Runtime Stats';\n        this._rec = el('span', 'lr-rec') as HTMLSpanElement;\n        header.appendChild(title);\n        header.appendChild(this._rec);\n\n        const actions = el('span', 'lr-actions');\n        actions.appendChild(this._btn('?', 'What do these numbers mean', () => this._toggleHelp()));\n        actions.appendChild(this._btn('Base', 'Mark current state as baseline', () => this._ctrl.setBaseline()));\n        actions.appendChild(this._btn('Clr', 'Clear baseline', () => this._ctrl.clearBaseline()));\n        actions.appendChild(this._btn('Log', 'Dump full report to console', () => this._ctrl.logReport()));\n        actions.appendChild(this._btn('▂', 'Ultra-compact strip (tap it to expand back)', () => this._setMini(true)));\n        actions.appendChild(this._btn('⤢', 'Enlarge / restore', () => this._toggleMaximize()));\n        actions.appendChild(this._btn('–', 'Collapse', () => this._toggleCollapse()));\n        actions.appendChild(this._btn('✕', 'Close (press L to reopen)', () => this._ctrl.hide()));\n        header.appendChild(actions);\n        this._root.appendChild(header);\n        this._enableDrag(header);\n\n        // Body ----------------------------------------------------------\n        this._body = el('div', 'lr-body') as HTMLDivElement;\n\n        this._summary = el('div', 'lr-summary') as HTMLDivElement;\n        this._body.appendChild(this._summary);\n\n        // Inline legend — title tooltips do not exist on touch screens, so the\n        // \"?\" button shows the same explanations in a tap-friendly block.\n        this._help = el('div', 'lr-help') as HTMLDivElement;\n        this._help.style.display = 'none';\n        this._help.innerHTML = HELP_HTML;\n        this._body.appendChild(this._help);\n\n        const grid = el('div', 'lr-grid');\n        for (const def of CARDS) {\n            grid.appendChild(this._buildCard(def));\n        }\n        this._body.appendChild(grid);\n\n        // Suspects ------------------------------------------------------\n        const tabs = el('div', 'lr-tabs');\n        for (const tab of TABS) {\n            const b = el('button', 'lr-tab') as HTMLButtonElement;\n            b.textContent = tab.label;\n            if (tab.help) {\n                b.title = tab.help;\n            }\n            b.dataset.kind = tab.kind;\n            if (tab.kind === this._activeTab) {\n                b.classList.add('active');\n            }\n            b.onclick = () => this._selectTab(tab.kind);\n            tabs.appendChild(b);\n        }\n        this._body.appendChild(tabs);\n\n        // Detail box for tapped rows — on a phone there is no console to read,\n        // so the creation path renders right here (selectable for copying).\n        this._detail = el('div', 'lr-detail') as HTMLDivElement;\n        this._detail.style.display = 'none';\n        this._body.appendChild(this._detail);\n\n        this._tableBody = el('div', 'lr-table') as HTMLDivElement;\n        this._tableBody.addEventListener('click', (e) => this._onRowClick(e));\n        this._body.appendChild(this._tableBody);\n\n        this._root.appendChild(this._body);\n        document.body.appendChild(this._root);\n\n        // Ultra-compact strip — the phone-friendly \"fps meter\": one unobtrusive\n        // line with the vitals; tap it to expand to the full panel.\n        this._mini = el('div') as HTMLDivElement;\n        this._mini.id = 'leak-radar-mini';\n        this._mini.style.display = 'none';\n        this._mini.title = 'Runtime Stats — tap to expand';\n        const mk = (): HTMLSpanElement => {\n            const s = document.createElement('span');\n            s.className = 'lrm-v';\n            this._mini.appendChild(s);\n            return s;\n        };\n        this._mFps = mk();\n        this._mDc = mk();\n        this._mVram = mk();\n        this._mPress = mk();\n        this._mDet = mk();\n        const miniClose = document.createElement('span');\n        miniClose.className = 'lrm-x';\n        miniClose.textContent = '✕';\n        miniClose.onclick = (e) => {\n            e.stopPropagation();\n            this._ctrl.hide();\n        };\n        this._mini.appendChild(miniClose);\n        this._mini.onclick = () => this._setMini(false);\n        document.body.appendChild(this._mini);\n    }\n\n    private _buildCard(def: ICardDef): HTMLDivElement {\n        const card = el('div', 'lr-card') as HTMLDivElement;\n        if (def.help) {\n            card.title = def.help;\n        }\n\n        const top = el('div', 'lr-card-top');\n        const label = el('span', 'lr-card-label');\n        label.textContent = def.label;\n        const delta = el('span', 'lr-delta') as HTMLSpanElement;\n        top.appendChild(label);\n        top.appendChild(delta);\n\n        const value = el('span', 'lr-card-value') as HTMLSpanElement;\n        value.textContent = '0';\n\n        const svg = document.createElementNS(SVG_NS, 'svg');\n        svg.setAttribute('class', 'lr-spark');\n        svg.setAttribute('viewBox', `0 0 ${SPARK_W} ${SPARK_H}`);\n        svg.setAttribute('preserveAspectRatio', 'none');\n        const poly = document.createElementNS(SVG_NS, 'polyline') as SVGPolylineElement;\n        poly.setAttribute('fill', 'none');\n        poly.setAttribute('stroke-width', '1.5');\n        svg.appendChild(poly);\n\n        card.appendChild(top);\n        card.appendChild(value);\n        card.appendChild(svg);\n\n        this._cards.set(def.key, { value, delta, poly });\n        return card;\n    }\n\n    // --------------------------------------------------------------- render\n\n    private _renderSparkline(poly: SVGPolylineElement, history: ILeakSample[], def: ICardDef): void {\n        const n = Math.min(history.length, WINDOW);\n        const start = history.length - n;\n        let min = Number.POSITIVE_INFINITY;\n        let max = Number.NEGATIVE_INFINITY;\n        for (let i = start; i < history.length; i++) {\n            const v = history[i][def.key];\n            if (v < min) min = v;\n            if (v > max) max = v;\n        }\n        const range = max - min || 1;\n        const pts: string[] = [];\n        for (let i = 0; i < n; i++) {\n            const v = history[start + i][def.key];\n            const x = n === 1 ? 0 : (i / (n - 1)) * SPARK_W;\n            const y = SPARK_H - ((v - min) / range) * (SPARK_H - 2) - 1;\n            pts.push(`${x.toFixed(1)},${y.toFixed(1)}`);\n        }\n        poly.setAttribute('points', pts.join(' '));\n\n        // Trend colour: rising over the window is suspicious (unless good=FPS).\n        const first = history[start][def.key];\n        const last = history[history.length - 1][def.key];\n        const rising = last > first + range * 0.15;\n        const color = def.good ? '#7CFC9A' : rising ? '#FF8A5B' : '#7CFC9A';\n        poly.setAttribute('stroke', color);\n    }\n\n    private _renderSummary(latest: ILeakSample, baseline: ILeakBaseline | null): void {\n        const pressureNote = latest.pressure >= 80 ? `   ⚠ iOS pressure ${Math.round(latest.pressure)}%` : '';\n        if (!baseline) {\n            this._summary.textContent =\n                'No baseline. Press “Base” at an idle state, run a round, return to idle — anything that did not return to 0 is leaking.' +\n                pressureNote;\n            this._summary.className = 'lr-summary' + (pressureNote ? ' leak' : '');\n            return;\n        }\n        const b = baseline.sample;\n        const dHeap = Math.round((latest.heapMB - b.heapMB) * 10) / 10;\n        const dVram = Math.round((latest.vramMB - b.vramMB) * 10) / 10;\n        const dNodes = latest.nodes - b.nodes;\n        const dOrph = latest.orphans - b.orphans;\n        const dTex = latest.textures - b.textures;\n        const dGsap = latest.tweens + latest.timelines - b.tweens - b.timelines;\n        const leaking = dNodes > 0 || dOrph > 0 || dTex > 0 || dGsap > 0 || dHeap > 0.5 || !!pressureNote;\n        this._summary.className = 'lr-summary ' + (leaking ? 'leak' : 'ok');\n        this._summary.textContent =\n            `Δ baseline:  heap ${signed(dHeap, 1)}MB   vram ${signed(dVram, 1)}MB   nodes ${signed(dNodes)}` +\n            `   detached ${signed(dOrph)}   tex ${signed(dTex)}   gsap ${signed(dGsap)}${pressureNote}`;\n    }\n\n    private _renderRec(baseline: ILeakBaseline | null): void {\n        if (baseline) {\n            const secs = Math.floor((Date.now() - baseline.at) / 1000);\n            this._rec.textContent = `● baseline ${formatClock(secs)}`;\n            this._rec.style.display = 'inline';\n        } else {\n            this._rec.style.display = 'none';\n        }\n    }\n\n    private _renderTable(suspects: ISuspectSets, baseline: ILeakBaseline | null): void {\n        const kind = this._activeTab;\n        const rows = suspects[kind] || [];\n        const baseMap = baseline ? baseline[kind] : null;\n\n        const header = headerFor(kind);\n        const frag = document.createDocumentFragment();\n        frag.appendChild(rowEl(header, 'lr-row lr-row-head'));\n\n        // When a baseline exists, sort by growth (Δ) so the leak floats to top.\n        const sorted = rows.slice();\n        if (baseMap) {\n            sorted.sort((a, b) => deltaOf(b, baseMap) - deltaOf(a, baseMap) || b.count - a.count);\n        }\n\n        const top = sorted.slice(0, 18);\n        for (const s of top) {\n            const base = baseMap ? baseMap[s.key] || 0 : null;\n            const cur = kind === 'texture' ? Math.round((s.bytes || 0) / 1024) : s.count;\n            const d = base === null ? null : cur - base;\n            const cls = 'lr-row' + (d !== null && d > 0 ? ' lr-row-leak' : '');\n            const row = rowEl(cellsFor(kind, s, d), cls);\n            row.style.cursor = 'pointer';\n            row.dataset.label = s.label;\n            row.dataset.count = String(s.count);\n            row.dataset.trace = s.trace || s.site || '';\n            if (s.trace || s.site) {\n                row.title = `${s.label} — click to print the creation path\\n${s.trace || s.site}`;\n            }\n            frag.appendChild(row);\n        }\n        if (top.length === 0) {\n            frag.appendChild(rowEl(['(nothing tracked yet)', '', '', ''], 'lr-row'));\n        }\n\n        this._tableBody.innerHTML = '';\n        this._tableBody.appendChild(frag);\n    }\n\n    /** Tapping a suspect row shows its creation path inline (and logs it too). */\n    private _onRowClick(e: MouseEvent): void {\n        const row = (e.target as HTMLElement)?.closest('.lr-row') as HTMLElement | null;\n        if (!row || !row.dataset.label) {\n            return;\n        }\n        const trace = row.dataset.trace || '(no creation trace — open Leak Radar before the action that creates it)';\n        // biome-ignore lint/suspicious/noConsole: dev-only leak inspector\n        console.log(`🛰 Leak Radar — ${row.dataset.label}  ×${row.dataset.count || '?'}\\n   created via:  ${trace}`);\n\n        this._detail.innerHTML = '';\n        const head = el('div', 'lr-detail-head');\n        const caption = document.createElement('span');\n        caption.textContent = `${row.dataset.label} ×${row.dataset.count || '?'}`;\n        head.appendChild(caption);\n        head.appendChild(\n            this._btn('✕', 'Close', () => {\n                this._detail.style.display = 'none';\n            }),\n        );\n        const body = el('div', 'lr-detail-trace');\n        body.textContent = trace.replace(/\\s+←\\s+/g, '\\n← ');\n        this._detail.appendChild(head);\n        this._detail.appendChild(body);\n        this._detail.style.display = '';\n    }\n\n    // ----------------------------------------------------------- behaviour\n\n    private _selectTab(kind: SuspectKind): void {\n        this._activeTab = kind;\n        const buttons = this._root.querySelectorAll('.lr-tab');\n        buttons.forEach((b) => {\n            const btn = b as HTMLButtonElement;\n            btn.classList.toggle('active', btn.dataset.kind === kind);\n        });\n    }\n\n    private _toggleCollapse(): void {\n        this._collapsed = !this._collapsed;\n        this._body.style.display = this._collapsed ? 'none' : '';\n    }\n\n    private _toggleMaximize(): void {\n        this._maximized = !this._maximized;\n        // Clamp to the viewport so \"enlarge\" works on phones too (also the only\n        // way to grow the panel there — CSS resize has no handle on touch).\n        this._root.style.width = this._maximized ? 'min(720px, 96vw)' : '';\n        this._root.style.height = this._maximized ? '82vh' : '';\n    }\n\n    private _toggleHelp(): void {\n        this._help.style.display = this._help.style.display === 'none' ? '' : 'none';\n    }\n\n    /** Switch between the full panel and the ultra-compact strip. */\n    private _setMini(on: boolean): void {\n        this._mode = on ? 'mini' : 'full';\n        this._root.style.display = on ? 'none' : 'flex';\n        this._mini.style.display = on ? 'flex' : 'none';\n    }\n\n    private _renderMini(latest: ILeakSample, baseline: ILeakBaseline | null): void {\n        this._mFps.textContent = `${Math.round(latest.fps)}fps`;\n        this._mDc.textContent = `${Math.round(latest.drawCalls)}dc`;\n        this._mVram.textContent = `${Math.round(latest.vramMB)}MB`;\n        this._mPress.textContent = `${Math.round(latest.pressure)}%`;\n        this._mPress.style.color = latest.pressure >= 90 ? '#ff5b5b' : latest.pressure >= 70 ? '#ffb04d' : '#7CFC9A';\n        // Detached: show the growth since baseline when one is set — that is the\n        // leak signal; otherwise the absolute count.\n        const dDet = baseline ? latest.orphans - baseline.sample.orphans : null;\n        this._mDet.textContent = dDet !== null ? `d${dDet > 0 ? '+' : ''}${dDet}` : `d${latest.orphans}`;\n        this._mDet.style.color = dDet !== null && dDet > 0 ? '#ff7a59' : '#8ea3ba';\n    }\n\n    private _btn(text: string, title: string, onClick: () => void): HTMLButtonElement {\n        const b = el('button', 'lr-btn') as HTMLButtonElement;\n        b.textContent = text;\n        b.title = title;\n        b.onclick = onClick;\n        return b;\n    }\n\n    private _enableDrag(handle: HTMLElement): void {\n        let dragging = false;\n        let ox = 0;\n        let oy = 0;\n        handle.addEventListener('mousedown', (e) => {\n            if ((e.target as HTMLElement).tagName === 'BUTTON') {\n                return;\n            }\n            dragging = true;\n            ox = e.clientX - this._root.offsetLeft;\n            oy = e.clientY - this._root.offsetTop;\n            document.body.style.userSelect = 'none';\n        });\n        document.addEventListener('mousemove', (e) => {\n            if (!dragging) {\n                return;\n            }\n            this._root.style.left = `${e.clientX - ox}px`;\n            this._root.style.top = `${e.clientY - oy}px`;\n            this._root.style.right = 'auto';\n        });\n        document.addEventListener('mouseup', () => {\n            dragging = false;\n            document.body.style.userSelect = '';\n        });\n\n        // Touch drag — a phone has no mouse, and the game canvas below must not\n        // receive the move (preventDefault on the non-passive touchmove).\n        handle.addEventListener(\n            'touchstart',\n            (e) => {\n                if ((e.target as HTMLElement).tagName === 'BUTTON') {\n                    return;\n                }\n                const touch = e.touches[0];\n                dragging = true;\n                ox = touch.clientX - this._root.offsetLeft;\n                oy = touch.clientY - this._root.offsetTop;\n            },\n            { passive: true },\n        );\n        document.addEventListener(\n            'touchmove',\n            (e) => {\n                if (!dragging) {\n                    return;\n                }\n                const touch = e.touches[0];\n                this._root.style.left = `${touch.clientX - ox}px`;\n                this._root.style.top = `${touch.clientY - oy}px`;\n                this._root.style.right = 'auto';\n                e.preventDefault();\n            },\n            { passive: false },\n        );\n        document.addEventListener('touchend', () => {\n            dragging = false;\n        });\n    }\n\n    private _injectStyle(): void {\n        if (document.getElementById('leak-radar-style')) {\n            return;\n        }\n        const style = document.createElement('style');\n        style.id = 'leak-radar-style';\n        style.textContent = CSS;\n        document.head.appendChild(style);\n    }\n}\n\n// -------------------------------------------------------------- DOM helpers\n\nfunction el(tag: string, className?: string): HTMLElement {\n    const e = document.createElement(tag);\n    if (className) {\n        e.className = className;\n    }\n    return e;\n}\n\nfunction rowEl(cells: string[], className: string): HTMLDivElement {\n    const row = el('div', className) as HTMLDivElement;\n    for (const c of cells) {\n        const span = document.createElement('span');\n        span.textContent = c;\n        row.appendChild(span);\n    }\n    return row;\n}\n\nfunction headerFor(kind: SuspectKind): string[] {\n    if (kind === 'gsap') {\n        return ['Creation site', 'live', 'Δ', 'oldest'];\n    }\n    if (kind === 'texture') {\n        return ['Source', 'count', 'ΔkB', 'MB'];\n    }\n    if (kind === 'orphan') {\n        return ['Leftover object', 'count', 'Δ', 'age'];\n    }\n    return ['Component', '×inst', 'Δ', 'visuals'];\n}\n\nfunction cellsFor(kind: SuspectKind, s: ISuspect, d: number | null): string[] {\n    const delta = d === null ? '' : signed(d);\n    if (kind === 'gsap') {\n        return [s.label, String(s.count), delta, s.oldestMs ? `${Math.round(s.oldestMs / 1000)}s` : ''];\n    }\n    if (kind === 'texture') {\n        return [s.label, String(s.count), delta, ((s.bytes || 0) / (1024 * 1024)).toFixed(1)];\n    }\n    if (kind === 'orphan') {\n        return [s.label, String(s.count), delta, s.oldestMs ? `${Math.round(s.oldestMs / 1000)}s` : ''];\n    }\n    return [s.label, String(s.count), delta, String(s.detail || 0)];\n}\n\nfunction deltaOf(s: { key: string; count: number; bytes?: number }, baseMap: Record<string, number>): number {\n    const cur = s.bytes !== undefined ? Math.round(s.bytes / 1024) : s.count;\n    return cur - (baseMap[s.key] || 0);\n}\n\nfunction formatDelta(d: number, fmt?: (n: number) => string): string {\n    if (d === 0) {\n        return '0';\n    }\n    const v = fmt ? fmt(Math.abs(d)) : String(Math.round(Math.abs(d)));\n    return (d > 0 ? '+' : '−') + v;\n}\n\nfunction deltaClass(d: number, good?: boolean): string {\n    if (d === 0) {\n        return '';\n    }\n    if (good) {\n        return d > 0 ? 'up-good' : 'down-bad';\n    }\n    return d > 0 ? 'up-bad' : 'down-good';\n}\n\nfunction signed(n: number, digits = 0): string {\n    const v = digits ? n.toFixed(digits) : String(Math.round(n));\n    return n > 0 ? `+${v}` : v;\n}\n\nfunction formatClock(totalSeconds: number): string {\n    const m = Math.floor(totalSeconds / 60);\n    const s = totalSeconds % 60;\n    return `${m}:${s.toString().padStart(2, '0')}`;\n}\n\nconst HELP_HTML = `\n<b>Workflow:</b> press <b>Base</b> while idle → play a round / rotate → return to idle. Any red +Δ did not clean up after itself.<br>\n<b>Detached</b> — removed from the stage but never destroyed (still held by a tween / array / closure). Real leaks keep aging in the <b>Leftover</b> tab; tap a row to see where it was created.<br>\n<b>VRAM MB</b> — estimated GPU memory (uploaded textures + framebuffers + canvas).<br>\n<b>iOS press</b> — % of the device memory budget. Sustained &gt;80% risks Safari reloading the page.<br>\n<b>Heap MB</b> — JS heap (Chrome only, “—” on iOS Safari).`;\n\nconst CSS = `\n#leak-radar {\n    position: fixed; top: calc(8px + env(safe-area-inset-top, 0px)); right: 8px; z-index: 2147483000;\n    width: 340px; min-width: 280px; max-width: 96vw; min-height: 220px; max-height: 94vh;\n    display: none; flex-direction: column; resize: both; overflow: hidden;\n    font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 11px;\n    color: #d7e0ea; background: rgba(16,19,26,0.94);\n    border: 1px solid #2b3340; border-radius: 6px;\n    box-shadow: 0 6px 24px rgba(0,0,0,0.5); user-select: none;\n}\n#leak-radar .lr-header {\n    display: flex; align-items: center; gap: 6px; cursor: move;\n    padding: 5px 6px; background: #1b2230; border-radius: 6px 6px 0 0;\n    border-bottom: 1px solid #2b3340;\n}\n#leak-radar .lr-title { font-weight: 600; color: #9fd0ff; }\n#leak-radar .lr-rec { color: #ff6b6b; font-size: 10px; }\n#leak-radar .lr-actions { margin-left: auto; display: flex; gap: 3px; }\n#leak-radar .lr-btn {\n    background: #2a3242; color: #cfe0f0; border: 1px solid #3a4456;\n    border-radius: 3px; font-size: 10px; padding: 1px 5px; cursor: pointer;\n    font-family: inherit;\n}\n#leak-radar .lr-btn:hover { background: #38465c; }\n#leak-radar .lr-body { padding: 6px; flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }\n#leak-radar .lr-summary {\n    font-size: 10px; line-height: 1.3; padding: 4px 5px; margin-bottom: 6px;\n    border-radius: 4px; background: #1a212d; color: #8ea3ba;\n}\n#leak-radar .lr-summary.leak { background: #2e1a1a; color: #ffb0a0; }\n#leak-radar .lr-summary.ok { background: #16271b; color: #9fe6b4; }\n#leak-radar .lr-grid {\n    display: grid; grid-template-columns: repeat(auto-fill, minmax(72px, 1fr)); gap: 4px; margin-bottom: 6px;\n}\n#leak-radar .lr-card {\n    background: #161c26; border: 1px solid #232c39; border-radius: 4px; padding: 3px 4px;\n}\n#leak-radar .lr-card-top { display: flex; justify-content: space-between; align-items: baseline; }\n#leak-radar .lr-card-label { color: #6f8298; font-size: 9px; text-transform: uppercase; letter-spacing: .3px; }\n#leak-radar .lr-card-value { display: block; font-size: 14px; font-weight: 600; color: #eef3f8; line-height: 1.1; }\n#leak-radar .lr-spark { width: 100%; height: 20px; display: block; }\n#leak-radar .lr-delta { font-size: 9px; }\n#leak-radar .lr-delta.up-bad { color: #ff7a59; }\n#leak-radar .lr-delta.down-good { color: #6fcf7f; }\n#leak-radar .lr-delta.up-good { color: #6fcf7f; }\n#leak-radar .lr-delta.down-bad { color: #ff7a59; }\n#leak-radar .lr-tabs { display: flex; gap: 3px; margin-bottom: 4px; }\n#leak-radar .lr-tab {\n    flex: 1; background: #1a212d; color: #8ea3ba; border: 1px solid #2b3340;\n    border-radius: 3px; padding: 3px; cursor: pointer; font-size: 10px; font-family: inherit;\n}\n#leak-radar .lr-tab.active { background: #2b3a52; color: #cfe6ff; border-color: #3d557a; }\n#leak-radar .lr-table { flex: 1 1 auto; min-height: 60px; overflow-y: auto; }\n#leak-radar .lr-row {\n    display: grid; grid-template-columns: 1fr 38px 42px 48px; gap: 4px;\n    padding: 2px 4px; border-bottom: 1px solid #1d2530;\n}\n#leak-radar .lr-row span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n#leak-radar .lr-row span:not(:first-child) { text-align: right; color: #aebccd; }\n#leak-radar .lr-row-head { position: sticky; top: 0; background: #10131a; }\n#leak-radar .lr-row-head span { color: #5f7186; font-size: 9px; text-transform: uppercase; }\n#leak-radar .lr-row-leak { background: #2a1717; }\n#leak-radar .lr-row-leak span:not(:first-child) { color: #ff8a70; }\n#leak-radar .lr-help {\n    font-size: 10px; line-height: 1.5; padding: 5px 6px; margin-bottom: 6px;\n    border-radius: 4px; background: #131a29; color: #a9bcd2; border: 1px solid #26314a;\n}\n#leak-radar .lr-help b { color: #cfe0f0; }\n#leak-radar .lr-detail {\n    background: #0d1420; border: 1px solid #2b3a52; border-radius: 4px;\n    padding: 4px 6px; margin-bottom: 4px;\n    user-select: text; -webkit-user-select: text;\n}\n#leak-radar .lr-detail-head { display: flex; justify-content: space-between; align-items: center; color: #cfe6ff; margin-bottom: 2px; }\n#leak-radar .lr-detail-trace { white-space: pre-wrap; word-break: break-word; color: #9fb4cc; font-size: 10px; }\n#leak-radar-mini {\n    position: fixed; top: calc(4px + env(safe-area-inset-top, 0px)); left: 4px; z-index: 2147483000;\n    display: none; align-items: center; gap: 7px; padding: 3px 7px;\n    background: rgba(16,19,26,0.85); border: 1px solid #2b3340; border-radius: 4px;\n    font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 11px;\n    color: #d7e0ea; cursor: pointer; user-select: none;\n}\n#leak-radar-mini .lrm-v { white-space: nowrap; }\n#leak-radar-mini .lrm-x { color: #6f8298; padding: 0 2px; }\n@media (pointer: coarse) {\n    #leak-radar-mini { font-size: 13px; padding: 6px 10px; gap: 9px; }\n    #leak-radar { font-size: 13px; width: min(360px, 94vw); }\n    #leak-radar .lr-btn { font-size: 14px; padding: 5px 9px; }\n    #leak-radar .lr-tab { font-size: 12px; padding: 8px 3px; }\n    #leak-radar .lr-card-label { font-size: 10px; }\n    #leak-radar .lr-card-value { font-size: 17px; }\n    #leak-radar .lr-summary, #leak-radar .lr-help { font-size: 12px; }\n    #leak-radar .lr-row { padding: 7px 4px; font-size: 12px; grid-template-columns: 1fr 44px 48px 54px; }\n    #leak-radar .lr-row-head { padding: 3px 4px; }\n    #leak-radar .lr-row-head span { font-size: 10px; }\n    #leak-radar .lr-delta { font-size: 11px; }\n    #leak-radar .lr-detail-trace { font-size: 12px; }\n    #leak-radar .lr-rec { font-size: 11px; }\n}\n`;\n","import { ISuspect } from './LeakRadarTypes';\n\ninterface IOrphanEntry {\n    ref: any; // WeakRef<DisplayObject>\n    type: string;\n    owner: string;\n    site?: string;\n    trace?: string;\n    firstSeen: number;\n    lastAttached: number;\n}\n\n// Resolved off globalThis so the build does not require the ES2021 lib types.\nconst WeakRefCtor: any = (globalThis as any).WeakRef;\nconst FinalizationRegistryCtor: any = (globalThis as any).FinalizationRegistry;\n\n/**\n * How long an object may stay parent-less before it is reported. This absorbs\n * legitimate \"remove now, re-add in a moment\" patterns AND gives the GC time to\n * collect objects that were removed and dereferenced: an unreferenced object\n * may linger a few seconds until collection (it then disappears on its own via\n * the FinalizationRegistry), while a real leak stays listed and keeps aging.\n */\nexport const ORPHAN_GRACE_MS = 2500;\nconst SOFT_CAP = 20000;\n\n/**\n * Finds \"leftover\" display objects: things that were once attached to the\n * scene, got removed from their parent, but were never destroyed and are still\n * referenced somewhere (a tween, an array, a closure) — the classic detached\n * leak the scene-graph census alone cannot see.\n *\n * Pure runtime, no instrumentation of constructors: every object the census\n * walks is remembered behind a WeakRef (so we never keep it alive ourselves).\n * An entry is reported as an orphan when its object is still alive, no longer\n * has a parent, and was not destroyed. A FinalizationRegistry prunes entries\n * once the GC actually frees them, so a real leak stays listed while a normal\n * remove-then-collect disappears on its own.\n */\nexport default class OrphanTracker {\n    private _seen: Map<number, IOrphanEntry> = new Map();\n    private _ids: WeakMap<object, number> = new WeakMap();\n    private _nextId = 1;\n    private _registry: any = FinalizationRegistryCtor\n        ? new FinalizationRegistryCtor((id: number) => this._seen.delete(id))\n        : null;\n\n    public get supported(): boolean {\n        return !!WeakRefCtor;\n    }\n\n    /** Remember a currently-attached display object (called during the walk). */\n    public markAttached(obj: any, owner: string): void {\n        if (!WeakRefCtor || !obj || typeof obj !== 'object' || !obj.parent || obj._destroyed) {\n            return;\n        }\n        const now = Date.now();\n        let id = this._ids.get(obj);\n        if (id === undefined) {\n            if (this._seen.size > SOFT_CAP) {\n                this._prune();\n            }\n            id = this._nextId++;\n            this._ids.set(obj, id);\n            this._seen.set(id, {\n                ref: new WeakRefCtor(obj),\n                type: obj.constructor?.name || 'Unknown',\n                owner,\n                site: obj.__lrSite,\n                trace: obj.__lrTrace,\n                firstSeen: now,\n                lastAttached: now,\n            });\n            this._registry?.register(obj, id);\n        } else {\n            const e = this._seen.get(id);\n            if (e) {\n                e.lastAttached = now;\n                e.owner = owner;\n                // The creation site may only have been stamped on a later add.\n                if (!e.site && obj.__lrSite) {\n                    e.site = obj.__lrSite;\n                    e.trace = obj.__lrTrace;\n                }\n            }\n        }\n    }\n\n    /** Count + group the objects that are detached but still alive. */\n    public orphans(): { count: number; suspects: ISuspect[] } {\n        if (!WeakRefCtor) {\n            return { count: 0, suspects: [] };\n        }\n        const now = Date.now();\n        const groups = new Map<\n            string,\n            { count: number; oldest: number; label: string; site?: string; trace?: string }\n        >();\n        let count = 0;\n\n        for (const [id, e] of Array.from(this._seen.entries())) {\n            const obj = e.ref.deref();\n            if (!obj || obj._destroyed) {\n                this._seen.delete(id); // collected or properly destroyed\n                continue;\n            }\n            // Still parented, or only just removed — not a confirmed leak yet.\n            if (obj.parent || now - e.lastAttached <= ORPHAN_GRACE_MS) {\n                continue;\n            }\n            count++;\n            // Group by the creation site when we have it (the actionable line),\n            // otherwise fall back to the owning view.\n            const where = e.site || e.owner;\n            const key = `${e.type}|${where}`;\n            const label = e.site ? `${e.type} · ${e.site}` : `${e.type} @ ${e.owner}`;\n            const g = groups.get(key) || { count: 0, oldest: now, label, site: e.site, trace: e.trace };\n            g.count++;\n            // Age = how long it has been DETACHED (not how old the object is) —\n            // the longer past the grace period, the more certain the leak.\n            g.oldest = Math.min(g.oldest, e.lastAttached);\n            groups.set(key, g);\n        }\n\n        const suspects: ISuspect[] = Array.from(groups.entries())\n            .map(([key, v]) => ({\n                key,\n                label: v.label,\n                count: v.count,\n                oldestMs: now - v.oldest,\n                site: v.site,\n                trace: v.trace,\n            }))\n            .sort((a, b) => b.count - a.count);\n\n        return { count, suspects };\n    }\n\n    private _prune(): void {\n        for (const [id, e] of Array.from(this._seen.entries())) {\n            const obj = e.ref.deref();\n            if (!obj || obj._destroyed) {\n                this._seen.delete(id);\n            }\n        }\n    }\n}\n","import Core from '@egt/core';\nimport { Container, Graphics, Sprite, Text, utils } from 'pixi.js';\nimport { ISuspect } from './LeakRadarTypes';\nimport OrphanTracker from './OrphanTracker';\n\n/** Generic PIXI display classes - anything else is treated as a \"component\". */\nconst GENERIC_CLASSES = new Set<string>([\n    'DisplayObject',\n    'Container',\n    'Sprite',\n    'AnimatedSprite',\n    'TilingSprite',\n    'Text',\n    'BitmapText',\n    'Graphics',\n    'Mesh',\n    'SimpleMesh',\n    'SimpleRope',\n    'SimplePlane',\n    'NineSlicePlane',\n    'ParticleContainer',\n    'Spine',\n    'Stage',\n]);\n\nconst MAX_DEPTH = 400;\n\nexport interface ISceneCounts {\n    nodes: number;\n    sprites: number;\n    texts: number;\n    graphics: number;\n    spine: number;\n    containers: number;\n    /** Custom component class -> number of live instances of it. */\n    componentInstances: Map<string, number>;\n    /** Custom component class -> number of leaf visuals it owns. */\n    componentLeaves: Map<string, number>;\n}\n\ntype LeafKind = 'sprites' | 'texts' | 'graphics' | 'spine' | null;\n\n/**\n * Reads what is actually alive, with no instrumentation of the engine:\n *  - walks the PIXI scene graph from the stage root and tallies display\n *    objects by type, attributing every leaf visual to the nearest custom\n *    component class that owns it;\n *  - enumerates the PIXI BaseTexture cache for live texture count + memory.\n *\n * This directly answers \"which component subtree keeps growing\" - the most\n * common leak being a view that is recreated every round but never removed\n * from its parent.\n */\nexport default class SceneCensus {\n    private _orphans = new OrphanTracker();\n    /** BaseTexture -> owning component (first user seen in the latest walk). */\n    private _texOwners: Map<any, string> = new Map();\n\n    public walk(): ISceneCounts {\n        this._texOwners = new Map();\n        const counts: ISceneCounts = {\n            nodes: 0,\n            sprites: 0,\n            texts: 0,\n            graphics: 0,\n            spine: 0,\n            containers: 0,\n            componentInstances: new Map(),\n            componentLeaves: new Map(),\n        };\n\n        const root = this._root();\n        if (root) {\n            this._visit(root, '(stage)', counts, 0);\n        }\n        return counts;\n    }\n\n    /** Build the component suspects list from a walk result. */\n    public componentSuspects(counts: ISceneCounts): ISuspect[] {\n        const out: ISuspect[] = [];\n        counts.componentInstances.forEach((instances, key) => {\n            out.push({\n                key,\n                label: key,\n                count: instances,\n                detail: counts.componentLeaves.get(key) || 0,\n            });\n        });\n        // Most instances first, then most owned visuals.\n        out.sort((a, b) => b.count - a.count || (b.detail || 0) - (a.detail || 0));\n        return out;\n    }\n\n    /** Detached-but-alive display objects seen during the walks so far. */\n    public orphans(): { count: number; suspects: ISuspect[] } {\n        return this._orphans.orphans();\n    }\n\n    /** Enumerate the live BaseTexture cache: count, total MB and per-source rows. */\n    public textures(): { count: number; mb: number; suspects: ISuspect[] } {\n        const cache: Record<string, any> = (utils as any).BaseTextureCache || {};\n        const groups = new Map<\n            string,\n            { count: number; bytes: number; label: string; site?: string; trace?: string }\n        >();\n        let count = 0;\n        let bytes = 0;\n\n        for (const key in cache) {\n            const bt = cache[key];\n            // Destroyed BaseTextures must never be reported (PIXI usually removes\n            // them from the cache, but be defensive so the radar matches reality).\n            if (!bt || bt.destroyed) {\n                continue;\n            }\n            count++;\n            const w = bt.realWidth || bt.width || 0;\n            const h = bt.realHeight || bt.height || 0;\n            let b = w * h * 4;\n            if (bt.mipmap) {\n                b = Math.floor(b * 1.33);\n            }\n            bytes += b;\n\n            const src = sourceLabel(key);\n            const site = bt.__lrSite as string | undefined;\n            const usedBy = this._texOwners.get(bt);\n            // File textures: the file name says it all. Anonymous ones (canvas,\n            // Text, video, generated — \"pixiid_*\" keys) get dimensions plus the\n            // creation site, or at least which component is using them.\n            const isAnonymous = src === '(canvas / dataURI)' || key.indexOf('pixiid') === 0;\n            let groupKey = src;\n            let label = src;\n            if (isAnonymous) {\n                const where = site || (usedBy ? `used by ${usedBy}` : '(created before capture)');\n                groupKey = `anon·${where}·${w}x${h}`;\n                label = `canvas ${w}x${h} · ${where}`;\n            }\n            const trace = (bt.__lrTrace as string | undefined) || (usedBy ? `used by ${usedBy}` : undefined);\n            const g = groups.get(groupKey) || { count: 0, bytes: 0, label, site, trace };\n            g.count++;\n            g.bytes += b;\n            groups.set(groupKey, g);\n        }\n\n        const suspects: ISuspect[] = Array.from(groups.entries())\n            .map(([key, v]) => ({ key, label: v.label, count: v.count, bytes: v.bytes, site: v.site, trace: v.trace }))\n            .sort((a, b) => (b.bytes || 0) - (a.bytes || 0));\n\n        return { count, mb: bytes / (1024 * 1024), suspects };\n    }\n\n    /**\n     * Estimate GPU memory actually held by the renderer: every uploaded\n     * BaseTexture (the texture system's managed list — includes render\n     * textures and video textures that never enter the cache), framebuffers\n     * and the WebGL canvas itself. Render textures appear both as textures\n     * and framebuffers, so this slightly overestimates — fine for a trend\n     * metric: iOS Safari reloads the page on GPU/memory pressure, and this\n     * is the number that climbs toward that limit.\n     */\n    public gpu(): { vramMB: number } {\n        const stage: any = (Core as any).stage;\n        const renderer: any = stage?.renderer || stage?.app?.renderer;\n        if (!renderer) {\n            return { vramMB: 0 };\n        }\n        let bytes = 0;\n        const managed: any[] = renderer.texture?.managedTextures || renderer.texture?._managedTextures || [];\n        for (let i = 0; i < managed.length; i++) {\n            const bt = managed[i];\n            if (!bt || bt.destroyed || !bt.valid) {\n                continue;\n            }\n            let b = (bt.realWidth || bt.width || 0) * (bt.realHeight || bt.height || 0) * 4;\n            if (bt.mipmap) {\n                b *= 1.33;\n            }\n            bytes += b;\n        }\n        const fbs: any[] = renderer.framebuffer?.managedFramebuffers || [];\n        for (let i = 0; i < fbs.length; i++) {\n            bytes += (fbs[i]?.width || 0) * (fbs[i]?.height || 0) * 4;\n        }\n        const view = renderer.view;\n        if (view) {\n            bytes += (view.width || 0) * (view.height || 0) * 4;\n        }\n        return { vramMB: bytes / (1024 * 1024) };\n    }\n\n    private _root(): any {\n        const stage: any = (Core as any).stage;\n        if (!stage) {\n            return null;\n        }\n        return stage.app?.stage || stage.stage || null;\n    }\n\n    private _visit(node: any, owner: string, counts: ISceneCounts, depth: number): void {\n        if (!node || depth > MAX_DEPTH) {\n            return;\n        }\n\n        const className: string = node.constructor?.name || 'Unknown';\n        let currentOwner = owner;\n\n        // A non-generic class node is a \"component\" and owns its whole subtree.\n        if (!GENERIC_CLASSES.has(className)) {\n            currentOwner = className;\n            counts.componentInstances.set(className, (counts.componentInstances.get(className) || 0) + 1);\n        }\n\n        counts.nodes++;\n\n        const leaf = classify(node);\n        if (leaf) {\n            counts[leaf]++;\n            counts.componentLeaves.set(currentOwner, (counts.componentLeaves.get(currentOwner) || 0) + 1);\n        } else {\n            counts.containers++;\n        }\n\n        this._orphans.markAttached(node, currentOwner);\n\n        // Remember which component first uses each texture, so cache entries with\n        // anonymous ids (canvas/text/video) can still be attributed in the panel.\n        const bt =\n            node.texture?.baseTexture || node._texture?.baseTexture || node.material?.texture?.baseTexture || null;\n        if (bt && !this._texOwners.has(bt)) {\n            this._texOwners.set(bt, currentOwner);\n        }\n\n        // A Spine is one logical unit; descending into its slot meshes is noise.\n        if (leaf === 'spine') {\n            return;\n        }\n\n        const children = node.children;\n        if (children && children.length) {\n            for (let i = 0; i < children.length; i++) {\n                this._visit(children[i], currentOwner, counts, depth + 1);\n            }\n        }\n    }\n}\n\n/** Classify a node into a leaf visual kind, or null for container-like nodes. */\nfunction classify(node: any): LeafKind {\n    if (isSpine(node)) {\n        return 'spine';\n    }\n    // NB: in PIXI 6 Text extends Sprite, so Text must be checked first.\n    if (node instanceof Text || node.constructor?.name === 'BitmapText') {\n        return 'texts';\n    }\n    if (node instanceof Sprite) {\n        return 'sprites';\n    }\n    if (node instanceof Graphics) {\n        return 'graphics';\n    }\n    // Containers (incl. custom views) are structural, not leaf visuals.\n    if (node instanceof Container) {\n        return null;\n    }\n    return null;\n}\n\n/** Duck-type pixi-spine without taking a hard dependency on it. */\nfunction isSpine(node: any): boolean {\n    return node?.constructor?.name === 'Spine' || (!!node?.skeleton && !!node?.state);\n}\n\n/** Shorten a BaseTexture cache key to a readable source label. */\nfunction sourceLabel(key: string): string {\n    if (!key) {\n        return '(unknown)';\n    }\n    if (key.startsWith('data:')) {\n        return '(canvas / dataURI)';\n    }\n    const noQuery = key.split('?')[0];\n    return noQuery.split('/').pop() || noQuery;\n}\n","/**\n * Stack-trace helpers shared by the probes. They turn a raw `Error().stack`\n * into the name of the app function that ran — which is far more useful than a\n * line number, because bundled/source-mapped line numbers often do not line up\n * with the editor. Framework frames (PIXI, GSAP, the probes) are skipped so the\n * reported function belongs to game code.\n *\n * Two build flavours produce two very different stacks:\n *  - eval source maps: frames carry `webpack-internal:///.../File.ts` paths, so\n *    engine frames are recognised by their PATH (the SKIP list below);\n *  - external source maps: V8 does NOT apply source maps to `Error.stack`, so\n *    every frame points at the bundle (`bundle.js:123`). Paths are useless\n *    then, but dev bundles are not minified, so the original FUNCTION NAMES\n *    survive — engine frames are recognised by their class name instead.\n */\n\nconst SKIP = [\n    '/@pixi',\n    'pixi.js',\n    'pixi-spine',\n    'node_modules',\n    '/gsap/',\n    'gsap.js',\n    'LeakRadar',\n    'GsapProbe',\n    'CreationProbe',\n    'SceneCensus',\n    'OrphanTracker',\n    'stackUtil',\n    'TextureHook',\n    // the probes' own wrapper functions carry this name (visible even when the\n    // file path is gone, e.g. \"Texture.__lrProbe [as from] (bundle.js:1:2)\")\n    '__lrProbe',\n];\n\n/**\n * Engine classes whose methods must never be reported as the creation site.\n * Matched against the parsed function name (\"Text.updateText\", \"new Sprite\",\n * \"Tween.render\"). Longer names go before their prefixes (TextMetrics before\n * Text) because alternation picks the first match.\n */\nconst ENGINE_FN =\n    /^(new )?(AbstractRenderer|AnimationState|BaseImageResource|BasePrepare|BaseTexture|BatchRenderer|BitmapFont|BitmapText|Callback|CanvasResource|Container|DisplayObject|EventEmitter|Graphics|ImageResource|Loader|MeshMaterial|Mesh|ObservablePoint|RenderTexture|Renderer|Resource|Skeleton|Spine|Spritesheet|Sprite|TextMetrics|TextStyle|TextureSystem|TextureUvs|Texture|Text|Ticker|Timeline|Transform|Tween|VideoResource)([._ []|$)/;\n\ninterface IFrame {\n    fn: string;\n    file: string;\n    line: string;\n}\n\n/** Parse one raw stack line into { function, file, line }. */\nfunction parseFrame(raw: string): IFrame {\n    const s = raw.trim().replace(/^at\\s+/, '');\n    let fn = '';\n    let loc = s;\n    const paren = s.match(/^(.*?)\\s+\\((.*)\\)\\s*$/);\n    if (paren) {\n        fn = paren[1];\n        loc = paren[2];\n    }\n    loc = loc.replace('webpack-internal:///', '').replace(/https?:\\/\\/[^/]+\\//, '');\n    const lm = loc.match(/([^/()\\s]+):(\\d+):\\d+/);\n    const file = lm ? lm[1].split('/').pop() || lm[1] : '';\n    const line = lm ? lm[2] : '';\n    fn = fn\n        .replace(/^async\\s+/, '')\n        .replace(/^Object\\./, '')\n        .trim();\n    if (!fn || fn === '<anonymous>') {\n        fn = '';\n    }\n    return { fn, file, line };\n}\n\n/** True when the frame's location still names an original source file. */\nfunction hasSourceFile(f: IFrame): boolean {\n    return /\\.tsx?$/.test(f.file);\n}\n\n/** Decide whether a parsed frame belongs to game code. */\nfunction frameIsApp(raw: string, f: IFrame): boolean {\n    if (!raw || SKIP.some((s) => raw.indexOf(s) !== -1)) {\n        return false;\n    }\n    // A real source-file path identifies app code even for anonymous frames\n    // (the eval-source-map flavour, where engine paths were filtered above).\n    if (hasSourceFile(f)) {\n        return true;\n    }\n    // Bundle-only frame: the function name is all we have.\n    if (!f.fn || f.fn === 'eval') {\n        return false;\n    }\n    if (/^_[a-z$]/.test(f.fn)) {\n        // bare gsap-style internals (_lazyRender, _renderZeroDurationTween, …)\n        return false;\n    }\n    return !ENGINE_FN.test(f.fn);\n}\n\n/** Name of the first app function in the stack (falls back to file:line). */\nexport function firstAppFrame(stack?: string): string {\n    if (!stack) {\n        return '?';\n    }\n    const lines = stack.split('\\n');\n    for (let i = 1; i < lines.length; i++) {\n        const f = parseFrame(lines[i]);\n        if (!frameIsApp(lines[i], f)) {\n            continue;\n        }\n        if (f.fn && f.fn !== 'eval') {\n            return f.fn;\n        }\n        if (f.file) {\n            return `${f.file}:${f.line}`;\n        }\n    }\n    return '(framework only)';\n}\n\n/** Up to `n` app frames as \"function (File.ts:line)\" joined with arrows. */\nexport function appTrace(stack: string | undefined, n: number): string {\n    if (!stack) {\n        return '';\n    }\n    const out: string[] = [];\n    const lines = stack.split('\\n');\n    for (let i = 1; i < lines.length && out.length < n; i++) {\n        const f = parseFrame(lines[i]);\n        if (!frameIsApp(lines[i], f)) {\n            continue;\n        }\n        if (f.fn) {\n            // bundle coordinates add nothing — show them only for real source files\n            out.push(hasSourceFile(f) ? `${f.fn} (${f.file}:${f.line})` : f.fn);\n        } else if (f.file) {\n            out.push(`${f.file}:${f.line}`);\n        }\n    }\n    return out.join('  ←  ');\n}\n","import Core, { IRequest } from './Core';\nimport ErrorTypes from './enums/ErrorTypes';\nimport { getActiveSentrySpan, getMemoryUsage, SENTRY_DATA } from './sentry/sentry-utils';\nimport * as Sentry from '@sentry/browser';\nimport SessionMetricsCollector from './metrics/SessionMetricsCollector';\n\nexport default class AnalyticsDispatcher {\n    public static reelsStoppedAnalyticsEvent(\n        gameKey: string,\n        stateOfGame: string,\n        isDesktop: boolean,\n        isDemo: boolean,\n        orientation: string,\n        device: string,\n        autoplay: boolean,\n        isGameFastStopped: boolean,\n        fullScreenMode: boolean, // full screen value is not correct when website is zoomed.\n        isLeftHand: boolean,\n        quickMode: boolean,\n        turboMode: boolean,\n        spinMode: string,\n        soundMuted: boolean,\n        batterySaver: boolean,\n        doubleChanceActive: boolean = false,\n        betBtnIndex: number,\n        denomination: number,\n        currency: string,\n        factor: number,\n        backgroundSoundMuted: boolean | undefined,\n    ): void {\n        const gtag = (window as any).gtag;\n        if (!gtag) {\n            return;\n        }\n\n        gtag('event', 'spin', {\n            gameKey,\n            stateOfGame,\n            isDesktop,\n            isDemo,\n            orientation,\n            device,\n            autoplay,\n            isGameFastStopped,\n            fullScreenMode, // full screen value is not correct when website is zoomed.\n            isLeftHand,\n            quickMode,\n            turboMode,\n            spinMode,\n            soundMuted,\n            batterySaver,\n            doubleChanceActive,\n            betBtnIndex,\n            denomination,\n            currency,\n            factor,\n            backgroundSoundMuted,\n        });\n    }\n\n    public static sendOpenGameEvent(): void {\n        const gtag = (window as any).gtag;\n        if (!gtag || Core.configuration.comeFromLobby) {\n            return;\n        }\n        let fromLobby = false;\n        let tab = '';\n        let languageChanged = false;\n        let gameImage = '';\n        let sectionPosition = 0;\n        let sectionName = '';\n        // console.log('openGame exchange', Core.gamePortalExchangeObject);\n        if (Object.keys(Core.gamePortalExchangeObject).length > 0) {\n            fromLobby = true;\n            if (Core.gamePortalExchangeObject.tab === '') {\n                tab = 'lobby';\n                sectionName = Core.gamePortalExchangeObject.groupId;\n                sectionPosition = Core.gamePortalExchangeObject.groupOrder;\n            } else {\n                tab = sectionName = Core.gamePortalExchangeObject.tab;\n                sectionPosition = 1;\n            }\n            // TODO: some day chane 1x2, 1x2, 2x1 folders to be as received regulat/horizontal/vertical\n            switch (Core.gamePortalExchangeObject.imageFolder) {\n                case '1x1':\n                    gameImage = 'regular';\n                    break;\n                case '1x2':\n                    gameImage = 'horizontal';\n                    break;\n                case '2x1':\n                    gameImage = 'vertical';\n                    break;\n                default:\n                    gameImage = Core.gamePortalExchangeObject.imageFolder;\n            }\n            languageChanged = Core.gamePortalExchangeObject.entryLanguage !== Core.translator.currentLanguage;\n        }\n\n        gtag('event', 'openGame', {\n            gameKey: Core.configuration.gameKey,\n            fromLobby,\n            language: Core.translator.currentLanguage,\n            languageChanged,\n            tab,\n            isDemo: Core.configuration.demo,\n            sectionName,\n            sectionPosition,\n            gameImage,\n        });\n    }\n\n    public static sendTimeMetricEvent(state: string, event: string, responseTime: number): void {\n        const gtag = (window as any).gtag;\n        if (!gtag) {\n            return;\n        }\n\n        gtag('event', 'timeMetrics', {\n            gameKey: Core.configuration.gameKey,\n            isDemo: Core.configuration.demo,\n            state,\n            eventName: event,\n            responseTimeInMs: responseTime,\n        });\n    }\n\n    public static sendErrorEvent(errType: ErrorTypes, errCode: string, errDescription: any): void {\n        const gtag = (window as any).gtag;\n        if (!gtag) {\n            return;\n        }\n        const errorType = ErrorTypes[errType];\n        let description = '';\n        if (typeof errDescription === 'object') {\n            Object.entries(errDescription).forEach(([key, value]) => {\n                description += `${key}=${JSON.stringify(value)}; `;\n            });\n        } else {\n            description = JSON.stringify(errDescription);\n        }\n\n        gtag('event', 'appError', {\n            errorType,\n            errCode,\n            description,\n            gameKey: Core.configuration.gameKey,\n            isDesktop: Core.isDesktopMode,\n            isDemo: Core.configuration.demo,\n            device: Core.environment.getDevice()?.model + ' ' + Core.environment.getDevice()?.type,\n            os: Core.environment.getOS().name + ' ' + Core.environment.getOS().version,\n            browser: Core.environment.getBrowser().name + ' ' + Core.environment.getBrowser().version,\n        });\n    }\n\n    public static buyBonusClickEvent(): void {\n        const gtag = (window as any).gtag;\n        if (!gtag) {\n            return;\n        }\n\n        gtag('event', 'buyBonusPurchase', {\n            gameKey: Core.configuration.gameKey,\n            isDemo: Core.configuration.demo,\n        });\n    }\n\n    public static slideFeatureEvent(betBtnIndex: number): void {\n        const gtag = (window as any).gtag;\n        if (!gtag) {\n            return;\n        }\n\n        gtag('event', 'slideFeature', {\n            betBtnIndex,\n        });\n    }\n\n    public static playerHistoryClicked(): void {\n        const gtag = (window as any).gtag;\n        if (!gtag) {\n            return;\n        }\n\n        gtag('event', 'playerHistoryClicked', {\n            gameKey: Core.configuration.gameKey,\n            isDemo: Core.configuration.demo,\n        });\n    }\n\n    public static homeButtonClicked(): void {\n        if (Core.sentryClient) {\n            const currentSpan = getActiveSentrySpan();\n            if (currentSpan) {\n                currentSpan.setAttribute(SENTRY_DATA.ROUND.OPEN_LOBBY, 'true');\n                currentSpan.setStatus({ code: 1 });\n                currentSpan.end();\n            }\n        }\n\n        const gtag = (window as any).gtag;\n        if (!gtag) {\n            return;\n        }\n\n        gtag('event', 'homeButtonClicked', {\n            gameKey: Core.configuration.gameKey,\n            isDemo: Core.configuration.demo,\n        });\n    }\n\n    public static exitButtonClicked(): void {\n        const gtag = (window as any).gtag;\n        if (!gtag) {\n            return;\n        }\n\n        gtag('event', 'exitButtonClicked', {\n            gameKey: Core.configuration.gameKey,\n            isDemo: Core.configuration.demo,\n        });\n    }\n\n    public static settingsButtonClicked(): void {\n        const gtag = (window as any).gtag;\n        if (!gtag) {\n            return;\n        }\n\n        gtag('event', 'settingsButtonClicked', {\n            gameKey: Core.configuration.gameKey,\n            isDemo: Core.configuration.demo,\n        });\n    }\n\n    public static jackpotFieldClicked(jackpotName: string, jackpotLevel: any): void {\n        const gtag = (window as any).gtag;\n        if (!gtag) {\n            return;\n        }\n        gtag('event', 'jackpotFieldClicked', {\n            gameKey: Core.configuration.gameKey,\n            isDemo: Core.configuration.demo,\n            jackpotName: jackpotName,\n            jackpotLevel: jackpotLevel,\n        });\n    }\n\n    public static gameStart(): void {\n        if (Core.sentryClient) {\n            const getCurrentSpan = getActiveSentrySpan();\n            if (getCurrentSpan) {\n                const usedMemory = getMemoryUsage();\n                Sentry.setMeasurement(\n                    SENTRY_DATA.PERFORMANCE.MEMORY.USED_JSHEAP_SIZE,\n                    usedMemory?.usedJSHeapSize || 0,\n                    'megabyte',\n                    getCurrentSpan,\n                );\n                Sentry.setMeasurement(\n                    SENTRY_DATA.PERFORMANCE.MEMORY.TOTAL_JSHEAP_SIZE,\n                    usedMemory?.totalJSHeapSize || 0,\n                    'megabyte',\n                    getCurrentSpan,\n                );\n                Sentry.setMeasurement(\n                    SENTRY_DATA.PERFORMANCE.MEMORY.JSHEAP_SIZE_LIMIT,\n                    usedMemory?.jsHeapSizeLimit || 0,\n                    'megabyte',\n                    getCurrentSpan,\n                );\n                getCurrentSpan.setStatus({ code: 1 });\n                getCurrentSpan.end(Date.now());\n            }\n            // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n            const orientation = Core.ORIENTATION.value.orientation;\n            // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n            let music = Core.sounds.ON_BACKGROUND_SOUNDS_MUTED.value ? 'false' : 'true';\n            // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n            const sound = Core.sounds.ON_SOUND_MUTED.value ? 'false' : 'true';\n\n            // we switch off the music along with the sounds\n            if (Core.sounds.ON_SOUND_MUTED.value) {\n                music = 'false';\n            }\n\n            // startSentryTransaction(Core.sentryClient, SentryTransactionTypes.GAME_IDLE, {\n            //     [SENTRY_DATA.SETTINGS.MUSIC]: music,\n            //     [SENTRY_DATA.SETTINGS.SOUND]: sound,\n            //     [SENTRY_DATA.ROUND.ORIENTATION]: orientation,\n            // });\n        }\n    }\n\n    public static sendMessage(request: { event?: string } & IRequest): void {\n        if (Core.sentryClient) {\n            if (request.event && request.event === 'bet') {\n                const orientation = Core.ORIENTATION.value.orientation;\n                let music = Core.sounds.ON_BACKGROUND_SOUNDS_MUTED.value ? 'false' : 'true';\n                const sound = Core.sounds.ON_SOUND_MUTED.value ? 'false' : 'true';\n\n                // we switch off the music along with the sounds\n                if (Core.sounds.ON_SOUND_MUTED.value) {\n                    music = 'false';\n                }\n\n                const roundData = {\n                    [SENTRY_DATA.SETTINGS.MUSIC]: music,\n                    [SENTRY_DATA.SETTINGS.SOUND]: sound,\n                    [SENTRY_DATA.ROUND.ORIENTATION]: orientation,\n                };\n\n                if (!isNaN(this.spinSpeed)) {\n                    roundData[SENTRY_DATA.ROUND.SPIN_SPEED] = this.spinSpeed;\n                }\n\n                if (this.spinMode) {\n                    roundData[SENTRY_DATA.ROUND.SPIN_MODE] = this.spinMode;\n                }\n\n                // startSentryTransaction(Core.sentryClient, SentryTransactionTypes.GAME_ROUND, roundData);\n            }\n        }\n    }\n\n    // ==============================\n    // Session metrics wrappers (Collector access via Dispatcher)\n    // ==============================\n    public static incrementUserAction(action: string): void {\n        try {\n            SessionMetricsCollector.getInstance().incrementUserAction(action);\n        } catch (_) {\n            /* noop */\n        }\n    }\n\n    public static onSpinStarted(payload: {\n        orientation: string;\n        desktop: boolean;\n        spinMode: string;\n        spinSpeed?: number;\n    }): void {\n        try {\n            SessionMetricsCollector.getInstance().onSpinStarted(payload);\n        } catch (_) {\n            /* noop */\n        }\n    }\n\n    public static onReelsStopped(payload: {\n        quickMode: boolean;\n        turboMode: boolean;\n        specialSpinSpeedDisabled?: boolean;\n    }): void {\n        try {\n            SessionMetricsCollector.getInstance().onReelsStopped(payload);\n        } catch (_) {\n            /* noop */\n        }\n    }\n\n    public static recordServerResponseTime(ms: number, eventName?: string): void {\n        try {\n            SessionMetricsCollector.getInstance().recordServerResponseTime(ms, eventName);\n        } catch (_) {\n            /* noop */\n        }\n    }\n\n    public static forceFlushSessionMetrics(): void {\n        try {\n            SessionMetricsCollector.getInstance().forceFlush();\n        } catch (_) {\n            /* noop */\n        }\n    }\n\n    public static getCurrentSessionMetrics(): any {\n        try {\n            return SessionMetricsCollector.getInstance().getCurrentMetrics();\n        } catch (_) {\n            return null;\n        }\n    }\n    public static spinSpeed: number;\n    public static spinMode: string;\n}\n","import { IAsset } from './Core';\n\nexport default class AssetsCollection {\n    private map = new Map<string, IAsset>();\n\n    constructor(initial: IAsset[] = []) {\n        this.merge(initial);\n    }\n\n    public merge(next: IAsset[] = []) {\n        for (const a of next) this.map.set(a.id, a);\n    }\n\n    public remove(ids: string[] = []): void {\n        for (const id of ids) this.map.delete(id);\n    }\n\n    public toArray(): IAsset[] {\n        return Array.from(this.map.values());\n    }\n}\n","import { Howl } from 'howler';\nimport { BitmapFont, Loader, LoaderResource, Texture, utils } from 'pixi.js';\nimport { ToneAudioBuffer } from 'tone';\nimport { inject, injectable, singleton } from 'tsyringe';\nimport PriorityQueue from 'typescript-collections/dist/lib/PriorityQueue';\nimport { Logger } from 'unicorn.console-logger';\nimport Core, { LifeCycle, Log, PostMessageDispatcher } from './Core';\nimport AssetPriority from './enums/AssetPriority';\nimport { LoggerGroups } from './enums/LoggerGroups';\nimport { IAsset } from './interfaces/IAsset';\nimport { AssetsReplaceMode, IAssetsLoader } from './interfaces/IAssetsLoader';\nimport { ILoadAsset } from './interfaces/ILoadAsset';\nimport { ILoadingIndicator } from './interfaces/ILoadingIndicator';\nimport { ISoundAsset } from './interfaces/ISoundAsset';\nimport { IToneSoundAsset } from './interfaces/IToneSoundAsset';\n\n@injectable()\n@singleton()\nexport default class AssetsLoader implements IAssetsLoader {\n    /**\n     * We use this to put as separator on asset id when mult url asset is loaded\n     * https://jira.egt-bg.com/browse/ONL-187\n     */\n\n    private readonly multiUrlSeparator: string = '_____';\n    /**\n     * Multi-purpose loader used to load everything except sounds.\n     */\n    private loader: Loader;\n\n    /**\n     * Force loader used to pause the current loading process and load paytable, gamble and other assets. After the end of the process it resumes the main loading one.\n     */\n    private forceLoader: Loader;\n\n    /**\n     * Prioritized assets queue to be loaded.\n     */\n    private assetsQueue: PriorityQueue<IAsset>;\n\n    /**\n     * A flag to indicate wether or not assets has been replaced.\n     */\n    private replacedAssets: boolean = false;\n\n    /**\n     * Flag related to if the force load resources are loaded or not\n     */\n    private forceLoadResourcesLoading: boolean = false;\n\n    /**\n     * Prioritized assets queue to be loaded in case of force load.\n     */\n    private forceLoadAssetsQueue: PriorityQueue<IAsset>;\n\n    /**\n     * Next group of assets to load.\n     */\n    private assetsLoading: { [key: string]: ILoadAsset };\n\n    /**\n     * Current priority of the assets being loaded.\n     */\n    private currentPriorityLoading: number | null;\n\n    /**\n     * Generic assets to load.\n     */\n    private genericAssetsToLoad: number;\n\n    /**\n     * Generic assets to load remaining.\n     */\n    private genericAssetsRemaining: number;\n\n    /**\n     * Sound assets to load.\n     */\n    private soundAssetsToLoad: number;\n\n    /**\n     * Sound assets to load remaining.\n     */\n    private soundAssetsRemaining: number;\n\n    /**\n     * Store reference to the loaded rasources here.\n     */\n    // private loadedAssets: Spritesheet[] | Spritesheet[][] = [];\n    public loadedAssets: Map<string, LoaderResource | never[]> = new Map();\n\n    /**\n     * Progress percentages.\n     */\n    private progressPercents: { generic: number; sound: number; total: number };\n\n    private highPriorityStep: number;\n    private lastEmitedProgres: number;\n\n    private svgMap: Map<string, any>;\n\n    private fallbackAssetIds: Map<string, string>;\n\n    /**\n     * Custom asset loader that makes use of Loader and Howler to load.\n     * Provided pixi loader instance to use. Uses Loader if none is specified.\n     * @param loadingIndicator\n     */\n    constructor(@inject('ILoadingIndicator') private loadingIndicator: ILoadingIndicator) {\n        this.svgMap = new Map();\n        this.fallbackAssetIds = new Map();\n        this.initLoaders();\n    }\n\n    /**\n     * Determines if there is sth loading right now.\n     * @returns {boolean}\n     */\n    public isLoading(): boolean {\n        return Object.keys(this.assetsLoading).length > 0;\n    }\n\n    /**\n     * Add provided asset to the asset queue.\n     * @param {IAsset} asset\n     */\n    public addAsset(asset: IAsset | ISoundAsset): this {\n        if (this.isAssetRegistered(asset.id)) {\n            this.changeAssetPriority(asset.id, asset.priority);\n            return this;\n        }\n        this.checkForDesktopOption(asset);\n        // add svg to svgMap\n        if (asset.type === 'svg') {\n            this.svgMap.set(asset.id, asset);\n        }\n\n        if (asset.type === 'sound') {\n            const timeStamp =\n                (window as any)?.ssi?.CustomResourcesHost &&\n                (Core.configuration.replaceAssets || Core.configuration.replaceSoundAssets)\n                    ? `&time=${Date.now()}`\n                    : '';\n            asset.url += `?${Core.hash}${timeStamp}`;\n        }\n\n        this.assetsQueue.enqueue(asset);\n        return this;\n    }\n\n    public changeAssetPriority(assetId: string, priority: AssetPriority): void {\n        this.assetsQueue.forEach((el) => {\n            if (el.id === assetId) {\n                el.priority = priority;\n            }\n        });\n    }\n\n    public isAssetRegistered(assetId: string): boolean {\n        let found: boolean = false;\n        this.assetsQueue.forEach((el) => {\n            if (el.id === assetId) {\n                found = true;\n            }\n        });\n        return found;\n    }\n\n    public getAssetsQueue(): PriorityQueue<IAsset> {\n        return this.assetsQueue;\n    }\n\n    /**\n     * Adds provided assets to the asset queue.\n     * @param {[IAsset]} assets\n     */\n    public addAssets(assets: IAsset[]): this {\n        assets.forEach((asset) => this.addAsset(asset));\n        return this;\n    }\n\n    /**\n     * Loads all assets on the asset queue batching them by priority.\n     */\n    public load(): this {\n        // this.assetsQueue.forEach(el => {\n        //     console.log(el.id, el.priority);\n        // });\n        if (!this.isLoading()) {\n            let steps: number = 0;\n            this.assetsQueue.forEach((asset) => {\n                if (asset.priority === AssetPriority.HIGHEST) {\n                    // For texture asset types there are two requests.\n                    steps += asset.type === 'texture' ? 2 : 1;\n                }\n            });\n            this.highPriorityStep = this.loadingIndicator.getAvailableSteps() / steps;\n            this.loadNextPriorityGroup();\n        }\n\n        return this;\n    }\n\n    /**\n     * Loads all forced assets on the forceLoadAssetsQueue. It pauses the current loading of the main loader and resumes it after all forced loaded assets are loaded.\n     */\n    public forceLoad(assets: IAsset[], callback: any): void {\n        // if (this.forceLoadResourcesLoading) {\n        //     Log.debug(\"Forceload is active already. Loading is skipped\", assets);\n        //     return;\n        // }\n        Log.debug('Forceloading', this.constructor.name, assets);\n        this.forceLoadResourcesLoading = true;\n        let newForcedAssets: number = 0;\n\n        assets.forEach((asset) => {\n            if (\n                !this.forceLoader.resources[asset.id] &&\n                !this.forceLoadAssetsQueue.contains(asset) &&\n                !this.loadedAssets.has(asset.id)\n            ) {\n                this.forceLoadAssetsQueue.enqueue(asset);\n                newForcedAssets++;\n            }\n        });\n\n        if (newForcedAssets > 0) {\n            while (this.forceLoadAssetsQueue.peek()) {\n                const asset: IAsset = this.forceLoadAssetsQueue.dequeue()!;\n                if (!this.loadedAssets.has(asset.id) && !Array.isArray(asset.url)) {\n                    this.forceLoader.add(asset.id, asset.url);\n                }\n            }\n        }\n\n        if (Object.keys(this.forceLoader.resources).length === 0) {\n            Log.debug('Forceload assets already have been added to queue ', this.constructor.name, assets);\n            this.forceLoadResourcesLoading = false;\n            callback();\n            return;\n        }\n\n        this.loader.reset();\n        this.loader.destroy();\n        utils.clearTextureCache();\n        this.forceLoader.load(() => {\n            this.forceLoadResourcesLoading = false;\n            this.forceLoadAssetsQueue.clear();\n            this.initLoader();\n            if (Object.keys(this.assetsLoading).length > 0) {\n                this.startLoadingAssets();\n            } else {\n                this.checkAllAssetsLoaded();\n            }\n            callback();\n        });\n    }\n\n    /**\n     * Resets queued and loading asset + Loader.\n     */\n    public reset(): this {\n        this.assetsQueue.clear();\n        this.loader.reset();\n        this.loader.destroy();\n        this.forceLoader.reset();\n        this.forceLoader.destroy();\n        this.loadedAssets.forEach((recource) => {\n            // @ts-ignore\n            if (recource.textures) {\n                // @ts-ignore\n                for (const property in recource.textures) {\n                    // @ts-ignore\n                    recource.textures[property].destroy(true);\n                    // @ts-ignore\n                    recource.textures[property] = null;\n                }\n            }\n            // @ts-ignore\n            if (recource.bitmapFont) {\n                // @ts-ignore\n                recource.bitmapFont.destroy();\n                // @ts-ignore\n                BitmapFont.uninstall(recource.bitmapFont.font);\n            }\n            // @ts-ignore\n            recource = null;\n        });\n        if (this.svgMap) {\n            this.svgMap.clear();\n        }\n\n        this.loadedAssets.clear();\n        utils.destroyTextureCache();\n        this.initLoaders();\n        return this;\n    }\n\n    /**\n     * Gets the asset that was stored in the loader.resources.\n     * @param id\n     */\n    public getAsset(id: string): any {\n        // return this.loader.resources[id];\n        return this.loadedAssets.get(id);\n    }\n\n    public getAssets(ids: string[]): Texture[] {\n        // return this.loader.resources[id];\n        const textures: Texture[] = [];\n        ids.forEach((a) => {\n            textures.push(this.getAsset(a).texture);\n        });\n        return textures;\n    }\n\n    /**\n     * Gets the animation assets from multi animations resource.\n     * @param spriteId\n     * @param animationId - send animation frame name without numbers at the end\n     */\n    public getAnimationAssets(spriteId: string, animationId: string): any {\n        const asset = this.getAsset(spriteId);\n\n        let symbolTextures = {};\n        if (Array.isArray(asset)) {\n            asset.forEach((a) => {\n                symbolTextures = Object.assign(symbolTextures, a.spritesheet.textures);\n            });\n        } else {\n            symbolTextures = asset.spritesheet.textures;\n        }\n        const frames = Object.keys(symbolTextures)\n            .filter((name) => name.startsWith(animationId))\n            .sort()\n            .map((frameName) => symbolTextures[frameName]);\n\n        return frames;\n    }\n\n    /**\n     * Gets the force loaded asset that was stored in the forceLoader.resources.\n     * @param id\n     */\n    public getForceLoadedAsset(id: string): any {\n        return this.forceLoader.resources[id];\n    }\n\n    /**\n     *\n     * @param spritesheetId\n     * @param textureId\n     */\n    public getTextureFromSpriteSheet(spritesheetId: string, textureId: string): any {\n        // we put null for main asset ID for multi URLs\n        if (Array.isArray(this.loadedAssets.get(spritesheetId))) {\n            // @ts-ignore\n            return (\n                // @ts-ignore\n                this.loadedAssets\n                    // @ts-ignore\n                    .get(spritesheetId)\n                    // @ts-ignore\n                    .filter((spritesheet) => spritesheet.textures[textureId] !== undefined)[0]?.textures[textureId]\n            );\n        } else {\n            // @ts-ignore\n            return this.loadedAssets.get(spritesheetId).spritesheet.textures[textureId];\n        }\n    }\n\n    public getHTMLSpriteImage(spritesheetId: string, textureId: string): any {\n        if (Array.isArray(this.loadedAssets.get(spritesheetId))) {\n            return (\n                // @ts-ignore\n                this.loadedAssets\n                    // @ts-ignore\n                    .get(spritesheetId)\n                    // @ts-ignore\n                    .filter((spritesheet) => spritesheet.textures[textureId] !== undefined)\n            );\n        } else {\n            // @ts-ignore\n            return this.loadedAssets.get(spritesheetId).textures[textureId];\n        }\n    }\n\n    public async replaceAssets(mode: AssetsReplaceMode = 'all'): Promise<void> {\n        // Only read by initLoader, to cache-bust what the pixi Loader fetches.\n        // A sound-only run replaces nothing that goes through it, so busting\n        // there would re-download every texture for nothing.\n        if (mode !== 'sound') {\n            this.replacedAssets = true;\n        }\n        const assetsToCheck: Array<IAsset> = [];\n\n        this.assetsQueue.forEach((asset) => {\n            // this.checkForDesktopOption(asset);\n            const isSound = asset.type === 'sound';\n            if ((mode === 'sound' && !isSound) || (mode === 'image' && isSound)) {\n                return;\n            }\n            assetsToCheck.push(asset);\n        });\n\n        const replacedAssets = (\n            await Promise.all(assetsToCheck.map((asset) => this.checkAndReplaceAsset(asset)))\n        ).filter(Boolean);\n\n        Log.table(replacedAssets, this.constructor.name);\n    }\n\n    /* private async checkAndReplaceAsset(asset: IAsset): Promise<{ id: string; type: string; url: string } | null> {\n        if (typeof asset.url !== 'string') {\n            // we don't support multi urls for now\n            return null;\n        }\n\n        const targetUrl = (window as any).ssi.CustomResourcesHost;\n        const urlAssetsIndex = asset.url.indexOf('/assets/');\n        const timestamp = Date.now();\n\n        const newUrl: string =\n            targetUrl +\n            asset.url.substring(urlAssetsIndex) +\n            (!asset.url.includes('time=') ? `${!asset.url.includes('?') ? '?' : '&'}time=${timestamp}` : '');\n\n        try {\n            const response = await fetch(newUrl, { method: 'HEAD' });\n\n            if (response.ok) {\n                if (asset.type === 'sound') {\n                    const jsonUrl = newUrl.replace('.mp3', '.json');\n                    const jsonResponse = await fetch(jsonUrl);\n                    if (jsonResponse.ok) {\n                        asset.url = newUrl;\n                        const spriteData = await jsonResponse.json();\n                        // @ts-ignore\n                        asset.sprite = spriteData.sprite;\n                        return { id: asset.id, type: asset.type, url: newUrl };\n                    }\n                } else {\n                    asset.url = newUrl;\n                    return { id: asset.id, type: asset.type, url: newUrl };\n                }\n            }\n        } catch (_err) {\n            // Log.debug('Error for fetching resource', newUrl);\n        }\n        return null;\n    } */\n    private async checkAndReplaceAsset(\n        asset: IAsset,\n    ): Promise<{ id: string; type: string; url: string | string[] } | null> {\n        const targetUrl = (window as any).ssi.CustomResourcesHost;\n        const timestamp = Date.now();\n\n        // Normalize to array\n        const urls = Array.isArray(asset.url) ? asset.url : [asset.url];\n\n        const updatedUrls: string[] = [];\n\n        try {\n            for (const originalUrl of urls) {\n                if (typeof originalUrl !== 'string') {\n                    continue;\n                }\n\n                const urlAssetsIndex = originalUrl.indexOf('/assets/');\n\n                if (urlAssetsIndex === -1) {\n                    continue;\n                }\n\n                const newUrl =\n                    targetUrl +\n                    originalUrl.substring(urlAssetsIndex) +\n                    (!originalUrl.includes('time=')\n                        ? `${!originalUrl.includes('?') ? '?' : '&'}time=${timestamp}`\n                        : '');\n\n                const response = await fetch(newUrl, {\n                    method: 'HEAD',\n                });\n\n                if (!response.ok) {\n                    continue;\n                }\n\n                // Sound handling\n                if (asset.type === 'sound') {\n                    const jsonUrl = newUrl.replace('.mp3', '.json');\n\n                    const jsonResponse = await fetch(jsonUrl);\n\n                    if (!jsonResponse.ok) {\n                        continue;\n                    }\n\n                    const spriteData = await jsonResponse.json();\n\n                    // @ts-ignore\n                    asset.sprite = spriteData.sprite;\n                }\n\n                updatedUrls.push(newUrl);\n            }\n\n            if (updatedUrls.length === 0) {\n                return null;\n            }\n\n            // Restore original structure\n            asset.url = Array.isArray(asset.url) ? updatedUrls : updatedUrls[0];\n\n            return {\n                id: asset.id,\n                type: asset.type,\n                url: asset.url,\n            };\n        } catch (_err) {\n            // Log.debug('Error for fetching resource');\n        }\n\n        return null;\n    }\n\n    private initLoader(): void {\n        if (this.loader) {\n            this.loader.reset();\n            this.loader.destroy();\n        }\n        this.loader = new Loader();\n        this.loader.defaultQueryString = Core.hash + (this.replacedAssets ? '&time=' + Date.now() : '');\n        this.loader.pre(this.svgLoader.bind(this));\n        this.loader.onProgress.add(this.onGenericAssetProgress.bind(this)); // called once per loaded/errored file\n        this.loader.onError.add(this.onGenericAssetError.bind(this)); // called once per errored file\n        this.loader.onLoad.add(this.onGenericAssetLoad.bind(this)); // called once per loaded file\n    }\n    //===============================================================\n\n    private svgLoader(resource, next): void {\n        if (resource.extension !== 'svg') {\n            return next();\n        }\n\n        let pixelRatio = window.devicePixelRatio || 1;\n\n        // Adjust the resolution based on screen size (higher DPI on larger screens)\n        const mode = Core.isDesktopMode ? 'desktop' : 'mobile';\n        const scaleCoef = window.screen.width / Core.display.stage.width;\n        if (scaleCoef > 1) {\n            pixelRatio *= 2;\n        }\n\n        const svgConfig = this.svgMap.get(resource.name)?.config;\n\n        let img = new Image();\n        img.src = resource.url;\n        img.crossOrigin = 'anonymous'; // To handle cross-origin SVG issues\n\n        // Wait until the image is loaded\n        img.onload = () => {\n            if (svgConfig && svgConfig[mode]) {\n                img.width = svgConfig[mode].width;\n                img.height = svgConfig[mode].height;\n            }\n            img.width *= pixelRatio;\n            img.height *= pixelRatio;\n            // Create a high-resolution image resource\n            // Create a Pixi sprite from the image\n            const texture = Texture.from(img, { resolution: pixelRatio });\n\n            // Attach sprite to the resource\n            resource.texture = texture;\n\n            // Mark resource as complete and proceed\n            resource.complete();\n\n            img.remove();\n            // @ts-ignore\n            img = null;\n            next();\n        };\n\n        // Handle image load errors\n        img.onerror = () => {\n            next();\n        };\n    }\n\n    //================================================================\n\n    private initForseLoader(): void {\n        this.forceLoader = new Loader();\n        this.forceLoader.onLoad.add(this.onGenericForceAssetLoad.bind(this)); // called once per loaded file\n        this.forceLoadAssetsQueue = new PriorityQueue<IAsset>((a, b) => a.priority - b.priority);\n    }\n\n    private initLoaders(): void {\n        this.initLoader();\n        this.initForseLoader();\n        this.assetsQueue = new PriorityQueue<IAsset>((a, b) => a.priority - b.priority);\n        this.initLoadingQueue();\n    }\n\n    private initLoadingQueue(): void {\n        this.assetsLoading = {};\n        this.fallbackAssetIds.clear();\n        this.currentPriorityLoading = null;\n        this.genericAssetsToLoad = 0;\n        this.genericAssetsRemaining = 0;\n        this.soundAssetsToLoad = 0;\n        this.soundAssetsRemaining = 0;\n        this.progressPercents = { generic: 0, sound: 0, total: 0 };\n    }\n\n    /**\n     *\n     * @param loader\n     * @param resource\n     */\n    private onGenericAssetProgress(loader: Loader, _resource: LoaderResource): void {\n        // Calculate real percentage (including other loaders)\n        const innerIncrement = loader.progress - this.progressPercents.generic;\n        this.progressPercents.generic = loader.progress;\n        const totalIncrement = (innerIncrement * this.genericAssetsToLoad) / Object.keys(this.assetsLoading).length;\n        this.progressPercents.total += totalIncrement;\n\n        // Core.PRIORITY_GROUP_PROGRESS.next({\n        //     priority: this.currentPriorityLoading,\n        //     progress: this.progressPercents.total,\n        // });\n    }\n\n    /**\n     *\n     * @param error\n     * @param loader\n     * @param resource\n     */\n\n    private onGenericAssetError(error: Error, loader: Loader, resource: LoaderResource): void {\n        const isFallbackResource = this.fallbackAssetIds.has(resource.name);\n        const assetId = this.fallbackAssetIds.get(resource.name) || resource.name;\n        const loadAsset = this.assetsLoading[assetId];\n        const fallbackUrl = loadAsset && this.getFallbackUrl(resource);\n\n        if (loadAsset && !this.fallbackAssetIds.has(resource.name) && fallbackUrl) {\n            const fallbackResourceId = `${resource.name}${this.multiUrlSeparator}fallback`;\n            this.fallbackAssetIds.set(fallbackResourceId, assetId);\n            if (loadAsset.asset.type === 'svg') {\n                this.svgMap.set(fallbackResourceId, loadAsset.asset);\n            }\n            loader.add(fallbackResourceId, fallbackUrl, { parentResource: resource });\n            return;\n        }\n\n        // Some generic resources add other resources to load we don't know about\n        if (loadAsset) {\n            loadAsset.loaded = false;\n            loadAsset.error = error; // resource.error holds the error too\n\n            Core.ASSET_ERROR.next(loadAsset);\n        }\n        if (isFallbackResource) {\n            this.fallbackAssetIds.delete(resource.name);\n            this.svgMap.delete(resource.name);\n        }\n    }\n\n    private getFallbackUrl(resource: LoaderResource): string | undefined {\n        const url = resource.url;\n        const fallbackUrl = url.replace(\n            /((?:\\/translations\\/)|_)([a-z]{2}(?:-[a-z]{2})?)(?=(?:\\.[^./?#]+)?(?:[?#]|$))/i,\n            (_match, prefix) => `${prefix}${Core.translator.defaultLanguage}`,\n        );\n        return fallbackUrl === url ? undefined : fallbackUrl;\n    }\n\n    /***\n     * Return the id of the main asset or '' if there is no one\n     * @param resourceName\n     */\n    private getMainAssetId(resourceName: string): string {\n        return resourceName.substr(0, resourceName.indexOf(this.multiUrlSeparator));\n    }\n\n    /***\n     * Check if passed resource name is part from multipack.\n     * @param resourceName\n     */\n    private isResourcePartFromMultipack(resourceName: string): boolean {\n        const mainAssetId = this.getMainAssetId(resourceName);\n        if (mainAssetId !== '') {\n            return true;\n        }\n        return false;\n    }\n\n    /***\n     * Handle the logic for each part of multipack resource\n     * @param resource\n     */\n    private processPart(resource: LoaderResource): void {\n        const mainAssetId = this.getMainAssetId(resource.name);\n        const loadAsset = this.assetsLoading[mainAssetId];\n        // is this additional resource and not direct asst json (as image from json)\n        const mainAssetIndex = loadAsset.modules.indexOf(resource.name);\n        if (mainAssetIndex !== -1) {\n            // push sub-asset resoutrce to array with resources and remove it from modules\n            const assetResource: any = this.loadedAssets.get(mainAssetId);\n            assetResource.push(resource);\n            loadAsset.modules.splice(mainAssetIndex, 1);\n            if (loadAsset.modules.length === 0) {\n                loadAsset.loaded = true;\n                loadAsset.error = null;\n                // Core.ASSET_LOADED.next(loadAsset);\n                Core.emit(LifeCycle.ON_ASSET_LOADED, loadAsset);\n                utils.clearTextureCache();\n            }\n        }\n    }\n    /**\n     *\n     * @param loader\n     * @param resource\n     */\n    private onGenericAssetLoad(_loader: Loader, resource: LoaderResource): void {\n        const isFallbackResource = this.fallbackAssetIds.has(resource.name);\n        if (!isFallbackResource && this.isResourcePartFromMultipack(resource.name)) {\n            this.processPart(resource);\n        } else {\n            const assetId = this.fallbackAssetIds.get(resource.name) || resource.name;\n            // if(resource.extension === \"json\" && resource?.data?.meta?.image){\n            //     resource.data.meta.image += \"?avs\"\n            //     console.log(resource.data.meta.image)\n            // }\n            const loadAsset = this.assetsLoading[assetId];\n\n            if (this.currentPriorityLoading === AssetPriority.HIGHEST) {\n                const progress: number = this.loadingIndicator.updateProgress(resource.name, this.highPriorityStep);\n                if (this.lastEmitedProgres !== progress) {\n                    this.lastEmitedProgres = progress;\n                    PostMessageDispatcher.gameLoadProgress(progress);\n                }\n            }\n\n            // multipack asset discovered from meta.related_multi_packs - its parts are still loading and\n            // processPart marks it as loaded when the last one arrives\n            if (Array.isArray(this.loadedAssets.get(resource.name))) {\n                return;\n            }\n\n            // Some generic resources add other resources to load we don't know about\n            if (loadAsset) {\n                loadAsset.loaded = true;\n                loadAsset.error = null;\n                this.loadedAssets.set(assetId, resource);\n                // Core.ASSET_LOADED.next(loadAsset);\n                Core.emit(LifeCycle.ON_ASSET_LOADED, loadAsset);\n                utils.clearTextureCache();\n            }\n            if (isFallbackResource) {\n                this.fallbackAssetIds.delete(resource.name);\n                this.svgMap.delete(resource.name);\n            }\n        }\n    }\n\n    private checkForDesktopOption(asset: IAsset | ISoundAsset): void {\n        if (Core.isDesktopMode && asset.hasDesktopVersion) {\n            if (asset.desktopUrl) {\n                asset.url = asset.desktopUrl;\n                return;\n            }\n            const languageTester = `_${Core.translator.currentLanguage}`;\n            const extentionWithLnaguage = new RegExp(languageTester + '.[0-9a-z]+$', 'i');\n            let extension = '';\n            if (asset.url && typeof asset.url === 'string' && asset.url.match(extentionWithLnaguage)) {\n                // @ts-ignore\n                extension = asset.url.match(extentionWithLnaguage)[0];\n            } else {\n                const extentionOnly = new RegExp('.[0-9a-z]+$', 'i');\n\n                if (typeof asset.url === 'string') {\n                    // @ts-ignore\n                    extension = asset.url.match(extentionOnly)[0];\n                } else {\n                    // @ts-ignore\n                    extension = asset.url[0].match(extentionOnly)[0];\n                }\n            }\n            if (Array.isArray(asset.url)) {\n                asset.url.map((el) => {\n                    return (\n                        el.slice(0, el.lastIndexOf(extension)) + (!el.includes('Desktop') ? 'Desktop' : '') + extension\n                    );\n                });\n            } else {\n                asset.url =\n                    asset.url.slice(0, asset.url.lastIndexOf(extension)) +\n                    (!asset.url.includes('Desktop') ? 'Desktop' : '') +\n                    extension;\n            }\n        }\n    }\n\n    /**\n     *\n     * @param loader\n     * @param resource\n     */\n    private onGenericForceAssetLoad(_loader: Loader, resource: LoaderResource): void {\n        Log.debug('Forced assetLoaded', this.constructor.name, resource);\n        this.loadedAssets.set(resource.name, resource);\n        Core.emit(LifeCycle.ON_ASSET_LOADED, {\n            asset: {\n                id: resource.name,\n                type: 'translation',\n            },\n        });\n        utils.clearTextureCache();\n    }\n\n    /**\n     *\n     */\n    private onAllGenericAssetsComplete(): void {\n        // We don't really know how many resources are being loaded because middlewares can add some more to the queue,\n        // so we go down from n resources-to-load to 0 in one step.\n        // See for instance the spine atlas parser middleware: pixi-spine/src/loaders.ts\n        this.genericAssetsRemaining = 0;\n        this.checkAllAssetsLoaded();\n    }\n\n    /**\n     *\n     */\n    private onSoundAssetProgress(): void {\n        this.soundAssetsRemaining--;\n\n        // Calculate real percentage (including other loaders)\n        const innerPercent = ((this.soundAssetsToLoad - this.soundAssetsRemaining) * 100) / this.soundAssetsToLoad;\n        const innerIncrement = innerPercent - this.progressPercents.sound;\n        this.progressPercents.sound = innerPercent;\n        const totalIncrement = (innerIncrement * this.soundAssetsToLoad) / Object.keys(this.assetsLoading).length;\n        this.progressPercents.total += totalIncrement;\n\n        // Core.PRIORITY_GROUP_PROGRESS.next({\n        //     priority: this.currentPriorityLoading,\n        //     progress: this.progressPercents.total,\n        // });\n    }\n\n    /**\n     *\n     * @param asset\n     * @param error\n     */\n    private onSoundAssetError(asset: IAsset, error: Error): void {\n        this.onSoundAssetProgress();\n\n        const loadAsset = this.assetsLoading[asset.id];\n\n        if (loadAsset) {\n            loadAsset.loaded = false;\n            loadAsset.error = error;\n\n            Core.ASSET_ERROR.next(loadAsset);\n        }\n\n        if (this.soundAssetsRemaining <= 0) {\n            this.checkAllAssetsLoaded();\n        }\n    }\n\n    /**\n     *\n     * @param asset\n     */\n    private onSoundAssetLoad(asset: IAsset): void {\n        this.onSoundAssetProgress();\n\n        const loadAsset = this.assetsLoading[asset.id];\n\n        if (loadAsset) {\n            loadAsset.loaded = true;\n            loadAsset.error = null;\n\n            // Core.ASSET_LOADED.next(loadAsset);\n            // Core.sounds.addSound(loadAsset.asset as ISoundAsset);\n            Core.emit(LifeCycle.ON_ASSET_LOADED, loadAsset);\n        }\n\n        if (this.soundAssetsRemaining <= 0) {\n            this.checkAllAssetsLoaded();\n        }\n    }\n\n    /**\n     * Loads all assets with next prioriy on the queue.\n     */\n    private loadNextPriorityGroup(): void {\n        this.initLoadingQueue();\n        this.initLoader();\n\n        const asset = this.assetsQueue.peek();\n\n        if (asset) {\n            this.currentPriorityLoading = asset.priority;\n            this.loadPriorityGroup();\n        } else {\n            // No more assets in the queue, we are done.\n            Core.emit(LifeCycle.ON_ALL_ASSETS_LOADED);\n        }\n    }\n\n    /**\n     * Add all assets with same priority to the loading list and start loading them.\n     */\n    private loadPriorityGroup(): void {\n        while (this.assetsQueue.peek() && this.assetsQueue.peek()!.priority === this.currentPriorityLoading) {\n            const asset = this.assetsQueue.dequeue()!;\n\n            this.assetsLoading[asset.id] = {\n                asset,\n                loaded: false,\n                error: null,\n                modules: [],\n            };\n        }\n\n        this.startLoadingAssets();\n    }\n\n    /**\n     *\n     */\n    private startLoadingAssets(): void {\n        if (this.forceLoadResourcesLoading) {\n            return;\n        }\n        const loadAssets = Object.keys(this.assetsLoading).map((key) => this.assetsLoading[key]);\n\n        loadAssets.forEach((loadAsset) => {\n            if (loadAsset.asset.type === 'sound') {\n                this.soundAssetsToLoad++;\n                this.soundAssetsRemaining++;\n                if (Core.audioEngineType === 'Howler') {\n                    //! lemmy\n                    this.loadSoundAsset(loadAsset.asset as ISoundAsset);\n                } else {\n                    this.loadToneSoundAsset(loadAsset.asset as IToneSoundAsset);\n                    if (Core.customResourcesHost) {\n                        // @ts-ignore\n                        const asset = {} as any;\n                        Object.assign(asset, loadAsset.asset);\n                        asset.url = asset.url.split('.mp3').join('.json');\n                        asset.id += 'Xml';\n                        asset.type = 'MP3JSON';\n                        this.assetsLoading[asset.id] = {\n                            asset,\n                            loaded: false,\n                            error: null,\n                            modules: [],\n                        };\n                        this.genericAssetsToLoad++;\n                        this.addGenericAsset(asset);\n                    }\n                }\n            } else {\n                this.genericAssetsToLoad++;\n                this.addGenericAsset(loadAsset.asset);\n            }\n        });\n\n        // Load generic assets through the loader\n        this.genericAssetsRemaining = this.genericAssetsToLoad;\n        this.loadGenericAssets();\n    }\n    public async loadToneSoundAsset(asset: IToneSoundAsset): Promise<void> {\n        try {\n            const buffer = (await ToneAudioBuffer.load(asset.url as string)) as AudioBuffer;\n            asset.buffer = buffer;\n            asset.players = {};\n            Core.sounds.addSound(asset as IToneSoundAsset);\n            this.onSoundAssetLoad(asset);\n        } catch (error) {\n            const loadError = error instanceof Error ? error : new Error(`Error loading sound ${asset.id}`);\n            this.onSoundAssetError(asset, loadError);\n        }\n    }\n\n    /**\n     *\n     * @param asset\n     */\n    private loadSoundAsset(asset: ISoundAsset): void {\n        asset.howl = new Howl({\n            src: [asset.url],\n            autoplay: asset.autoplay,\n            loop: asset.loop || false,\n            volume: asset.volume || 1,\n            mute: asset.mute || false,\n            rate: asset.rate || 1,\n            html5: asset.html5 || false,\n            sprite: asset.sprite,\n            onload: this.onSoundAssetLoad.bind(this, asset),\n            onloaderror: (_soundId: number, error: any) => {\n                const loadError = error instanceof Error ? error : new Error(`Error loading sound ${asset.id}`);\n                this.onSoundAssetError(asset, loadError);\n            },\n        });\n        Core.sounds.addSound(asset as ISoundAsset);\n    }\n\n    /**\n     *\n     * @param asset\n     */\n    private addGenericAsset(asset: IAsset): void {\n        if (!this.loadedAssets.has(asset.id)) {\n            if (Array.isArray(asset.url)) {\n                this.addGenericAssetMultiURL(asset);\n            } else {\n                this.loader.add(asset.id, asset.url);\n                // A multipack asset can declare only its first pack - the rest are taken from\n                // meta.related_multi_packs of that pack. It has to be on onComplete, because the PIXI\n                // spritesheet middleware reads the same field right after and loads them on its own.\n                // IMPORTANT: LETS DO THIS ONLY IN DEV MODE\n                if (Core.devTools) {\n                    this.loader.resources[asset.id].onComplete.add((resource: LoaderResource) => {\n                        this.discoverMultipackParts(asset, resource);\n                    });\n                }\n            }\n        }\n    }\n\n    /**\n     * Used for multi URL assets because we can not add under one key\n     * @param asset\n     */\n    private addGenericAssetMultiURL(asset: IAsset): void {\n        // if is multi - we put main key and load all of URLs\n        this.assetsLoading[asset.id] = {\n            asset,\n            loaded: false,\n            error: null,\n            modules: [],\n        };\n        this.loadedAssets.set(asset.id, []);\n        let ind: number = 0;\n        (asset.url as []).forEach((url) => {\n            // to the id add _____ in order easy to recognize parts of multi assets\n            const id: string = asset.id + this.multiUrlSeparator + ind.toString();\n            this.loader.add(id, url);\n            // ==== Skip standart PIXI way of loading multipack assets =====\n            // this is from last/new PIXI 6 version where multipack assets are auto loaded\n            this.loader.resources[id].onComplete.add((r) => {\n                r.data.meta.related_multi_packs = [];\n                this.loader.resources[id].onComplete.detachAll();\n            });\n            this.assetsLoading[asset.id].modules.push(id);\n            ind++;\n        });\n    }\n\n    /**\n     * Loads the remaining packs of a multipack asset which has only its first pack declared in the game\n     * configuration. They are taken from meta.related_multi_packs of the declared pack.\n     * @param asset\n     * @param entry - the resource of the declared pack\n     */\n    private discoverMultipackParts(asset: IAsset, entry: LoaderResource): void {\n        const relatedPacks = entry.data?.meta?.related_multi_packs;\n        if (!Array.isArray(relatedPacks) || relatedPacks.length === 0) {\n            return;\n        }\n        // ==== Skip standart PIXI way of loading multipack assets =====\n        entry.data.meta.related_multi_packs = [];\n\n        const loadAsset = this.assetsLoading[asset.id];\n        const declaredUrl = asset.url as string;\n        const partUrls = this.resolveRelatedPackUrls(declaredUrl, relatedPacks);\n        if (!loadAsset || partUrls.length === 0) {\n            return;\n        }\n\n        Log.debug(`Multipack parts discovered for ${asset.id}`, this.constructor.name, partUrls);\n        // the declared pack is the first one in the array, the rest are added by processPart\n        const assetResource: any = [entry];\n        this.loadedAssets.set(asset.id, assetResource);\n        // the asset is a multipack one as if it was declared with all of its urls - the views wait for the\n        // videos to load by comparing the number of loaded packs with the number of urls of the asset\n        asset.url = [declaredUrl, ...partUrls];\n\n        partUrls.forEach((url, index) => {\n            // to the id add _____ in order easy to recognize parts of multi assets\n            const id: string = asset.id + this.multiUrlSeparator + (index + 1).toString();\n            loadAsset.modules.push(id);\n            // parentResource is mandatory - PIXI does not allow adding resources to a running loader without it\n            this.loader.add(id, url, { parentResource: entry });\n            this.loader.resources[id].onComplete.add((partResource: LoaderResource) => {\n                // ==== Skip standart PIXI way of loading multipack assets =====\n                // every pack lists all of its siblings, so the parts point back to the loaded ones\n                if (partResource.data?.meta) {\n                    partResource.data.meta.related_multi_packs = [];\n                }\n            });\n        });\n    }\n\n    /**\n     * Resolves related pack file names against the url of the declared pack. Its query string is kept - it\n     * holds the cache busting parameters of the replaced assets.\n     * @param declaredUrl\n     * @param relatedPacks\n     */\n    private resolveRelatedPackUrls(declaredUrl: string, relatedPacks: string[]): string[] {\n        const [entryPath, query] = declaredUrl.split('?');\n        const separatorIndex = entryPath.lastIndexOf('/') + 1;\n        const directory = entryPath.slice(0, separatorIndex);\n        const entryFile = entryPath.slice(separatorIndex);\n        const urls: string[] = [];\n\n        relatedPacks.forEach((pack) => {\n            // packs list all of their siblings - the already loaded one has to be skipped\n            if (typeof pack !== 'string' || pack === entryFile) {\n                return;\n            }\n            const url = directory + pack + (query ? `?${query}` : '');\n            if (!urls.includes(url)) {\n                urls.push(url);\n            }\n        });\n\n        return urls;\n    }\n\n    /**\n     *\n     */\n    private loadGenericAssets(): void {\n        if (this.genericAssetsToLoad > 0) {\n            this.loader.load(this.onAllGenericAssetsComplete.bind(this));\n        } else {\n            this.checkAllAssetsLoaded();\n        }\n    }\n\n    /**\n     *\n     */\n    private checkAllAssetsLoaded(): void {\n        if (this.genericAssetsRemaining + this.soundAssetsRemaining <= 0) {\n            // Notify priority group loaded\n            Core.emit(LifeCycle.ON_PRIORITY_GROUP_LOADED, {\n                priority: this.currentPriorityLoading,\n                assets: Object.keys(this.assetsLoading)\n                    .map((key) => this.assetsLoading[key])\n                    .filter((loadAsset) => loadAsset.loaded),\n            });\n            if (this.currentPriorityLoading === AssetPriority.HIGHEST) {\n                Core.emit(LifeCycle.ON_HIGHEST_PRIORITY_GROUP_LOADED, {\n                    priority: this.currentPriorityLoading,\n                    assets: Object.keys(this.assetsLoading)\n                        .map((key) => this.assetsLoading[key])\n                        .filter((loadAsset) => loadAsset.loaded),\n                });\n                Core.emit(LifeCycle.ON_START_GAME);\n\n                Logger.closeGroup(Logger.getLastGroupName());\n                Logger.openGroup(LoggerGroups.IDLE);\n\n                // to be uncomened if next POC is approved\n                // https://jira.egt-digital.com/browse/ON-6367\n                // if (Core.configuration.gameKey !== '') {\n                this.loadingIndicator.finish();\n                PostMessageDispatcher.gameLoadComplete();\n                // }\n            }\n\n            // Load next priority group\n            this.loadNextPriorityGroup();\n        }\n    }\n}\n","import { BehaviorSubject } from 'rxjs';\n\nimport { DependencyContainer } from 'tsyringe';\nimport { Logger } from 'unicorn.console-logger';\nimport Core, { IBaseModeFactory, IForceSetConfig, IModeConfig, IModes } from './Core';\nimport BaseComponents from './enums/BaseComponents';\nimport { ILifeCycle } from './interfaces/ILifeCycle';\ntype ModeFactoryCtor<TModeConfig> = new (modeType: any, force: IForceSetConfig) => TModeConfig;\n\nexport default class BaseComponent implements ILifeCycle {\n    public componentName: string = '';\n    public componentType: any = BaseComponents.NONE;\n    // name of the override configuration if needed\n    public configurationName = '';\n\n    protected mainAssetID: string | string[];\n    protected readonly ASSETS_LOADED: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    protected dependencyContainer: DependencyContainer;\n\n    protected modeFactory: IBaseModeFactory;\n    protected mode: IModes;\n\n    constructor() {\n        Logger.logViewMessage(`constructor()`, this.constructor.name);\n    }\n\n    protected initMode<TModeConfig>(\n        modeConfig: IModeConfig,\n        opts: {\n            defaultModeType: any;\n            baseConfigs: Record<any, any>;\n            defaultFactory: ModeFactoryCtor<TModeConfig>;\n        },\n    ): TModeConfig {\n        // 1) resolve forced mode\n        const modeType = modeConfig.forceMode ?? modeConfig.modeType ?? opts.defaultModeType;\n\n        // 2) pick factory\n        const FactoryClass = (modeConfig.modeFactory as ModeFactoryCtor<TModeConfig>) ?? opts.defaultFactory;\n\n        // 3) force config obj\n        const forceConfigObject: IForceSetConfig = {\n            configObj: modeConfig?.configuration?.[modeType]\n                ? {\n                      config: modeConfig.configuration[modeType],\n                      basConfig: opts.baseConfigs[modeType],\n                  }\n                : undefined,\n            view: modeConfig?.view?.[modeType],\n            desktopView: modeConfig?.desktopView?.[modeType],\n            secondView: modeConfig?.secondView?.[modeType],\n            controller: modeConfig?.controller?.[modeType],\n            desktopController: modeConfig?.desktopController?.[modeType],\n            secondController: modeConfig?.secondController?.[modeType],\n        };\n\n        // 4) create mode config\n        const created = new FactoryClass(modeType, forceConfigObject);\n\n        this.modeFactory = created as IBaseModeFactory;\n        this.mode = (created as any).mode;\n\n        return created;\n    }\n\n    public onBeforeDestroy(): void {\n        // Here we will make actions before all objects and game will be destroyed;\n    }\n\n    public destroy(): void {\n        // implement\n        this.ASSETS_LOADED.complete();\n        // @ts-ignore\n        this.ASSETS_LOADED = null;\n\n        if (this.dependencyContainer) {\n            // @ts-ignore\n            this.dependencyContainer = null;\n        }\n        // @ts-ignore\n        this.componentName = null;\n\n        // @ts-ignore\n        this.componentType = null;\n        // @ts-ignore\n        this.mainAssetID = null;\n\n        // Log.debug('BaseComponent DESTORY-', this);\n    }\n\n    public onCreateFeatureFlags(_loadGameResponse: any): void {\n        // implement only if need\n    }\n\n    public onCreateGameTemplate(_loadGameResponse: any): void {\n        // implement only if need\n    }\n\n    public onBeforeInit(): Promise<void> {\n        throw new Error('Method not implemented.');\n    }\n\n    public onAllAssetsLoaded(): void {\n        // implement\n    }\n\n    public onAfterGameConfigurationCreated(): void {\n        // Log.debug(\"onGameConfigurationCreated\", e);\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onHighestPriorityGroupLoaded(group: any): void {\n        // implement\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onBeforeStartLoadingResources(asset: any): void {\n        // implement\n    }\n\n    public onGameConfigurationCreated(): void {\n        // implement\n    }\n\n    public onIndividualAssetLoaded(asset: any): void {\n        if (this.mainAssetID) {\n            if (Array.isArray(this.mainAssetID)) {\n                const assetIndex = this.mainAssetID.indexOf(asset.asset.id);\n                if (assetIndex > -1) {\n                    this.mainAssetID.splice(assetIndex, 1);\n                    if (this.mainAssetID.length === 0) {\n                        this.ASSETS_LOADED.next(true);\n                    }\n                }\n            } else {\n                if (asset.asset.id === this.mainAssetID) {\n                    this.ASSETS_LOADED.next(true);\n                }\n            }\n        }\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onGameSettings(gameSettings: any): void {\n        // implement\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onInitialRender(container: any): void {\n        // implement\n        Logger.logViewMessage(`onInitialRender()`, this.constructor.name);\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onAfterInitialRender(container: any): void {\n        // implement\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onPrepareResources(container: any): void {\n        // implement\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onPriorityGroupLoaded(group: any): void {\n        // implement\n    }\n\n    public onRegisterDependencies(container: any): void {\n        // implement\n        this.dependencyContainer = container;\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onRegisterMobileDependencies(container: any): void {\n        // imlement\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onRegisterDesktopDependencies(container: any): void {\n        // imlement\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onBeforeResolveDependencies(container: any): void {\n        // implement\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onResolveDependencies(container: any): void {\n        // implement\n        // this.rv = this.dependencyContainer.resolve('RootView');\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onInit(view: any): void {\n        // it does nothing\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onInitComplete(view: any): void {\n        // it does nothing\n    }\n\n    public onGameStarted(): void {\n        // implement\n    }\n\n    protected ready(): Promise<void> {\n        return new Promise((resolve) => {\n            if (Core.ON_GAME_PAUSED.value === 'NONE') {\n                if (this.ASSETS_LOADED.value || this.mainAssetID === undefined) {\n                    resolve();\n                } else {\n                    Core.LOADING_ASSETS.next(true);\n                    const subscription = this.ASSETS_LOADED.subscribe((value) => {\n                        if (value) {\n                            subscription.unsubscribe();\n                            Core.LOADING_ASSETS.next(false);\n                            resolve();\n                        }\n                    });\n                }\n            } else {\n                const subscription = Core.ON_GAME_PAUSED.subscribe((value) => {\n                    if (value === 'NONE') {\n                        subscription.unsubscribe();\n                        if (this.ASSETS_LOADED.value || this.mainAssetID === undefined) {\n                            resolve();\n                        } else {\n                            Core.LOADING_ASSETS.next(true);\n                            const subscription2 = this.ASSETS_LOADED.subscribe((value2) => {\n                                if (value2) {\n                                    subscription2.unsubscribe();\n                                    Core.LOADING_ASSETS.next(false);\n                                    resolve();\n                                }\n                            });\n                        }\n                    }\n                });\n            }\n        });\n    }\n}\n","import { getInheritanceLevel } from '@egt/ui-lib';\n\nexport default class BaseComponentConfiguration {\n    public destroy(): void {\n        const level = getInheritanceLevel(this.constructor);\n        // @ts-ignore\n        if (this.constructor.__decoratorProperties) {\n            // @ts-ignore\n            for (const propertyKey of this.constructor.__decoratorProperties) {\n                let proto = this.constructor.prototype;\n                for (let i = 0; i <= level; i++) {\n                    if (proto[propertyKey]) {\n                        if (proto[propertyKey].subjects) {\n                            delete proto[propertyKey].subjects;\n                        }\n                        delete proto[propertyKey];\n                    }\n                    proto = Object.getPrototypeOf(proto);\n                }\n            }\n            // @ts-ignore\n            this.constructor.__decoratorProperties = [];\n        }\n    }\n}\n","import { Subject } from 'rxjs';\nimport { IView } from './interfaces/IView';\nimport { IBaseComponentController } from './IBaseComponentController';\n\n// @injectable()\nexport default class BaseController implements IBaseComponentController {\n    protected DESTROY: Subject<void> = new Subject<void>();\n\n    // private destroySubscription: Subscription;\n\n    constructor(protected _views: IView | IView[] | undefined) {\n        // if (_views) {\n        //     // Check for multiple views.\n        //     if (Array.isArray(_views)) {\n        //         this.destroySubscription = forkJoin(_views.map(v => v.DESTROY)).subscribe(() => {\n        //             this.destroy();\n        //         });\n        //     } else {\n        //         this.destroySubscription = (this._views as IView).DESTROY.subscribe(() => {\n        //             this.destroy();\n        //         });\n        //     }\n        // }\n    }\n\n    public init(): void {\n        // implement\n    }\n\n    public onGameStarted(_initialSettings?: any): void {\n        // implement\n    }\n\n    public onAfterInitialRender(): void {\n        // implement\n    }\n\n    public destroy(): void {\n        // Core.createdControllers.splice(Core.createdControllers.indexOf(this), 1);\n        // if (this.destroySubscription) {\n        //     this.destroySubscription.unsubscribe();\n        // }\n\n        this.DESTROY.next();\n        this.DESTROY.complete();\n\n        if (this._views) {\n            // Check for multiple views.\n            if (Array.isArray(this._views)) {\n                this._views.forEach((view) => {\n                    view.destroy();\n                });\n            } else {\n                this._views.destroy();\n            }\n        }\n\n        Object.keys(this).forEach((key: string) => {\n            if (this[key]) {\n                this[key] = null;\n            }\n        });\n        // @ts-ignore\n        this._views = null;\n        // delete this._views;\n        // Log.debug('BaseController DESTORY-', this);\n    }\n}\n","import { BehaviorSubject } from 'rxjs';\n\nimport { DependencyContainer } from 'tsyringe';\nimport Core, { BaseFeatures, IBaseModeFactory, IForceSetConfig, IModeConfig, IModes } from './Core';\nimport { ILifeCycle } from './interfaces/ILifeCycle';\nimport { Logger } from 'unicorn.console-logger';\ntype ModeFactoryCtor<TModeConfig> = new (modeType: any, force: IForceSetConfig) => TModeConfig;\n\nexport default class BaseFeature implements ILifeCycle {\n    public features: BaseFeature[] = [];\n    public featureType: any = BaseFeatures.NONE;\n    public featureName: string = '';\n    // name of the override configuration if needed\n    public configurationName = '';\n    protected mainAssetID: string | string[];\n    protected showLoadingScreen: boolean = true;\n    protected readonly ASSETS_LOADED: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    protected dependencyContainer: DependencyContainer;\n\n    protected modeFactory: IBaseModeFactory;\n    protected mode: IModes;\n\n    constructor() {\n        Logger.logViewMessage(`constructor()`, this.constructor.name);\n    }\n\n    protected initMode<TModeConfig>(\n        modeConfig: IModeConfig,\n        opts: {\n            defaultModeType: any;\n            baseConfigs: Record<any, any>;\n            defaultFactory: ModeFactoryCtor<TModeConfig>;\n        },\n    ): TModeConfig {\n        // 1) resolve forced mode\n        const modeType = modeConfig.forceMode ?? modeConfig.modeType ?? opts.defaultModeType;\n\n        // 2) pick factory\n        const FactoryClass = (modeConfig.modeFactory as ModeFactoryCtor<TModeConfig>) ?? opts.defaultFactory;\n\n        // 3) force config obj\n        const forceConfigObject: IForceSetConfig = {\n            configObj: modeConfig?.configuration?.[modeType]\n                ? {\n                      config: modeConfig.configuration[modeType],\n                      basConfig: opts.baseConfigs[modeType],\n                  }\n                : undefined,\n            view: modeConfig?.view?.[modeType],\n            desktopView: modeConfig?.desktopView?.[modeType],\n            secondView: modeConfig?.secondView?.[modeType],\n            controller: modeConfig?.controller?.[modeType],\n            desktopController: modeConfig?.desktopController?.[modeType],\n            secondController: modeConfig?.secondController?.[modeType],\n        };\n\n        // 4) create mode config\n        const created = new FactoryClass(modeType, forceConfigObject);\n\n        this.modeFactory = created as IBaseModeFactory;\n        this.mode = (created as any).mode;\n\n        return created;\n    }\n\n    public onBeforeDestroy(): void {\n        // Here we will make actions before all objects and game will be destroyed;\n    }\n\n    public destroy(): void {\n        // implement\n        this.features = [];\n        this.ASSETS_LOADED.complete();\n        // @ts-ignore\n        this.ASSETS_LOADED = null;\n        // @ts-ignore\n        this.mainAssetID = null;\n        // @ts-ignore\n        this.features = null;\n        // @ts-ignore\n        this.featureType = null;\n        // @ts-ignore\n        this.featureName = null;\n        // @ts-ignore\n        this.configurationName = null;\n        // @ts-ignore\n        this.dependencyContainer = null;\n\n        // Log.debug('BaseFeature DESTORY-', this);\n    }\n\n    public onBeforeInit(): Promise<void> {\n        throw new Error('Method not implemented.');\n    }\n\n    public onAllAssetsLoaded(): void {\n        // implement\n    }\n\n    public onCreateFeatureFlags(_loadGameResponse: any): void {\n        // implement only if need\n    }\n\n    public onCreateGameTemplate(_loadGameResponse: any): void {\n        // implement only if need\n    }\n\n    public onAfterGameConfigurationCreated(): void {\n        // Log.debug(\"onGameConfigurationCreated\", e);\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onHighestPriorityGroupLoaded(group: any): void {\n        // implement\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onBeforeStartLoadingResources(asset: any): void {\n        // implement\n    }\n\n    public onGameConfigurationCreated(): void {\n        // implement\n    }\n\n    public onIndividualAssetLoaded(asset: any): void {\n        if (this.mainAssetID) {\n            if (Array.isArray(this.mainAssetID)) {\n                const assetIndex = this.mainAssetID.indexOf(asset.asset.id);\n                if (assetIndex > -1) {\n                    this.mainAssetID.splice(assetIndex, 1);\n                    if (this.mainAssetID.length === 0) {\n                        this.ASSETS_LOADED.next(true);\n                    }\n                }\n            } else {\n                if (asset.asset.id === this.mainAssetID) {\n                    this.ASSETS_LOADED.next(true);\n                }\n            }\n        }\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onGameSettings(gameSettings: any): void {\n        // implement\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onInitialRender(container: any): void {\n        // implement\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onAfterInitialRender(container: any): void {\n        // implement\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onPrepareResources(container: any): void {\n        // implement\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onPriorityGroupLoaded(group: any): void {\n        // implement\n    }\n\n    public onRegisterDependencies(container: any): void {\n        // implement\n        this.dependencyContainer = container;\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onRegisterMobileDependencies(container: any): void {\n        // imlement\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onRegisterDesktopDependencies(container: any): void {\n        // imlement\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onBeforeResolveDependencies(container: any): void {\n        // implement\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onResolveDependencies(container: any): void {\n        // implement\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onInit(view: any): void {\n        // it does nothing\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onInitComplete(view: any): void {\n        // it does nothing\n    }\n\n    public onGameStarted(): void {\n        // implement\n    }\n\n    protected ready(): Promise<void> {\n        return new Promise((resolve) => {\n            if (Core.ON_GAME_PAUSED.value === 'NONE' || Core.ON_GAME_PAUSED.value === this.featureType) {\n                if (this.ASSETS_LOADED.value || this.mainAssetID === undefined) {\n                    resolve();\n                } else {\n                    if (this.showLoadingScreen) {\n                        Core.LOADING_ASSETS.next(true);\n                    }\n\n                    const subscription = this.ASSETS_LOADED.subscribe((value) => {\n                        if (value) {\n                            subscription.unsubscribe();\n                            Core.LOADING_ASSETS.next(false);\n                            resolve();\n                        }\n                    });\n                }\n            } else {\n                const subscription = Core.ON_GAME_PAUSED.subscribe((value) => {\n                    if (value === 'NONE' || value === this.featureType) {\n                        subscription.unsubscribe();\n                        if (this.ASSETS_LOADED.value || this.mainAssetID === undefined) {\n                            resolve();\n                        } else {\n                            if (this.showLoadingScreen) {\n                                Core.LOADING_ASSETS.next(true);\n                            }\n                            const subscription2 = this.ASSETS_LOADED.subscribe((value2) => {\n                                if (value2) {\n                                    subscription2.unsubscribe();\n                                    Core.LOADING_ASSETS.next(false);\n                                    resolve();\n                                }\n                            });\n                        }\n                    }\n                });\n            }\n        });\n    }\n}\n","import { Container } from 'pixi.js';\nimport { DependencyContainer, injectable } from 'tsyringe';\nimport PriorityQueue from 'typescript-collections/dist/lib/PriorityQueue';\nimport BaseComponent from './BaseComponent';\nimport BaseFeature from './BaseFeature';\nimport BaseTemplate from './BaseTemplate';\nimport Core, { Align, AnalyticsDispatcher, GameTypes, IAsset, Language, LifeCycle, Scale } from './Core';\nimport { IBaseConfiguration } from './IBaseConfiguration';\nimport { ILifeCycle } from './interfaces/ILifeCycle';\nimport { Logger } from 'unicorn.console-logger';\nimport { logGameComponents } from './utils/GameComponentsLogger';\n\n@injectable()\nexport default class BaseGame implements ILifeCycle {\n    public features: BaseFeature[] = [];\n    public components: BaseComponent[] = [];\n    public featuresPriority: any = {};\n    public gameTemplate: BaseTemplate;\n    public gameType: GameTypes = GameTypes.BASE_GAME;\n    public componentModes: Map<string, string> = new Map();\n    public featureModes: Map<string, string> = new Map();\n    public supportedLayouts: string[];\n\n    protected _layout: string;\n    protected dependencyContainer: DependencyContainer;\n    protected gameSettings: any;\n    protected gameContainer: Container;\n    protected configuration: IBaseConfiguration = {\n        supportedLanguages: [Language.EN],\n        componentsConfiguration: [],\n        stageOptions: {\n            width: 1360,\n            height: 765,\n            scale: Scale.KEEP_ASPECT_RATIO,\n            align: Align.MIDDLE,\n            resolution: window.devicePixelRatio,\n            backgroundAlpha: 0,\n            backgroundColor: 0x000000,\n            changeOrientation: true,\n            antialias: false,\n        },\n    };\n\n    public hasFeature(_feature: any, _mode?: any): boolean {\n        return false;\n    }\n    public hasComponent(_component: any, _mode?: any): boolean {\n        return false;\n    }\n\n    public get gameLayout(): string {\n        return this._layout;\n    }\n\n    public set gameLayout(value: string) {\n        this._layout = value;\n    }\n\n    public onCreateFeatureFlags(_loadGameResponse: any): void {\n        // implement for any game type\n        // first flags are create by default value then game override default value and finally flags are override by URL params\n        // the methods are called in this order - 1. onCreateFeatureFlags, 2. onOverrideFeatureFlagsByGame, 3. onOverrideFeatureFlagsByURL\n    }\n\n    public getExternalFeatures(): any[] {\n        return [];\n    }\n\n    public getGameFeatures(): any[] {\n        return [];\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public getGameComponents(response?: any): any[] {\n        return [];\n    }\n\n    public onCreateGameTemplate(_loadGameResponse: any, _templateOverrides?: any, _layout?: any): void {\n        // Log.debug(\"onCreateGameTemplate\");\n        Logger.logServiceMessage([`onCreateGameTemplate() ILifeCycle`], this.constructor.name, 'log');\n    }\n\n    public externalFeaturesAdded(): void {\n        // Log.debug(\"onCreateGameTemplate\");\n        Logger.logServiceMessage([`externalFeaturesAdded() ILifeCycle`], this.constructor.name, 'log');\n    }\n\n    public onAllAssetsLoaded(): void {\n        // Log.debug(\"onAllAssetsLoaded\");\n        Logger.logServiceMessage([`onAllAssetsLoaded() ILifeCycle`], this.constructor.name, 'log');\n    }\n\n    public onBeforeStartLoadingResources(assets: PriorityQueue<IAsset>): void {\n        // Log.debug(\"onBeforeStartLoadingResources\");\n        Logger.logServiceMessage([`onBeforeStartLoadingResources() ILifeCycle`, assets], this.constructor.name, 'log');\n    }\n\n    public onBeforeInit(): void {\n        // Here we register features;\n        Logger.logServiceMessage([`onBeforeInit() ILifeCycle`], this.constructor.name, 'log');\n    }\n\n    public getFeature(typeOfFeature: any): any {\n        for (const feat of this.features) {\n            if (feat.featureType === typeOfFeature) {\n                return feat;\n            }\n        }\n        return null;\n    }\n\n    public getComponent(typeOfComponent: any): any {\n        for (const comp of this.components) {\n            if (comp.componentType === typeOfComponent) {\n                return comp;\n            }\n        }\n        return null;\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onHighestPriorityGroupLoaded(group: any): void {\n        Logger.logServiceMessage([`onHighestPriorityGroupLoaded() ILifeCycle`], this.constructor.name, 'log');\n        Core.emit(LifeCycle.ON_RESOLVE_DEPENDENCIES, this.dependencyContainer);\n\n        AnalyticsDispatcher.gameStart();\n\n        // Core.ATTACH_SUBSCRIPTIONS.next();\n        // Core.ATTACH_SUBSCRIPTIONS.complete();\n        this.startGame();\n\n        // moved to Assets loader in order to dispatch event to all modules and only after that to dispatch START GAME\n        // Core.emit(LifeCycle.ON_START_GAME);\n    }\n\n    public onGameConfigurationCreated(): void {\n        Logger.logServiceMessage([`onGameConfigurationCreated() ILifeCycle`], this.constructor.name, 'log');\n        // Log.debug(\"onGameConfigurationCreated\", e);\n        Core.initStage(this.configuration.stageOptions);\n    }\n\n    public onAfterGameConfigurationCreated(): void {\n        if (!Core.configuration.devTools && Core.localStorage.readSetting(Core.configuration.gameKey) !== null) {\n            Core.localStorage.removeSetting(Core.configuration.gameKey);\n        }\n        // Log.debug(\"onAfterGameConfigurationCreated\", e);\n        Logger.logServiceMessage([`onAfterGameConfigurationCreated() ILifeCycle`], this.constructor.name, 'log');\n    }\n\n    public onPriorityGroupLoaded(e): void {\n        // Log.debug(\"BASE GAME PRIOROTY GROUP\", e);\n        Logger.logServiceMessage([`onPriorityGroupLoaded() ILifeCycle`, e], this.constructor.name, 'log');\n    }\n\n    public onRegisterMobileDependencies(container: any): void {\n        // Log.debug(\"onRegisterMobileDependencies\", e);\n        Logger.logServiceMessage(\n            [`onRegisterMobileDependencies() ILifeCycle`, container],\n            this.constructor.name,\n            'log',\n        );\n    }\n\n    public onRegisterDesktopDependencies(container: any): void {\n        // Log.debug(\"onRegisterMobileDependencies\", e);\n        Logger.logServiceMessage(\n            [`onRegisterDesktopDependencies() ILifeCycle`, container],\n            this.constructor.name,\n            'log',\n        );\n    }\n\n    public onGameSettings(gameSettings: any): void {\n        this.gameSettings = gameSettings;\n        Logger.logServiceMessage([`onGameSettings() ILifeCycle`, gameSettings], this.constructor.name, 'log');\n    }\n\n    public onIndividualAssetLoaded(e): void {\n        // TODO:refactor this and think about another way to identify the translation assets\n        if (e.asset.type === 'translation') {\n            const assetUrl = e.asset.url || '';\n            const assetLanguageFromUrl = assetUrl.match(/\\/translations\\/([^./?#]+)(?:\\.[^/?#]+)?(?:[?#].*)?$/i)?.[1];\n            const assetLanguage = (assetLanguageFromUrl || '').toLowerCase();\n            const language = this.configuration.supportedLanguages.includes(assetLanguage)\n                ? assetLanguage\n                : Core.translator.defaultLanguage;\n            const currentLanguage = Core.translator.currentLanguage;\n            Core.translator.addKeysTo(language, Core.assets.getAsset(e.asset.id).data);\n            Core.translator.currentLanguage = currentLanguage;\n        } else if (e.asset.type === 'configuration') {\n            Core.configuration.external[e.asset.id] = Core.assets.getAsset(e.asset.id).data;\n        }\n    }\n\n    public onBeforeDestroy(): void {\n        // Here we will make actions before all objects and game will be destroyed;\n        Logger.logServiceMessage([`onBeforeDestroy() ILifeCycle`], this.constructor.name, 'log');\n    }\n\n    public destroy(): void {\n        Logger.logServiceMessage([`destroy() ILifeCycle`], this.constructor.name, 'log');\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        this.features.forEach((f) => {\n            // @ts-ignore\n            f = null;\n        });\n        this.features = [];\n        // @ts-ignore\n        this.features = null;\n\n        this.components = [];\n        // @ts-ignore\n        this.components = null;\n        // @ts-ignore\n        this.features = null;\n        // @ts-ignore\n        this.dependencyContainer = null;\n        // @ts-ignore\n        this.gameSettings = null;\n        // @ts-ignore\n        this.gameContainer = null;\n        // @ts-ignore\n        this.featuresPriority = null;\n        // @ts-ignore\n        this.configuration = null;\n\n        this.gameTemplate.destroy();\n        // @ts-ignore\n        this.gameTemplate = null;\n\n        Object.keys(this).forEach((key: string) => {\n            if (this[key]) {\n                this[key] = null;\n            }\n        });\n\n        // Log.debug('BaseGame DESTORY-', this);\n    }\n\n    public onInitialRender(view: any): void {\n        // it does nothing\n        Logger.logServiceMessage([`onInitialRender() ILifeCycle`, view], this.constructor.name, 'log');\n    }\n\n    public onInit(view: any): void {\n        // it does nothing\n        Logger.logServiceMessage([`onInit() ILifeCycle`, view], this.constructor.name, 'log');\n    }\n\n    public onInitComplete(view: any): void {\n        // it does nothing\n        Logger.logServiceMessage([`onInitComplete() ILifeCycle`, view], this.constructor.name, 'log');\n    }\n\n    public onAfterInitialRender(view: any): void {\n        // it does nothing\n        Logger.logServiceMessage([`onAfterInitialRender() ILifeCycle`, view], this.constructor.name, 'log');\n    }\n    public onRegisterDependencies(dependencyContainer: DependencyContainer): void {\n        this.dependencyContainer = dependencyContainer;\n        // To be implemented by child classes.\n        Logger.logServiceMessage(\n            [`onRegisterDependencies() ILifeCycle`, dependencyContainer],\n            this.constructor.name,\n            'log',\n        );\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onBeforeResolveDependencies(dependencyContainer: DependencyContainer): void {\n        // To be implemented by child classes.\n        Logger.logServiceMessage([`onBeforeResolveDependencies() ILifeCycle`], this.constructor.name, 'log');\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public onResolveDependencies(dependencyContainer: DependencyContainer): void {\n        // To be implemented by child classes.\n        Logger.logServiceMessage([`onResolveDependencies() ILifeCycle`], this.constructor.name, 'log');\n    }\n\n    public onPrepareResources(rootView: Container): void {\n        Logger.logServiceMessage([`onPrepareResources() ILifeCycle`, rootView], this.constructor.name, 'log');\n        // Log.debug('----------------- loading base game resources');\n        this.gameContainer = rootView;\n        // Core.assets.addAsset(Core.translator.getAssetFor(Core.translator.currentLanguage.toLowerCase()));\n        Core.assets.addAsset(Core.translator.getModuleAssetFor('_' + Core.translator.currentLanguage.toLowerCase()));\n        if (Core.translator.currentLanguage !== Core.translator.defaultLanguage) {\n            Core.assets.addAsset(Core.translator.getModuleAssetFor('_' + Core.translator.defaultLanguage));\n        }\n    }\n\n    public onGameStarted(): void {\n        // to be implemented\n        Logger.logServiceMessage([`onGameStarted() ILifeCycle`], this.constructor.name, 'log');\n        if (Core.configuration.devTools) {\n            logGameComponents();\n        }\n    }\n\n    protected startGame(): void {\n        // it does nothing\n        Logger.logServiceMessage([`startGame() ILifeCycle`], this.constructor.name, 'log');\n    }\n}\n","import { IAsset, ISoundAsset, Log } from '@egt/core';\n\nexport default abstract class BaseModesConfigurations<ModeTypeT> {\n    public mode: IModes;\n    public modeType: ModeTypeT;\n\n    protected baseModesConfig: IModes = <IModes>{};\n    protected templateModesConfig: IModes = <IModes>{};\n    protected gameModesConfig: IModes = <IModes>{};\n\n    protected baseAssets: Array<IAsset | ISoundAsset> = [];\n    protected templateAssets: Array<IAsset | ISoundAsset> = [];\n    protected gameAssets: Array<IAsset | ISoundAsset> = [];\n\n    constructor(modeType: ModeTypeT, forceSetConfig?: IForceSetConfig) {\n        this.modeType = modeType;\n        this.baseAssets = this.createAssetsConfig();\n        this.templateAssets = this.createTemplateAssetsConfig();\n        this.gameAssets = this.createGameAssetsConfig();\n\n        this.baseModesConfig = this.createBaseModesConfig(modeType);\n        this.templateModesConfig = this.createTemplateModesConfig(modeType);\n        this.gameModesConfig = this.createGameModesConfig(modeType);\n\n        this.mode = this.getModConfig();\n\n        if (forceSetConfig) {\n            if (forceSetConfig.configObj) {\n                this.mode.configuration = forceSetConfig.configObj.config(forceSetConfig.configObj.basConfig());\n            }\n            if (forceSetConfig.view) {\n                this.mode.view = forceSetConfig.view;\n            }\n            if (forceSetConfig.desktopView) {\n                this.mode.desktopView = forceSetConfig.desktopView;\n            }\n            if (forceSetConfig.secondView) {\n                this.mode.secondView = forceSetConfig.secondView;\n            }\n            if (forceSetConfig.controller) {\n                this.mode.controller = forceSetConfig.controller;\n            }\n            if (forceSetConfig.secondController) {\n                this.mode.secondController = forceSetConfig.secondController;\n            }\n            if (forceSetConfig.desktopController) {\n                this.mode.desktopController = forceSetConfig.desktopController;\n            }\n        }\n    }\n\n    public getModConfig(): IModes {\n        const mode: IModes = <IModes>{};\n\n        for (const key in this.baseModesConfig) {\n            mode[key] = this.baseModesConfig[key];\n        }\n\n        for (const key in this.templateModesConfig) {\n            if (Object.prototype.hasOwnProperty.call(mode, key) && mode[key] !== key && this.templateModesConfig[key]) {\n                mode[key] = this.templateModesConfig[key];\n            }\n        }\n\n        for (const key in this.gameModesConfig) {\n            if (Object.prototype.hasOwnProperty.call(mode, key) && mode[key] !== key && this.gameModesConfig[key]) {\n                mode[key] = this.gameModesConfig[key];\n            }\n        }\n        return mode;\n    }\n\n    public setConfig(config: any, baseConfig: any): void {\n        this.mode.configuration = config(baseConfig());\n    }\n\n    public setView(view: any): void {\n        this.mode.view = view;\n    }\n\n    public setSecondView(secondView: any): void {\n        this.mode.secondView = secondView;\n    }\n\n    public setController(controller: any): void {\n        this.mode.controller = controller;\n    }\n\n    public getAssets(): Array<IAsset | ISoundAsset> {\n        const assetsMap = new Map<string, IAsset | ISoundAsset>();\n\n        for (const asset of this.baseAssets) {\n            assetsMap.set(asset.id, asset);\n        }\n        for (const asset of this.templateAssets) {\n            if (!assetsMap.has(asset.id) || !this.objComparing(assetsMap.get(asset.id), asset, 'base')) {\n                assetsMap.set(asset.id, asset);\n            }\n        }\n        for (const asset of this.gameAssets) {\n            if (!assetsMap.has(asset.id) || !this.objComparing(assetsMap.get(asset.id), asset, 'template')) {\n                assetsMap.set(asset.id, asset);\n            }\n        }\n        return Array.from(assetsMap.values());\n    }\n\n    private objComparing(obj1, obj2, comparingWith: 'base' | 'template'): boolean {\n        if (obj1 === obj2) return true;\n\n        if (typeof obj1 !== 'object' || obj1 === null || typeof obj2 !== 'object' || obj2 === null) {\n            return false;\n        }\n\n        const keys1 = Object.keys(obj1);\n        const keys2 = Object.keys(obj2);\n\n        if (keys1.length !== keys2.length) return false;\n\n        for (const key of keys1) {\n            if (!keys2.includes(key)) return false;\n            if (!this.objComparing(obj1[key], obj2[key], comparingWith)) return false;\n        }\n        if (comparingWith === 'base') {\n            Log.error(\n                'Try to override assets in template with id: ' +\n                    obj1.id +\n                    ' but it same as asset in base configuration.',\n                this.constructor.name,\n            );\n        } else {\n            Log.error(\n                'Try to override assets in game with id: ' +\n                    obj1.id +\n                    ' but it same as asset in template or base configurations.',\n                this.constructor.name,\n            );\n        }\n\n        return true;\n    }\n\n    // this method must be overrode only in base factories\n    protected createBaseModesConfig(_modeType: ModeTypeT): IModes {\n        return <IModes>{};\n    }\n\n    // this method must be overrode only in base factories\n    protected createTemplateModesConfig(_modeType: ModeTypeT): IModes {\n        return <IModes>{};\n    }\n\n    // this method must be overrode only in game factories\n    protected createGameModesConfig(_modeType: ModeTypeT): IModes {\n        return <IModes>{};\n    }\n\n    // this method must be overrode only in base factories\n    protected createAssetsConfig(): Array<IAsset | ISoundAsset> {\n        return [];\n    }\n\n    // this method must be overrode only in template factories\n    protected createTemplateAssetsConfig(): Array<IAsset | ISoundAsset> {\n        return [];\n    }\n\n    // this method must be overrode only in template factories\n    protected createGameAssetsConfig(): Array<IAsset | ISoundAsset> {\n        return [];\n    }\n}\n\nexport interface IModes {\n    view?: any;\n    desktopView?: any;\n    secondView?: any;\n    thirdView?: any;\n    configuration?: any;\n    controller?: any;\n    desktopController?: any;\n    secondController?: any;\n}\nexport interface IForceSetConfig {\n    configObj?: {\n        config: any;\n        basConfig: any;\n    };\n    view?: any;\n    desktopView?: any;\n    secondView?: any;\n    controller?: any;\n    desktopController?: any;\n    secondController?: any;\n}\n\nexport interface IModeConfig {\n    modeFactory?: any;\n    modeType?: any;\n    view?: any;\n    desktopView?: any;\n    secondView?: any;\n    configuration?: any;\n    // configuration of a component's secondary part (e.g. buy-bonus' double chance);\n    // merged between template and game the same way as `configuration`\n    secondConfiguration?: any;\n    controller?: any;\n    secondController?: any;\n    desktopController?: any;\n    forceMode?: any;\n}\n\nexport interface IBaseModeFactory {\n    mode: IModes;\n    modeType: any;\n}\n","/*\n  This is a base class for all stores. It will have all the common methods that are used in all the stores.\n */\nimport { isArray, isObject, Logger } from 'unicorn.console-logger';\nimport { BehaviorSubject, isObservable, Subject, merge } from 'rxjs';\nimport Core from '@egt/core';\nimport { skip, takeUntil } from 'rxjs/operators';\n\nfunction isBehaviorSubject<T>(obj: Subject<T>): obj is BehaviorSubject<T> {\n    return obj instanceof BehaviorSubject;\n}\n\nexport function logSubjectsValues<T extends object>(_this: T, ignore: Subject<any>[] = [], logInitialValues = false) {\n    Object.keys(_this).forEach((key) => {\n        const property = _this[key] as Subject<any>;\n\n        // Check if the property is an Observable (Subject, BehaviorSubject, etc.)\n        if (isObservable(property) && !ignore.some((ignoredSubject) => ignoredSubject === property)) {\n            // Check if it's a BehaviorSubject by looking for the \"value\" property\n\n            const isBehaviorSubjectType = isBehaviorSubject(property);\n            let isFirstEmission = true;\n            let preValue = undefined;\n\n            // skip first emit from BehaviorSubject if we want to ignore the initial value\n            const subject = isBehaviorSubjectType && !logInitialValues ? property.pipe(skip(1)) : property;\n            subject.pipe(takeUntil(merge(Core.EXIT_APPLICATION, Core.ON_GAME_UNLOADED))).subscribe({\n                next: (value) => {\n                    if (!isObject(value) && !isArray(value)) {\n                        value = `${value}`;\n                    }\n\n                    // Handle first emission  for BehaviorSubjects\n                    if (isBehaviorSubjectType && isFirstEmission && logInitialValues) {\n                        Logger.logModelMessage([`${key} initial value:`, value], _this);\n                    } else {\n                        Logger.logModelMessage([`${key} emitted:`, { new: value, prev: preValue }], _this);\n                    }\n\n                    isFirstEmission = false;\n                    preValue = value;\n                },\n                error: (error) => {\n                    Logger.logModelMessage([`${key} error`, error], _this, 'error');\n                },\n                complete: () => {\n                    Logger.logModelMessage([`${key} completed`], _this);\n                },\n            });\n        }\n    });\n}\n\nexport abstract class BaseStore {\n    constructor() {\n        Logger.logModelMessage(['Created'], this.constructor.name);\n    }\n\n    protected enableLogging(ignoreLogSubjects: Subject<unknown>[] = [], logInitialValues = false) {\n        if (Core.configuration.devTools) {\n            logSubjectsValues(this, ignoreLogSubjects, logInitialValues);\n        }\n    }\n}\n","import { DependencyContainer } from 'tsyringe';\nimport { ITemplate } from './interfaces/ITemplate';\n\nexport default class BaseTemplate implements ITemplate {\n    public featuresMap: any;\n    protected componentsMap;\n    protected defaultTemplateComponents;\n\n    public getTemplateComponents(): any[] {\n        return [];\n    }\n\n    public getTemplateGameFeatures(): any[] {\n        return [];\n    }\n\n    public getTemplateExternalFeatures(): any[] {\n        return [];\n    }\n\n    public hasComponentWithActiveModeType(_component, _mode: any): any {\n        return '';\n    }\n\n    public updateComponents(_components: any[]): void {\n        // implement\n    }\n\n    public extendComponents(_components: any[]): void {\n        // implement\n    }\n\n    public updateGameFeatures(_features: any[]): void {\n        // implement\n    }\n\n    public addExternalFeatures(_features: any[]): void {\n        // implement\n    }\n\n    public updateExternalServerList(features: any[]): any[] {\n        return features;\n    }\n\n    public updateExternalFeatures(_features: any[]): void {\n        // implement\n    }\n\n    public removeComponents(_components: any[]): void {\n        // implement\n    }\n\n    public destroy(): void {\n        if (this.featuresMap) {\n            // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n            this.featuresMap.forEach((element) => {\n                element = [];\n            });\n            this.featuresMap.clear();\n        }\n\n        if (this.componentsMap) {\n            // this.componentsMap.forEach(el => {\n            //     if (el) {\n            //         if (el.constructor.__decoratorProperties) {\n            //             // @ts-ignore\n            //             for (const propertyKey of el.constructor.__decoratorProperties) {\n            //                 // @ts-ignore\n            //                 delete el.__proto__.__proto__[propertyKey];\n            //             }\n            //             // Optionally, you can clear the list of decorator properties\n            //             // @ts-ignore\n            //             el.constructor.__decoratorProperties = [];\n            //         }\n            //     }\n            // });\n\n            this.componentsMap.clear();\n        }\n\n        // @ts-ignore\n        this.featuresMap = null;\n        // @ts-ignore\n        this.componentsMap = null;\n        // @ts-ignore\n        this.defaultTemplateComponents = null;\n    }\n\n    public removeFeatures(_features: any[]): void {\n        // implement\n    }\n\n    public setComponentsMap(_components: any[]): void {\n        // implement\n    }\n\n    public registerTemplateConfiguration(_dependencyContainer: DependencyContainer): void {\n        // implement\n    }\n\n    protected setFeaturesMap(_features: any[]): void {\n        // implement\n    }\n}\n","import { asapScheduler } from 'rxjs';\nimport { observeOn } from 'rxjs/operators';\nimport { inject, injectable, singleton } from 'tsyringe';\nimport Core, { BalanceResponse, Log, PostMessageDispatcher } from './Core';\nimport ErrorTypes from './enums/ErrorTypes';\nimport { ICommunication } from './interfaces/ICommunication';\nimport { IErrorData } from './interfaces/IErrorData';\nimport { IRequest } from './interfaces/IRequest';\n// import { LoadGameMock } from './mockLoadGameResponse';\n\n@injectable()\n@singleton()\nexport default class CommunicationManager {\n    private id: number = 1;\n    /** used after reconnect to send same message again because we are not sure it is received */\n    private _lastMessageSent: any;\n    private readonly _waitingResponseCommands = ['bet', 'collect'];\n    private _waitingResponse: boolean = false;\n\n    constructor(@inject('ICommunication') private connection: ICommunication) {\n        Core.ON_SERVER_RESPONSE.pipe(observeOn(asapScheduler)).subscribe(this.onServerMessage.bind(this));\n        Core.ON_CONNECTION_RESTORED.subscribe(this.onConnectionRestored.bind(this));\n    }\n\n    // if a stored message is posted as param - we use it instead reissue id\n    // we return last send message in order to send same on reconnect if needed\n    public sendMessage(request: IRequest): number {\n        this._lastMessageSent = request.serialize();\n        this._lastMessageSent.id = this.getId();\n        this.connection.sendMessage(this._lastMessageSent);\n        if (this._waitingResponseCommands.includes(this._lastMessageSent.event)) {\n            this._waitingResponse = true;\n        }\n        return this._lastMessageSent.id;\n    }\n\n    private onServerMessage(response): void {\n        // Mock response for testing\n        // LoadGameMock.enabled = false;\n        // LoadGameMock.apply(response);\n        // LoadGameMock.enabled = false;\n        // this._lastMessageSent = undefined;\n        if (this._lastMessageSent?.id === response.referenceId) {\n            this._lastMessageSent = null;\n        }\n        if (response.error !== undefined) {\n            Log.error(response, this.constructor.name, response);\n            const errorData = {} as IErrorData;\n            errorData.code = response.error.code;\n            errorData.modal = true;\n            errorData.type = ErrorTypes.GAME_LOCK_ERROR;\n            if (Core.configuration.gameKey === '') {\n                switch (errorData.code.toString()) {\n                    // case \"4813\":  // TODO - when it is clear what to do with already animted reels\n                    case '4807':\n                    case '4808':\n                    case '4809':\n                    case '4810':\n                        errorData.type = ErrorTypes.GAME_ERROR;\n                        break;\n                    default:\n                        errorData.type = ErrorTypes.GAME_LOCK_ERROR;\n                }\n            }\n            // errorData.type = response.state === \"idle\" ? ErrorTypes.GAME_ERROR : ErrorTypes.GAME_LOCK_ERROR;\n            if (Core.configuration.multiplayer) {\n                if (response.event === 'joinGame') {\n                    Core.SHOW_ERROR.next(errorData);\n                } else {\n                    // do not show error dialog here - just forward the message\n                    // MP game will show toast or error\n                    Core.ON_SERVER_MESSAGE.next(response);\n                }\n            } else {\n                const code = errorData.code.toString();\n\n                if (code === '4813' || code === '4818') {\n                    errorData.type = ErrorTypes.GAME_ERROR;\n                    errorData.payload = response;\n                }\n\n                Core.SHOW_ERROR.next(errorData);\n\n                if (code === '4813') {\n                    PostMessageDispatcher.balanceTooLow();\n                }\n            }\n            return;\n        }\n        if (this._waitingResponseCommands.includes(response.event)) {\n            this._waitingResponse = false;\n        }\n        if (response.balance !== undefined && !(response.event === 'balance' && this._waitingResponse)) {\n            const balanceResponse = new BalanceResponse(response);\n            if (\n                Core.PLAYER_BALANCE.value.balance !== balanceResponse.balance ||\n                Core.PLAYER_BALANCE.value.currency !== balanceResponse.currency\n            ) {\n                Core.PLAYER_BALANCE.next(balanceResponse);\n            }\n        }\n        switch (response.event) {\n            case 'unloadGame':\n                // Core.ON_GAME_UNLOADED.next();\n                if (response.error === undefined) {\n                    Core.ON_GAME_UNLOADED.next();\n                }\n                break;\n            case 'balance':\n                if (!this._waitingResponse) {\n                    Core.ON_SERVER_MESSAGE.next(response);\n                }\n                break;\n\n            case 'settings':\n                Core.configuration.sessionKey = response.sessionKey;\n                Core.settings = response;\n                Core.ON_GAME_LOADED.next(response);\n                break;\n            case 'loadGame':\n                if (response.error === undefined) {\n                    // if (response.gameKey === 'BLCBLSlot') {\n                    //     response.gameKey = 'BLWBLSlot';\n                    // }\n                    Core.configuration.gameKey = response.gameKey;\n                    Core.configuration.sessionKey = response.sessionKey;\n                    Core.ON_GAME_LOADED.next(response);\n                }\n                break;\n            case 'joinGame':\n                if (response.errorData === undefined) {\n                    response.gameKey = Core.configuration.gameKey;\n                    const firstLoad = Core.settingsMP === undefined;\n                    Core.configuration.sessionKey = response.data.sessionKey;\n                    Core.settingsMP = response.data;\n                    // Core.settingsMP.settings.bet.multipleBetsEnabled = false;\n                    if (firstLoad) {\n                        Core.ON_GAME_LOADED.next(response);\n                    } else {\n                        Core.ON_SERVER_MESSAGE.next(response);\n                    }\n                }\n                break;\n\n            // in some cases joinGame is not proccessed yet because the app is\n            // still not started but we recieve state change\n            case 'changeState':\n                Core.settingsMP.matchId = response.data.matchId;\n                Core.settingsMP.state = response.data.state;\n                Core.ON_SERVER_MESSAGE.next(response);\n                break;\n            default:\n                Core.ON_SERVER_MESSAGE.next(response);\n        }\n    }\n\n    private getId(): number {\n        return this.id++;\n    }\n\n    // if we have not responsed bet request - send again same\n    private onConnectionRestored(): void {\n        Log.client('Reconnected', this.constructor.name);\n        Core.customAppService.send('GAME_CONNECTION_STATUS', { connected: true });\n        if (this._lastMessageSent) {\n            this.connection.sendMessage(this._lastMessageSent);\n        }\n    }\n}\n","import Core from './Core';\nimport { ICondition } from './interfaces/ICondition';\n\nexport default class ConditionObject {\n    private conditionData: ICondition;\n\n    constructor(data: ICondition) {\n        this.conditionData = data;\n    }\n\n    public get condition(): boolean {\n        if (Core.isDesktopMode) {\n            return this.conditionData.desktop;\n        } else if (Core.ORIENTATION.value.isLandscape) {\n            return this.conditionData.landscape;\n        } else {\n            return this.conditionData.portrait;\n        }\n    }\n}\n","import { IConfiguration } from './interfaces/IConfiguration';\n\nexport default class Configuration implements IConfiguration {\n    public sessionToken: string;\n    public sessionKey: string;\n    public tempToken: string;\n    public playerId: string;\n    public playerName?: string | undefined;\n    public casinoId: string;\n    public gameKey: string;\n    public demo: boolean;\n    public devTools: boolean;\n    public redundantOverrideReport?: boolean;\n    public language: string;\n    public protocol: string;\n    public multiplayer: boolean;\n    public host: string;\n    public multiplayerHost: string;\n    public resourcesRootDir: string;\n    public currencyCode: string;\n    public currencyUnits: number;\n    public tournamentAPICallTimeout: number;\n    public version: string;\n    public showCustomGameErrors: boolean = false;\n    public isBimEnvironment: boolean = false;\n    public closeUrl: string;\n    public hasPortal: boolean;\n    public scenarioHost: string;\n    public assetPackHost: string;\n    public historyHost: string;\n    public multiplayerApi: string;\n    public tournamentHost: string;\n    public prizePopServiceHost: string;\n    public allowHostOverrideFromUrl: boolean;\n    public mode: string;\n    public external: any = {};\n    public mute: boolean = false;\n    public lobbyOpenType: 'fullscreen' | 'ingame' = 'fullscreen';\n    public lobbyHost: string;\n    public lobbyRedirectHost: string;\n    public apiIntegrationHost: string;\n    public bgMusicMute: boolean = false;\n    public hideHandCursor: boolean = false;\n    public blockLobby: boolean = false;\n    public comeFromLobby: number = 0;\n    // public gameFeatures: any[];\n    public replaceAssets: boolean = false;\n    public replaceSoundAssets: boolean = false;\n    public replaceImageAssets: boolean = false;\n    public noSounds: boolean = false;\n    public hideFullScreenButton: boolean = false;\n    public replayHost: string;\n    public openSection: string;\n    public layoutType: string;\n\n    constructor(options?: any) {\n        if (options) {\n            this.sessionToken = options.sessionToken || this.sessionToken;\n            this.tempToken = options.tempToken || this.tempToken;\n            this.playerId = options.playerId || this.playerId;\n            this.playerName = options.playerName || this.playerName;\n            this.casinoId = options.casinoId || this.casinoId;\n            this.gameKey = options.gameKey || this.gameKey;\n            this.demo = options.demo || this.demo;\n            this.language = options.language || this.language;\n            this.host = options.host || this.host;\n            this.resourcesRootDir = options.resourcesRootDir || this.resourcesRootDir;\n            this.currencyCode = options.currencyCode || this.currencyCode;\n            this.currencyUnits = options.currencyUnits || this.currencyUnits;\n            this.protocol = options.protocol || this.protocol;\n            this.devTools = options.devTools || this.devTools;\n            this.redundantOverrideReport = options.redundantOverrideReport ?? this.redundantOverrideReport;\n            this.historyHost = options.historyHost || this.historyHost;\n            this.tournamentHost = options.tournamentHost || this.tournamentHost;\n            this.prizePopServiceHost = options.prizePopServiceHost || this.prizePopServiceHost;\n            this.scenarioHost = options.scenarioHost || this.scenarioHost;\n            this.assetPackHost = options.assetPackHost || this.assetPackHost;\n            this.multiplayerApi = options.multiplayerApi || this.multiplayerApi;\n            this.allowHostOverrideFromUrl = options.allowHostOverrideFromUrl || this.allowHostOverrideFromUrl;\n            this.mute = options.mute || this.mute;\n            this.lobbyHost = options.lobbyHost || this.lobbyHost;\n            this.apiIntegrationHost = options.apiIntegrationHost || this.apiIntegrationHost;\n            this.bgMusicMute = options.bgMusicMute || this.bgMusicMute;\n            this.hideHandCursor = options.hideHandCursor || false;\n            this.blockLobby = options.blockLobby || false;\n            this.replaceAssets = options.replaceAssets || false;\n            this.replaceSoundAssets = options.replaceSoundAssets || false;\n            this.replaceImageAssets = options.replaceImageAssets || false;\n            this.noSounds = options.noSounds || false;\n            this.replayHost = options.replayHost || this.replayHost;\n            this.hideFullScreenButton = options.hideFullScreenButton || this.hideFullScreenButton;\n            this.openSection = options.openSection || this.openSection;\n            this.layoutType = options.layoutType || this.layoutType;\n        }\n\n        this.lobbyRedirectHost = window.location.protocol + '//' + window.location.host;\n    }\n}\n","import { BehaviorSubject, Subject } from 'rxjs';\nimport { BusMessage } from './data/BusMessage';\n\nconst CHANNEL_NAME = 'egt-game-client-channel';\nconst WINDOW_OPEN_KEY = 'egt-custom-app-window-open';\n\ntype MessageHandler = (message: BusMessage) => void;\n\nexport default class CustomAppService {\n    public readonly onMessage$ = new Subject<BusMessage>();\n    public readonly onConnected$ = new Subject<boolean>();\n    public readonly iframeVisible$ = new BehaviorSubject<boolean>(false);\n    public readonly sessionId: string;\n\n    private channel: BroadcastChannel | null = null;\n    private handlers: Map<string, MessageHandler[]> = new Map();\n    private appWindow: Window | null = null;\n    private _connected = false;\n    private _initialized = false;\n    public openedCustom = false;\n    private windowMessageListener: ((event: MessageEvent) => void) | null = null;\n    private focusListener: (() => void) | null = null;\n    private visibilityListener: (() => void) | null = null;\n\n    // Iframe overlay for mobile\n    private iframeContainer: HTMLDivElement | null = null;\n    private iframe: HTMLIFrameElement | null = null;\n    private _iframeVisible = false;\n\n    constructor() {\n        this.sessionId = `game-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;\n    }\n\n    // The service is instantiated in every session (Core field initializer), so all\n    // side effects (channel, listeners, iframe) live here and run only when dev\n    // tools are enabled. Until then send() and preloadIframe() are no-ops.\n    public init(): void {\n        if (this._initialized) {\n            return;\n        }\n        this._initialized = true;\n\n        // Restore window-open state from localStorage (survives refresh)\n        try {\n            this.openedCustom = localStorage.getItem(WINDOW_OPEN_KEY) === 'true';\n        } catch (_) {\n            this.openedCustom = false;\n        }\n\n        if (typeof BroadcastChannel !== 'undefined') {\n            this.channel = new BroadcastChannel(CHANNEL_NAME);\n            this.channel.onmessage = (event: MessageEvent) => {\n                const data = event.data;\n                if (data && data.type === 'CUSTOM_WINDOW_OPENED' && data.source === 'game-client') {\n                    this.setWindowOpen(true);\n                    // Hide iframe on this tab since a window is now open\n                    this.setIframeVisible(false);\n                    return;\n                }\n                this.handleIncoming(data);\n            };\n        }\n\n        this.windowMessageListener = this.onWindowMessage.bind(this);\n        if (this.windowMessageListener) {\n            window.addEventListener('message', this.windowMessageListener);\n        }\n\n        this.focusListener = () => {\n            if (this._connected) {\n                this.send('GAME_FOCUSED');\n            }\n        };\n        window.addEventListener('focus', this.focusListener);\n\n        this.visibilityListener = () => {\n            if (!document.hidden && this._connected) {\n                this.send('GAME_FOCUSED');\n            }\n        };\n        document.addEventListener('visibilitychange', this.visibilityListener);\n\n        // Stale check: if localStorage says window is open but we get no sign of life, clear it\n        if (this.openedCustom) {\n            setTimeout(() => {\n                if (this.openedCustom && !this._connected) {\n                    this.setWindowOpen(false);\n                }\n            }, 5000);\n        }\n    }\n\n    public open(): void {\n        if (this.appWindow && !this.appWindow.closed) {\n            this.appWindow.focus();\n            return;\n        }\n        if (this.openedCustom) {\n            this.send('FOCUS_APP');\n            return;\n        }\n        this.openIframe();\n    }\n\n    public openInNewWindow(): void {\n        // Remove iframe entirely since we're moving to a standalone window.\n        // This prevents the iframe from sending a stale APP_CLOSED on page refresh.\n        if (this.iframeContainer) {\n            this.iframeContainer.remove();\n            this.iframeContainer = null;\n            this.iframe = null;\n            this.setIframeVisible(false);\n        }\n\n        if (this.appWindow && !this.appWindow.closed) {\n            this.appWindow.focus();\n            return;\n        }\n\n        this.setWindowOpen(true);\n        this.appWindow = window.open(\n            '/custom-app.html',\n            'custom-app',\n            'width=960,height=700,resizable=yes,scrollbars=yes',\n        );\n        // Notify all tabs that a new window is open\n        if (this.channel) {\n            this.channel.postMessage({\n                type: 'CUSTOM_WINDOW_OPENED',\n                source: 'game-client',\n                timestamp: Date.now(),\n            });\n        }\n    }\n\n    public close(): void {\n        this.setIframeVisible(false);\n        if (this.appWindow && !this.appWindow.closed) {\n            this.appWindow.close();\n        }\n        this.appWindow = null;\n        this._connected = false;\n        this.onConnected$.next(false);\n    }\n\n    public toggle(): void {\n        if (this.appWindow && !this.appWindow.closed) {\n            this.appWindow.focus();\n            return;\n        }\n        if (this.openedCustom) {\n            this.send('FOCUS_APP');\n            return;\n        }\n        if (!this.iframeContainer) {\n            this.openIframe();\n        } else {\n            this.setIframeVisible(!this._iframeVisible);\n        }\n    }\n\n    public get iframeVisible(): boolean {\n        return this._iframeVisible;\n    }\n\n    private setIframeVisible(visible: boolean): void {\n        this._iframeVisible = visible;\n        if (this.iframeContainer) {\n            this.iframeContainer.style.display = visible ? 'flex' : 'none';\n        }\n        if (this.iframeVisible$.value !== visible) {\n            this.iframeVisible$.next(visible);\n        }\n    }\n\n    private isMobile(): boolean {\n        return (\n            /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ||\n            (navigator.maxTouchPoints > 0 && window.innerWidth < 1024)\n        );\n    }\n\n    public preloadIframe(): void {\n        if (!this._initialized) return;\n        if (this.iframeContainer || this.openedCustom) return;\n        if (this.appWindow && !this.appWindow.closed) return;\n\n        this.iframeContainer = document.createElement('div');\n        this.iframeContainer.id = 'custom-app-iframe-overlay';\n        Object.assign(this.iframeContainer.style, {\n            position: 'fixed',\n            top: '0',\n            left: '0',\n            width: '100%',\n            height: '100%',\n            zIndex: '99999',\n            display: 'none',\n            flexDirection: 'column',\n            background: 'rgba(0,0,0,0.85)',\n        });\n\n        this.iframe = document.createElement('iframe');\n        // Pass this window's sessionId so the embedded app locks onto this game\n        // only (a standalone window gets no sessionId and follows the focused game)\n        this.iframe.src = '/custom-app.html?sessionId=' + encodeURIComponent(this.sessionId);\n        Object.assign(this.iframe.style, {\n            flex: '1',\n            border: 'none',\n            width: '100%',\n            background: '#0f172a',\n        });\n\n        this.iframeContainer.appendChild(this.iframe);\n        document.body.appendChild(this.iframeContainer);\n        this._iframeVisible = false;\n    }\n\n    private openIframe(): void {\n        // Fallback if preload hasn't run yet\n        this.preloadIframe();\n        this.setIframeVisible(true);\n    }\n\n    public send(type: string, payload?: any): void {\n        if (!this._initialized) return;\n        const message: BusMessage = {\n            type,\n            source: 'game-client',\n            payload,\n            timestamp: Date.now(),\n            sessionId: this.sessionId,\n        };\n\n        if (this.channel) {\n            this.channel.postMessage(message);\n        } else if (this.appWindow && !this.appWindow.closed) {\n            // Fallback: send via postMessage only when BroadcastChannel is not available\n            this.appWindow.postMessage(message, '*');\n        }\n    }\n\n    public on(type: string, handler: MessageHandler): () => void {\n        if (!this.handlers.has(type)) {\n            this.handlers.set(type, []);\n        }\n        this.handlers.get(type)!.push(handler);\n\n        return () => {\n            const list = this.handlers.get(type);\n            if (list) {\n                const idx = list.indexOf(handler);\n                if (idx !== -1) list.splice(idx, 1);\n            }\n        };\n    }\n\n    public onAny(handler: MessageHandler): () => void {\n        return this.on('*', handler);\n    }\n\n    public get connected(): boolean {\n        return this._connected;\n    }\n\n    private setWindowOpen(value: boolean): void {\n        this.openedCustom = value;\n        try {\n            if (value) {\n                localStorage.setItem(WINDOW_OPEN_KEY, 'true');\n            } else {\n                localStorage.removeItem(WINDOW_OPEN_KEY);\n                this.preloadIframe();\n            }\n        } catch (_) {\n            // localStorage not available\n        }\n    }\n\n    public destroy(): void {\n        this.close();\n        if (this.iframeContainer) {\n            this.iframeContainer.remove();\n            this.iframeContainer = null;\n            this.iframe = null;\n        }\n        if (this.channel) {\n            this.channel.close();\n            this.channel = null;\n        }\n        if (this.windowMessageListener) {\n            window.removeEventListener('message', this.windowMessageListener);\n            this.windowMessageListener = null;\n        }\n        if (this.focusListener) {\n            window.removeEventListener('focus', this.focusListener);\n            this.focusListener = null;\n        }\n        if (this.visibilityListener) {\n            document.removeEventListener('visibilitychange', this.visibilityListener);\n            this.visibilityListener = null;\n        }\n        this.handlers.clear();\n        this.onMessage$.complete();\n        this.onConnected$.complete();\n        this._initialized = false;\n    }\n\n    private onWindowMessage(event: MessageEvent): void {\n        const data = event.data as BusMessage;\n        if (data && data.type && data.source === 'custom-app') {\n            this.handleIncoming(data);\n        }\n    }\n\n    private handleIncoming(message: BusMessage): void {\n        if (!message || !message.type || message.source !== 'custom-app') {\n            return;\n        }\n\n        // Always handle connection messages from any source\n        if (message.type === 'APP_READY') {\n            this._connected = true;\n            this.onConnected$.next(true);\n            if (document.hasFocus()) {\n                this.send('GAME_FOCUSED');\n            }\n        }\n\n        if (message.type === 'PING') {\n            if (!this._connected) {\n                this._connected = true;\n                this.onConnected$.next(true);\n            }\n            this.send('PONG', message.payload);\n        }\n\n        if (message.type === 'APP_CLOSED') {\n            this._connected = false;\n            this.setWindowOpen(false);\n            this.appWindow = null;\n            this.onConnected$.next(false);\n        }\n\n        if (message.type === 'OPEN_IN_NEW_WINDOW') {\n            if (this._iframeVisible && document.hasFocus()) {\n                this.openInNewWindow();\n            }\n            return;\n        }\n\n        if (message.type === 'CLOSE_IFRAME') {\n            if (this._iframeVisible) {\n                this.setIframeVisible(false);\n            }\n            return;\n        }\n\n        // For all other messages, only process if addressed to this tab's session\n        if (message.type !== 'APP_READY' && message.type !== 'PING' && message.type !== 'APP_CLOSED') {\n            if (message.sessionId && message.sessionId !== this.sessionId) {\n                return;\n            }\n            // If no sessionId yet, only the visible (active) tab should respond\n            if (!message.sessionId && document.hidden) {\n                return;\n            }\n        }\n\n        this.onMessage$.next(message);\n\n        const handlers = this.handlers.get(message.type);\n        if (handlers) {\n            handlers.forEach((h) => h(message));\n        }\n\n        const wildcardHandlers = this.handlers.get('*');\n        if (wildcardHandlers) {\n            wildcardHandlers.forEach((h) => h(message));\n        }\n    }\n}\n","import { ScratchFeatures } from '@egt/scratch';\n\nimport { Features, SlotComponents, Subjects } from '@egt/slot';\nimport ScratchSubjects from 'scratch/src/egt/scratch/components/data/ScratchSubjects';\nimport Core from './Core';\nimport { IDynamicPosition, IModifiedDynamicPosition } from './interfaces/IDynamicPosition';\nimport { OverrideType } from './utils/OverrideRedundancyReporter';\nimport RedundantOverrideInspector from './utils/RedundantOverrideInspector';\n\nexport interface IOverrideRuntimeContext {\n    overrideType: OverrideType;\n    configurationClassName: string;\n    extendedConfigurationClassName?: string;\n    propertyKey: string;\n}\n\nexport default class DynamicPositionObject<T> {\n    public positionData: IDynamicPosition<T>;\n    public configs: Array<{\n        value: IModifiedDynamicPosition<T>;\n        priority: number;\n        priorityType: { feature: any; mode: any };\n        condition?: (obj: any) => boolean;\n    }>;\n    public activePriorityIndex: number;\n\n    constructor(dataNew: IDynamicPosition<T>, data?: DynamicPositionObject<T>) {\n        if (!data) {\n            this.positionData = dataNew;\n        } else {\n            this.replacePositionData(dataNew, data);\n        }\n\n        for (const key in dataNew.defaults) {\n            Object.defineProperty(this, key, {\n                get: () => {\n                    return this.get(key as keyof T);\n                },\n            });\n        }\n    }\n\n    public updatePriorities(): void {\n        if (this.configs) {\n            this.activePriorityIndex = this.getConfigIndex(this.configs);\n            if (this.activePriorityIndex !== -1) {\n                this.replacePositionData(this.configs[this.activePriorityIndex].value, this);\n            }\n        }\n    }\n\n    public getSlotActiveFeature(): Features | SlotComponents | null {\n        if (Core.gameDependencyContainer.isRegistered('SlotSubjects')) {\n            const subjects: Subjects = Core.gameDependencyContainer.resolve('SlotSubjects');\n\n            let activeFeatures: any[] = subjects.ACTIVE_FEATURE.value;\n            activeFeatures = activeFeatures.concat(subjects.ACTIVE_COMPONENT.value);\n            for (let i = activeFeatures.length - 1; i >= 0; i--) {\n                const activeFeat = activeFeatures[i];\n                if (this.positionData.features && this.positionData.features?.[activeFeat]) {\n                    return activeFeat;\n                }\n            }\n        }\n        return null;\n    }\n\n    public getScratchActiveFeature(): ScratchFeatures | null {\n        if (Core.gameDependencyContainer.isRegistered('ScratchSubjects')) {\n            const subjects: ScratchSubjects = Core.gameDependencyContainer.resolve('ScratchSubjects');\n            const activeFeatures = subjects.ACTIVE_FEATURE.value;\n            for (let i = activeFeatures.length - 1; i >= 0; i--) {\n                const activeFeat = activeFeatures[i];\n                if (this.positionData.features && this.positionData.features?.[activeFeat]) {\n                    return activeFeat;\n                }\n            }\n        }\n        return null;\n    }\n\n    public get<K extends keyof T>(prop: K): T[K] {\n        const mainPosData = this.positionData;\n        let feat;\n        if (this.getGameType() === 'Slot') {\n            feat = this.getSlotActiveFeature();\n        } else {\n            feat = this.getScratchActiveFeature();\n        }\n        const featPosData = feat ? this.positionData.features?.[feat] : {};\n        if (Core.isDesktopMode && (mainPosData.desktop || featPosData?.desktop)) {\n            if (featPosData?.desktop && featPosData.desktop[prop] !== undefined) {\n                return featPosData.desktop[prop] as unknown as T[K];\n            } else if (mainPosData.desktop && mainPosData.desktop[prop] !== undefined) {\n                return mainPosData.desktop[prop] as unknown as T[K];\n            } else if (featPosData?.defaults?.[prop] !== undefined) {\n                return featPosData.defaults[prop] as T[K];\n            } else {\n                return mainPosData.defaults[prop] as T[K];\n            }\n        } else if (Core.ORIENTATION.value.isLandscape && (mainPosData.landscape || featPosData?.landscape)) {\n            const strProp = prop as string;\n            const leftHandProp = 'leftHand' + strProp.replace(/^./, strProp[0].toUpperCase()); // uppercase the first letter of the key\n            if (\n                Core.LEFT_HAND_MODE.value &&\n                (mainPosData.landscape?.[leftHandProp] ||\n                    featPosData?.landscape?.[leftHandProp] ||\n                    mainPosData.defaults[leftHandProp] ||\n                    featPosData?.defaults?.[leftHandProp])\n            ) {\n                if (typeof featPosData?.landscape?.[leftHandProp] !== 'undefined') {\n                    return featPosData.landscape?.[leftHandProp];\n                } else if (typeof mainPosData.landscape?.[leftHandProp] !== 'undefined') {\n                    return mainPosData.landscape?.[leftHandProp];\n                } else if (typeof featPosData?.defaults?.[leftHandProp] !== 'undefined') {\n                    return featPosData?.defaults?.[leftHandProp];\n                } else {\n                    return mainPosData.defaults[leftHandProp];\n                }\n            } else if (mainPosData.landscape?.[prop] !== undefined || featPosData?.landscape?.[prop] !== undefined) {\n                if (featPosData?.landscape?.[prop] !== undefined) {\n                    return featPosData?.landscape?.[prop] as unknown as T[K];\n                } else {\n                    return mainPosData.landscape?.[prop] as unknown as T[K];\n                }\n            } else {\n                if (featPosData?.defaults?.[prop] !== undefined) {\n                    return featPosData?.defaults[prop] as T[K];\n                } else {\n                    return mainPosData.defaults[prop] as T[K];\n                }\n            }\n        } else if (Core.ORIENTATION.value.isPortrait && (mainPosData.portrait || featPosData?.portrait)) {\n            if (featPosData?.portrait?.[prop] !== undefined) {\n                return featPosData.portrait[prop] as unknown as T[K];\n            } else if (mainPosData?.portrait?.[prop] !== undefined) {\n                return mainPosData.portrait[prop] as unknown as T[K];\n            } else if (featPosData?.defaults?.[prop] !== undefined) {\n                return featPosData.defaults[prop] as T[K];\n            } else {\n                return mainPosData.defaults[prop] as T[K];\n            }\n        } else {\n            // fallback for missing values\n            if (featPosData?.defaults?.[prop] !== undefined) {\n                return featPosData.defaults[prop] as T[K];\n            } else {\n                return mainPosData.defaults[prop] as T[K];\n            }\n        }\n    }\n\n    public replacePositionData(\n        dataNew: IModifiedDynamicPosition<T>,\n        data: DynamicPositionObject<T>,\n        overrideContext?: IOverrideRuntimeContext,\n    ): void {\n        if (overrideContext?.overrideType === 'ModifyValue' && this.shouldReportRedundantOverrides()) {\n            this.reportRedundantModifyValues(dataNew, data, overrideContext);\n        }\n\n        const posData = data.positionData;\n        for (const key in dataNew) {\n            if (posData[key]) {\n                if (key === 'features' || key === 'components') {\n                    for (const featureKey in dataNew[key]) {\n                        if (posData[key]?.[featureKey]) {\n                            // @ts-ignore\n                            for (const orientationKey in dataNew?.[key][featureKey]) {\n                                if (posData[key]?.[featureKey]?.[orientationKey]) {\n                                    // @ts-ignore\n                                    posData[key][featureKey][orientationKey] = Object.assign(\n                                        posData?.[key]?.[featureKey][orientationKey],\n                                        // @ts-ignore\n                                        dataNew[key][featureKey][orientationKey],\n                                    );\n                                } else {\n                                    // @ts-ignore\n                                    posData[key][featureKey][orientationKey] = dataNew[key][featureKey][orientationKey];\n                                }\n                            }\n                        } else {\n                            // @ts-ignore\n                            posData[key][featureKey] = dataNew[key][featureKey];\n                        }\n                    }\n                } else {\n                    posData[key] = Object.assign(posData[key], dataNew[key]);\n                }\n            } else {\n                posData[key] = dataNew[key];\n            }\n        }\n        this.positionData = posData;\n    }\n\n    public overrideDefaultProperties(\n        dataNew: IDynamicPosition<T>,\n        data: DynamicPositionObject<T>,\n        overrideContext?: IOverrideRuntimeContext,\n    ): void {\n        if (overrideContext?.overrideType === 'OverrideDefaultProperties' && this.shouldReportRedundantOverrides()) {\n            this.reportRedundantOverrideDefaultProperties(dataNew, data, overrideContext);\n        }\n\n        const posData = data.positionData;\n        Object.keys(dataNew).forEach((key) => {\n            Object.keys(posData).forEach((orientation) => {\n                if (orientation !== 'defaults') {\n                    if (posData[orientation].hasOwnProperty(key)) {\n                        delete posData[orientation][key];\n                    }\n                } else {\n                    if (posData[orientation][key]) {\n                        posData[orientation][key] = dataNew[key];\n                    }\n                }\n            });\n        });\n        this.positionData = posData;\n    }\n\n    private getConfigIndex(\n        configs: Array<{\n            value: IModifiedDynamicPosition<T>;\n            priority: number;\n            priorityType: { feature: any; mode: any };\n            condition?: (obj: any) => boolean; // optional condtition\n        }>,\n    ): number {\n        let biggerPriority: number = -1;\n        let configIndex: number = -1;\n\n        for (let i: number = 0; i < configs.length; i++) {\n            const isComponent: boolean = Core.hasComponent(\n                configs[i].priorityType.feature,\n                configs[i].priorityType.mode,\n            );\n            const isFeature: boolean = Core.hasFeature(configs[i].priorityType.feature, configs[i].priorityType.mode);\n            // const isScratchComponent: boolean = Core.hasComponent(configs[i].priorityType.feature, configs[i].priorityType.mode);\n            // const isScratchFeature: boolean = Core.hasFeature(configs[i].priorityType.feature, configs[i].priorityType.mode);\n            // @ts-ignore\n            const isConditionMet: boolean = configs[i].condition ? configs[i].condition(this) : true; // Check condition\n\n            // biggerPriority <= configs[i].priority\n            // should be equal because if have priority for example for mystery in base configuration\n            // and in override game configuration and they are 2 you should take this from game configuration\n            // game configuration is added second in list with priority and will override firs\n            // I saw this problem for Game Logo Component\n            if ((isComponent || isFeature) && biggerPriority <= configs[i].priority && isConditionMet) {\n                biggerPriority = configs[i].priority;\n                configIndex = i;\n            }\n        }\n        return configIndex;\n    }\n\n    private getGameType(): 'Slot' | 'Scratch' {\n        if (Core.configuration.gameKey.indexOf('Slot') !== -1) {\n            return 'Slot';\n        } else {\n            return 'Scratch';\n        }\n    }\n\n    private shouldReportRedundantOverrides(): boolean {\n        const diagnosticsEnabled =\n            Core.configuration?.redundantOverrideReport === undefined\n                ? Core.configuration?.devTools\n                : Core.configuration?.redundantOverrideReport;\n\n        return Boolean(diagnosticsEnabled && Core.configuration?.gameKey?.indexOf('Slot') !== -1);\n    }\n\n    private reportRedundantModifyValues(\n        dataNew: IModifiedDynamicPosition<T>,\n        data: DynamicPositionObject<T>,\n        overrideContext: IOverrideRuntimeContext,\n    ): void {\n        const positionDataRecord = data.positionData as unknown as Record<string, unknown>;\n        RedundantOverrideInspector.inspectModifyValue(\n            dataNew as unknown as IModifiedDynamicPosition<unknown>,\n            positionDataRecord,\n            overrideContext,\n        );\n    }\n\n    private reportRedundantOverrideDefaultProperties(\n        dataNew: IDynamicPosition<T>,\n        data: DynamicPositionObject<T>,\n        overrideContext: IOverrideRuntimeContext,\n    ): void {\n        RedundantOverrideInspector.inspectOverrideDefaultProperties(\n            dataNew as unknown as IDynamicPosition<unknown>,\n            data.positionData as unknown as Record<string, unknown>,\n            overrideContext,\n        );\n    }\n}\n","import { utils } from 'pixi.js';\nimport Screenfull from 'screenfull';\nimport { injectable, singleton } from 'tsyringe';\nimport { UAParser } from 'ua-parser-js';\nimport Core, { AnalyticsDispatcher, Log } from './Core';\nimport ErrorTypes from './enums/ErrorTypes';\nimport { IEnvironment } from './interfaces/IEnvironment';\n\n@injectable()\n@singleton()\nexport default class Environment implements IEnvironment {\n    public fullScreenController: any;\n    public isIosBrowser: boolean; // if true - show animation\n    public customReactIsShown = false;\n    public touchDown: boolean = false;\n    private env: UAParser;\n    private isFullscreen: boolean = false;\n    private isiOSChrome: boolean;\n    private isiOSSafari: boolean;\n    private preventDefaultHandler: any;\n    private onResizetHandler: any;\n    private onTouchStartHandler: any;\n    private onScrollHandler: any;\n    private touchendHandler: any;\n    private visibilityChangeHandler: any;\n    private removeIOSHandHandler: any;\n    private targetTouchEndHandler: any;\n    private iosHelperAttached: boolean = false;\n    // true while setIOSFullscreen's fixed layout is applied - teardown only reverts what it set\n    // (CustomScaler also pins #app-root fixed on non-iOS devices)\n    private iosLayoutPinned: boolean = false;\n    // true while the canvas is shortened above Safari's bottom tap area (address bar at the top)\n    private bottomInsetApplied: boolean = false;\n    private _showHelperWhenAsked: boolean = true;\n    private checkFrame = 0;\n    private resizeSettleTimeout: any;\n    private snapTimeout: any;\n    private showHandTimeout: any;\n    private viewportProbe: { root: HTMLDivElement; large: HTMLDivElement; small: HTMLDivElement } | null = null;\n    private iosVersion = 0;\n    private browserCompatibilityErrorCode = 0;\n    private iosHandDismissed: boolean = false;\n    // ~9 frames: Safari reports the final innerHeight this long after a rotation\n    private static readonly RESIZE_SETTLE_DELAY = 150;\n    // longer than one toolbar toggle during rotation / swipe, so the hand does not flash\n    private static readonly SHOW_HAND_DELAY = 150;\n    // scroll events stopped this long -> the scroll has ended; the snap is invisible, so no need to hurry\n    private static readonly SNAP_DELAY = 100;\n    private static readonly SCROLL_SPACER_ID = 'ios-scroll-spacer';\n    private static readonly PINNED_IDS = ['loading-overlay', 'iOSFullscreen'];\n    // With the address bar at the top, a collapsed iPhone Safari has no bottom toolbar: a tap near the bottom\n    // edge is taken by Safari to bring the toolbars back and never reaches the game. Keep the game above it:\n    // the tap area is the bottom toolbar Safari brings back, this plus the home indicator (safe-area-inset-bottom).\n    private static readonly TOP_BAR_BOTTOM_INSET = 50;\n    // Fullscreen detection via observed innerHeight growth. Needed because\n    // Safari Private / Advanced Tracking Protection masks `window.screen.height`\n    // (e.g. reports 896 on an iPhone 15 whose real screen is 852), which breaks\n    // the `innerH / screen.height` ratio check.\n    private initialInnerHeight: { portrait: number; landscape: number } = { portrait: 0, landscape: 0 };\n    private maxInnerHeight: { portrait: number; landscape: number } = { portrait: 0, landscape: 0 };\n    // Safari hides its toolbar only on a user scroll, so heights before the first touch are not a baseline:\n    // in Private mode the \"advanced privacy protections\" banner shrinks the page while it loads and its\n    // disappearing looked like the toolbar collapsing.\n    private touchSeen: boolean = false;\n\n    constructor() {\n        this.env = new UAParser();\n        this.fullScreenController = Screenfull;\n        const browser = this.getBrowser();\n        this.isiOSChrome = this.getOS().name === 'iOS' && browser.name === 'Mobile Chrome';\n        this.isiOSSafari = browser.name === 'Mobile Safari' || browser.name === 'Safari';\n        this.isIosBrowser = this.isiOSSafari || this.isiOSChrome;\n        this.preventDefaultHandler = this.preventDefault.bind(this);\n        this.onResizetHandler = this.onResize.bind(this);\n        this.onTouchStartHandler = this.onTouchStart.bind(this);\n        this.onScrollHandler = this.onScroll.bind(this);\n        this.touchendHandler = this.requestFullscreen.bind(this);\n        this.visibilityChangeHandler = this.visibilityChange.bind(this);\n        this.removeIOSHandHandler = this.removeIOSHand.bind(this);\n        this.targetTouchEndHandler = this.onTargetTouchEnd.bind(this);\n        document.addEventListener('contextmenu', (event) => event.preventDefault());\n    }\n\n    /** false while an HTML popup (help, paytable, gift spins info) is open, so the hand does not cover it */\n    public get showHelperWhenAsked(): boolean {\n        return this._showHelperWhenAsked;\n    }\n\n    public set showHelperWhenAsked(value: boolean) {\n        const reopened = value && !this._showHelperWhenAsked;\n        this._showHelperWhenAsked = value;\n        // the popup may have scrolled the page or hidden a toolbar change - re-evaluate once it closes\n        if (reopened && this.iosHelperAttached) {\n            this.scheduleCheck();\n            this.scheduleSnap();\n        }\n    }\n\n    public isMobileIos(): boolean {\n        if (/(iPhone|iPod|iPad)/i.test(navigator.userAgent) || this.isIpad()) {\n            const v = navigator.appVersion.match(/OS (\\d+)_(\\d+)_?(\\d+)?/);\n            if (v) {\n                this.iosVersion = [parseInt(v[1], 10), parseInt(v[2], 10), parseInt(v[3], 10)][0];\n            } else if (this.isIpad()) {\n                // iPadOS 13+ sends a desktop UA (\"Intel Mac OS X 10_15_7\") that has no \"OS n_\" iOS version,\n                // so read the Safari version instead; without it assume 15 so showHelper() still honours\n                // showHelperWhenAsked instead of treating the iPad as pre-15.\n                const safari = navigator.userAgent.match(/Version\\/(\\d+)/);\n                this.iosVersion = safari ? parseInt(safari[1], 10) : 15;\n            }\n\n            return !this.isFullScreenSupported();\n        }\n        return false;\n    }\n\n    /**\n     * The page may be scrolled (iOS fullscreen helper, 25vh) or pinned for iOS, so DOM placed in body has to make\n     * up for it. Unlike isMobileIos() this includes iPads with Fullscreen API support while the helper runs.\n     */\n    public isIOSScrollLayout(): boolean {\n        return this.isMobileIos() || this.needsIOSFullscreenHelper();\n    }\n\n    public isIpad(): boolean {\n        if (this.getOS().name === 'macOS' && navigator.maxTouchPoints) {\n            return true;\n        }\n        return false;\n    }\n    /**\n     *\n     *\n     * @return {*}  {boolean}\n     * @memberof Environment\n     */\n    public isFullScreen(): boolean {\n        return window.innerHeight === screen.height;\n    }\n\n    /**\n     * return true if the app is started in frame\n     */\n    public inIframe(): boolean {\n        try {\n            return window.self !== window.top;\n        } catch (_e) {\n            return true;\n        }\n    }\n\n    /**\n     * Gets the browser\n     */\n    public getBrowser(): UAParser.IBrowser {\n        return this.env.getBrowser();\n    }\n\n    public getBrowserString(): string {\n        return `${this.getBrowser().name} ${this.getBrowser().major} ${this.getOS().name}`;\n    }\n\n    /**\n     * Gets the CPU information\n     */\n    public getCPU(): UAParser.ICPU {\n        return this.env.getCPU();\n    }\n\n    /**\n     * Gets the device information\n     */\n    public getDevice(): UAParser.IDevice {\n        return this.env.getDevice();\n    }\n\n    /*\n     * Gets the device information from navigator, it seems it is more accurate but only supported in Chrome/Android for now\n     */\n    public getDeviceHints():\n        | undefined\n        | Promise<{ model: string; platform: string; platformVersion: string; fullVersionList: string }> {\n        if (!('userAgentData' in navigator)) return;\n\n        try {\n            const hints = (window.navigator as any).userAgentData.getHighEntropyValues([\n                'model',\n                'platform',\n                'platformVersion',\n            ]);\n            return hints;\n        } catch {\n            return;\n        }\n    }\n\n    /**\n     * Gets the engine that host is using\n     */\n    public getEngine(): UAParser.IEngine {\n        return this.env.getEngine();\n    }\n\n    /**\n     * Gets the OS of the Host\n     */\n    public getOS(): UAParser.IOS {\n        return this.env.getOS();\n    }\n\n    /**\n     * Gets the User agent of the browser\n     */\n    public getUA(): string {\n        return this.env.getUA();\n    }\n\n    /**\n     * Gets the hole information about the host summed in one object\n     */\n    public getEnvironment(): UAParser.IResult {\n        return this.env.getResult();\n    }\n\n    public isFullScreenSupported(): boolean {\n        return Screenfull.isEnabled;\n    }\n\n    public getDeviceType(): 'mobile' | 'desktop' {\n        // iPad in Desktop browse has Useragent as Mac OS and then we check maxTouchPoints:\n        // Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.2 Safari/605.1.15\n        // iPad in non Desktop mode has Useragent as IPad:\n        // Mozilla/5.0 (iPad; CPU OS.....\n        if (\n            /Mobi/i.test(navigator.userAgent) ||\n            /Android/i.test(navigator.userAgent) ||\n            /(iPhone|iPod|iPad)/i.test(navigator.userAgent) ||\n            /BlackBerry/i.test(navigator.userAgent) ||\n            /Opera Mini/i.test(navigator.userAgent) ||\n            /IEMobile/i.test(navigator.userAgent) ||\n            (this.getOS().name === 'macOS' && navigator.maxTouchPoints)\n        ) {\n            return 'mobile';\n        }\n        return 'desktop';\n    }\n\n    // biome-ignore lint/correctness/noUndeclaredVariables: IUAParser is namespace from ua-parser-js\n    public fullScreenControl(): screenfull.Screenfull {\n        return this.fullScreenController;\n    }\n\n    /** used when game is loaded to add ios fullscreen animation if not aded yet */\n    public addMobileFullscreen(): void {\n        if (document.getElementById('iOSFullscreenAnimation') || Core.configuration.hideHandCursor) {\n            return;\n        }\n        this.isFullscreen = false;\n        // // TEMP DEBUG\n        // this.debug(`UA: ${navigator.userAgent}`);\n        // this.debugSnapshot('init');\n        if (this.needsIOSFullscreenHelper()) {\n            this.setIOSFullscreen();\n        }\n        this.addMobileFullscreenHelper();\n    }\n\n    public setIOSFullscreen(): void {\n        const app = document.getElementById('app-root');\n        const erros = document.getElementById('errors');\n        if (app) {\n            app.style.height = '150vh';\n            // Fixed: the page still scrolls (that is what collapses Safari's toolbar), but neither the\n            // swipe nor Safari's momentum scroll after it can move the game. Before, the game moved with\n            // the page and had to be scrolled back against the momentum, which made it shake.\n            app.style.position = 'fixed';\n            app.style.left = '0';\n            // Safari tints its bars from fixed elements at the screen edges. A transparent fixed #app-root gives it\n            // no colour, so it kept the last one it sampled (e.g. the blue custom-app overlay after closing it).\n            app.style.backgroundColor = 'black';\n            erros?.classList.add('IOS');\n        }\n        this.iosLayoutPinned = true;\n        // 100vh on iOS is the height with the toolbar fully retracted. With the address bar at the top,\n        // Safari never fully retracts it (e.g. 100vh = 844, visible = 753 in fullscreen, 645 with the toolbar),\n        // so the canvas was taller than the screen and the centred game sat too low. 100dvh follows the\n        // visible height; Stage notices the new canvas size on its next tick and re-lays out.\n        const canvas = document.getElementById('app-canvas');\n        if (canvas && window.CSS?.supports?.('height', '100dvh')) {\n            canvas.style.height = '100dvh';\n            // the next check re-applies the inset if the address bar is still at the top\n            this.bottomInsetApplied = false;\n        }\n        this.addScrollSpacer();\n        this.updateTopForElement('app-root', '0');\n        // everything visible is pinned like #app-root, so scrolling (and waiting for the momentum to end) is never seen\n        Environment.PINNED_IDS.forEach((id) => this.pinElement(id));\n        this.snapToGame();\n    }\n\n    public isBrowserFeaturesCompatible(): boolean | number {\n        this.browserCompatibilityErrorCode = 9000;\n        const testPassed: boolean = this.isWebglSupported() && this.isFetchSupported() && this.isCssgridSupported();\n        if (testPassed) {\n            return true;\n        } else {\n            const code = this.browserCompatibilityErrorCode;\n            AnalyticsDispatcher.sendErrorEvent(\n                ErrorTypes.BROWSER_NOT_SUPPORTED_ERROR,\n                'browser is not supported',\n                `One of Webgl: ${this.isWebglSupported()} , Fetch: ${this.isFetchSupported()}, CSSGRID: ${this.isCssgridSupported()} `,\n            );\n            return code;\n        }\n    }\n\n    public removeIOSFullscreen(): void {\n        if (this.iosLayoutPinned) {\n            this.iosLayoutPinned = false;\n            const app = document.getElementById('app-root');\n            if (app) {\n                // back to the absolute 150vh layout the lobby keeps scrolling on\n                app.style.position = 'absolute';\n                app.style.backgroundColor = '';\n            }\n            document.getElementById(Environment.SCROLL_SPACER_ID)?.remove();\n            Environment.PINNED_IDS.forEach((id) => this.unpinElement(id));\n            const canvas = document.getElementById('app-canvas');\n            if (canvas) {\n                canvas.style.height = '';\n            }\n            this.bottomInsetApplied = false;\n        }\n        document.body.style.height = '100vh';\n        this.updateTopForElement('app-root', '0');\n        this.updateTopForElement('loading-overlay', '0');\n        this.updateTopForElement('ios-hand-close', '0');\n        window.scrollTo(0, 0);\n    }\n\n    /** used when is in portal to not use ios hand for full screen */\n    public removeMobileFullscreen(): void {\n        document.getElementById('ios-hand-close')?.removeEventListener('click', this.removeIOSHandHandler);\n        const el = document.getElementById('iOSFullscreenAnimation') as HTMLDivElement;\n        if (el) {\n            el.parentElement?.removeChild(el);\n            const el2 = document.getElementById('iOSFullscreen') as HTMLDivElement;\n            el2.parentElement?.removeChild(el2);\n        }\n        this.removeIOSFullscreen();\n        this.iosHelperAttached = false;\n        // the document touchend listener is removed below, so a touch in progress would never reset it\n        this.touchDown = false;\n        cancelAnimationFrame(this.checkFrame);\n        this.checkFrame = 0;\n        clearTimeout(this.resizeSettleTimeout);\n        clearTimeout(this.snapTimeout);\n        clearTimeout(this.showHandTimeout);\n        this.showHandTimeout = undefined;\n        this.viewportProbe?.root.parentElement?.removeChild(this.viewportProbe.root);\n        this.viewportProbe = null;\n        window.removeEventListener('resize', this.onResizetHandler);\n        document.removeEventListener('touchstart', this.onTouchStartHandler);\n        document.removeEventListener('scroll', this.onScrollHandler);\n        document.removeEventListener('gesturestart', this.preventDefaultHandler);\n        document.removeEventListener('gesturechange', this.preventDefaultHandler);\n        document.removeEventListener('gestureend', this.preventDefaultHandler);\n        document.removeEventListener('touchend', this.touchendHandler);\n        document.removeEventListener('visibilitychange', this.visibilityChangeHandler);\n        document.removeEventListener('fullscreenchange', this.onResizetHandler);\n        document.removeEventListener('webkitfullscreenchange', this.onResizetHandler);\n    }\n\n    public testBrowserCompatibility(): boolean {\n        let testPassed: boolean = false;\n\n        const brwoserSupport = {\n            Windows: {\n                Chrome: 57,\n                Firefox: 16,\n                Edge: 91,\n                Opera: 44,\n            },\n            Android: {\n                'Samsung Browser': 14,\n                Chrome: 92,\n                'MIUI Browser': 12,\n                Firefox: 90,\n            },\n            iOS: {\n                'Mobile Safari': 11,\n                Chrome: 91,\n            },\n            macOS: {\n                Safari: 13,\n                Chrome: 91,\n            },\n        };\n        const osName = this.env.getOS().name as string;\n        const browserName = this.env.getBrowser().name as string;\n        const browserVer = Number(this.env.getBrowser().major || this.env.getBrowser().version);\n        const os = brwoserSupport[osName];\n        if (os !== undefined) {\n            const minVersion = os[browserName];\n            if (minVersion !== undefined) {\n                testPassed = browserVer >= minVersion;\n            }\n        }\n        // console.log('Browser Compatibility', testPassed, osName, browserName, browserVer);\n        return testPassed;\n    }\n\n    private requestFullscreen(e: any) {\n        // this.debug(`*** touchend ${e?.type}`);\n        if (!Core.noSleep.isEnabled) {\n            this.activateNoSleep()\n                .then(() => {\n                    // Mute the video to prevent the Uncaught (in promise) DOMException: play() failed because the user didn't interact with the document first\n                    // This happens if the first interaction of the user is the mute icon\n                    // @ts-ignore\n                    if (Core.noSleep.noSleepVideo) {\n                        // @ts-ignore\n                        Core.noSleep.noSleepVideo.muted = true;\n                    }\n                })\n                .catch((error) => {\n                    Log.warn('No sleep error:', error);\n                });\n        }\n\n        // iPad Safari has its own fullscreen (the toolbar collapses on scroll): where the hand helper runs, the\n        // app is stretched over the visible screen (fixed #app-root, 100dvh canvas) instead of the Fullscreen API\n        const helperFullscreen = this.isIpadDevice() && this.needsIOSFullscreenHelper();\n        if (!this.isFullScreen() && this.isFullScreenSupported() && !helperFullscreen) {\n            const elem = document.documentElement;\n            if (elem.requestFullscreen) {\n                elem.requestFullscreen();\n                // @ts-ignore\n            } else if (elem.mozRequestFullScreen) {\n                /* Firefox */\n                // @ts-ignore\n                elem.mozRequestFullScreen();\n                // @ts-ignore\n            } else if (elem.webkitRequestFullscreen) {\n                /* Chrome, Safari & Opera */\n                // disable fullscreen for iPad becuase\n                // https://jira.egt-digital.com/browse/ON-5492 (Pad7 - Safari - Lobby scrolling shows last played game for a while)\n                // https://jira.egt-digital.com/browse/ON-5414 (Multi Tapping in fullscreen)\n                // iPad in desktop mode is recognized as Mac OS but has maxTouchPoints\n                /* if (!(this.getOS().name === 'Mac OS' && navigator.maxTouchPoints)) {\n                        // @ts-ignore\n                        elem.webkitRequestFullscreen();\n                    } */\n                // @ts-ignore\n            } else if (elem.msRequestFullscreen) {\n                /* IE/Edge */\n                // @ts-ignore\n                elem.msRequestFullscreen();\n            }\n        }\n        // Always release the touch. It used to be skipped in the requestFullscreen branch (iPad), which left\n        // touchDown stuck at true, so every later resize / scroll check was ignored and the hand never hid.\n        this.touchDown = false;\n        this.onScroll(e);\n    }\n\n    private preventDefault(a): void {\n        a.preventDefault();\n        a.stopPropagation();\n    }\n\n    private checkFullscreenIOS(): void {\n        if (!this.needsIOSFullscreenHelper()) {\n            return;\n        }\n        const collapsed = this.isToolbarCollapsed();\n        this.updateBottomInset(collapsed);\n        // this.debug(\n        //     `*** check collapsed=${collapsed} api=${!!(document.fullscreenElement || (document as any).webkitFullscreenElement)}`,\n        // );\n        if (collapsed) {\n            // entering fullscreen is applied immediately\n            clearTimeout(this.showHandTimeout);\n            this.showHandTimeout = undefined;\n            if (!this.isFullscreen) {\n                // this.debug('-> enter FULLSCREEN');\n                this.isFullscreen = true;\n                this.hide('iOSFullscreenAnimation');\n\n                const el = this.hide('iOSFullscreen');\n                if (el && this.isiOSSafari) {\n                    el.style.height = '104vh';\n                }\n            }\n        } else if (this.isFullscreen && this.showHelper() && !this.showHandTimeout) {\n            // Safari toggles the toolbar several times while rotating or while the swipe settles.\n            // Show the hand only when \"not fullscreen\" is still true after it has settled, otherwise it flickers.\n            this.showHandTimeout = setTimeout(() => {\n                this.showHandTimeout = undefined;\n                // this.debug('*** show-hand timer');\n                if (!this.iosHelperAttached || this.touchDown || !this.isFullscreen || !this.showHelper()) {\n                    return;\n                }\n                if (this.isToolbarCollapsed()) {\n                    return;\n                }\n                // this.debug('-> exit FULLSCREEN');\n                this.isFullscreen = false;\n                this.show('iOSFullscreenAnimation');\n                const el = this.show('iOSFullscreen');\n                if (el && this.isiOSSafari) {\n                    el.style.height = '102vh';\n                    el.style.zIndex = '1000';\n                }\n            }, Environment.SHOW_HAND_DELAY);\n        }\n    }\n\n    /**\n     * Shortens the canvas by TOP_BAR_BOTTOM_INSET while iPhone Safari has its address bar at the top, so the\n     * buttons at the bottom of the game stay clickable. That layout never retracts the toolbar completely, so a\n     * collapsed viewport that is still clearly below 100lvh means the address bar is at the top. Decided only\n     * when collapsed (both layouts look alike with the toolbar shown) and kept until the orientation changes.\n     */\n    private updateBottomInset(collapsed: boolean): void {\n        const canvas = document.getElementById('app-canvas');\n        if (!canvas || !this.iosLayoutPinned || !window.CSS?.supports?.('height', '100dvh')) {\n            return;\n        }\n        let inset = this.bottomInsetApplied;\n        const portrait = window.innerHeight > window.innerWidth;\n        if (!portrait || this.isIpadDevice()) {\n            inset = false;\n        } else if (collapsed) {\n            const probe = this.getViewportProbe();\n            inset = !!probe && probe.large.offsetHeight - window.innerHeight > 20;\n        }\n        if (inset !== this.bottomInsetApplied) {\n            this.bottomInsetApplied = inset;\n            // Stage re-lays out the game on its next tick from the canvas size\n            canvas.style.height = inset\n                ? `calc(100dvh - ${Environment.TOP_BAR_BOTTOM_INSET}px - env(safe-area-inset-bottom, 0px))`\n                : '100dvh';\n        }\n    }\n\n    private isToolbarCollapsed(): boolean {\n        // Fullscreen API entered some other way (e.g. the fullscreen button)\n        if (document.fullscreenElement || (document as any).webkitFullscreenElement) {\n            return true;\n        }\n        // Always evaluated so the observed heights stay up to date. Catches toolbars that shrink but do not\n        // fully retract (iPad Safari keeps a slim bar), which never reach 100lvh.\n        const observed = this.isToolbarCollapsedByObservedGrowth();\n        const byUnits = this.isToolbarCollapsedByViewportUnits();\n        return (byUnits ?? this.isToolbarCollapsedByHeuristics()) || observed;\n    }\n\n    /** the URL bar was observed to hide (innerH grew >20px from initial) and we are at/near that maximum */\n    private isToolbarCollapsedByObservedGrowth(): boolean {\n        // Works regardless of screen masking (Safari Private / Advanced Tracking Protection).\n        const key: 'portrait' | 'landscape' = window.innerHeight > window.innerWidth ? 'portrait' : 'landscape';\n        const currentH = window.innerHeight;\n        if (!this.touchSeen) {\n            return false;\n        }\n        // the lowest height seen is the toolbar-shown one, also after rotating while collapsed\n        if (this.initialInnerHeight[key] === 0 || currentH < this.initialInnerHeight[key]) {\n            this.initialInnerHeight[key] = currentH;\n        }\n        if (currentH > this.maxInnerHeight[key]) {\n            this.maxInnerHeight[key] = currentH;\n        }\n        return this.maxInnerHeight[key] - this.initialInnerHeight[key] > 20 && currentH >= this.maxInnerHeight[key] - 2;\n    }\n\n    /**\n     * `100lvh` is the viewport height with Safari's toolbars retracted - exactly the fullscreen state.\n     * Unlike `screen.height` it is not masked in Private mode / Advanced Tracking Protection and\n     * page zoom scales it together with innerHeight, so no per-device ratios are needed.\n     * Returns undefined when the browser does not expose distinct large/small viewports (iOS < 15.4).\n     */\n    private isToolbarCollapsedByViewportUnits(): boolean | undefined {\n        const probe = this.getViewportProbe();\n        if (!probe) {\n            return undefined;\n        }\n        const large = probe.large.offsetHeight;\n        const small = probe.small.offsetHeight;\n        if (large - small < 20) {\n            return undefined;\n        }\n        if (this.isIpadDevice()) {\n            // iPad Safari's minimized toolbar does not always reach 100lvh: it can settle just a few px past the\n            // fully shown height (e.g. svh 1094, minimized 1101 or 1126). Anything clearly above 100svh is minimized.\n            return window.innerHeight > small + 4;\n        }\n        return window.innerHeight >= large - 4;\n    }\n\n    private getViewportProbe(): { root: HTMLDivElement; large: HTMLDivElement; small: HTMLDivElement } | null {\n        if (this.viewportProbe) {\n            return this.viewportProbe;\n        }\n        if (!window.CSS?.supports?.('height', '100lvh')) {\n            return null;\n        }\n        const root = document.createElement('div');\n        root.id = 'ios-viewport-probe';\n        root.style.cssText =\n            'position:fixed;top:0;left:0;width:0;height:0;overflow:hidden;visibility:hidden;pointer-events:none';\n        const large = document.createElement('div');\n        large.style.height = '100lvh';\n        const small = document.createElement('div');\n        small.style.height = '100svh';\n        root.appendChild(large);\n        root.appendChild(small);\n        document.body.appendChild(root);\n        this.viewportProbe = { root, large, small };\n        return this.viewportProbe;\n    }\n\n    /** fallback for browsers without `lvh` / `svh` */\n    private isToolbarCollapsedByHeuristics(): boolean {\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        let a: number;\n        let d;\n        let verticalOfset = 0.9;\n        if (window.innerHeight > window.innerWidth) {\n            // portrait\n            a = Math.min(window.screen.width, window.screen.height);\n            d = Math.max(window.screen.width, window.screen.height);\n            verticalOfset = 0.87;\n            if (this.getBrowser().name === 'Mobile Safari' && this.getBrowser().major === '26') {\n                verticalOfset = 0.86;\n            }\n\n            if (this.isIpadDevice()) {\n                // IPAD SAFARI // IPAD CHROME\n                verticalOfset = 0.95;\n            } else if (/(iPhone)/i.test(navigator.userAgent) && this.isiOSChrome) {\n                // IPHONE CHROME\n                verticalOfset = 0.91;\n            }\n        }\n\n        if (window.innerWidth > window.innerHeight) {\n            a = Math.max(window.screen.width, window.screen.height);\n            d = Math.min(window.screen.width, window.screen.height);\n        }\n        // This rounds calculate value to 2-nd decimal\n        const val = Math.round((window.innerHeight / d) * 100) / 100;\n        // adjust the coeficient based on the page zoom\n        verticalOfset = this.calulateOffsetBasedOnPageZoom(verticalOfset, this.getPageZoomPercent());\n        // Primary (screen-based) condition. Fails when Safari Private / ATP masks screen.height.\n        const screenCond = d === window.innerHeight || val >= verticalOfset;\n\n        // TEMP DEBUG: core inputs of the fullscreen decision\n        // this.debug(\n        //     `CHECK d=${d} innerH=${window.innerHeight} val=${val} off=${verticalOfset} ` +\n        //         `screenCond=${screenCond} isFS=${this.isFullscreen} showHelper=${this.showHelper()}`,\n        // );\n        return screenCond;\n    }\n\n    private calulateOffsetBasedOnPageZoom(baseCoef: number, procentageZoom: number): number {\n        const levels = [100, 115, 125, 150, 175];\n        const idx = levels.indexOf(procentageZoom);\n        if (idx === -1) return baseCoef;\n        const stepsMax = levels.length - 1; // 4 steps beyond 100%\n        const minAtMaxZoom = 0.3; // target at 175%\n        const delta = (baseCoef - minAtMaxZoom) * (idx / stepsMax);\n        const result = baseCoef - delta;\n        return result;\n    }\n\n    private addMobileFullscreenHelper(): void {\n        const _browser: any = this.getBrowser();\n        if (Core.configuration.hideHandCursor) {\n            // DO NOT PUT DOWN IN IF BECAUSE DON'T ADD NO IOS AND NO ANDROID EVENTS\n            return;\n        }\n        if (this.needsIOSFullscreenHelper()) {\n            const c = `\n            <svg class=\"full-screen-hand\" style=\"display: inherit\">\n                    <g id=\"Artboard\" transform=\"translate(-43.000000, -44.000000)\" fill=\"#E8E8E8\" fill-rule=\"nonzero\">\n                        <path d=\"M54.0888672,44.2789912 C56.1064453,44.7343558 56.8219819,45.5691478 58.2626363,46.7136733 C60.3227722,48.3538407 61.3000161,50.7171184 62.5605887,52.8840548 C66.5968222,59.8278291 70.5826328,66.7907586 74.6020587,73.7393216 C74.7605307,74.0170726 74.8973929,74.5007424 75.3536001,74.3546837 C75.7425768,74.232569 75.5288797,73.8015761 75.5745004,73.5118532 C75.9346704,71.0048595 77.3955873,68.7879917 79.560311,67.4635863 C83.5965445,64.877629 90.2019451,66.2663839 92.8239362,71.3185782 C93.0376332,71.7328103 93.2057096,72.1877472 93.7699659,72.5157807 C94.4710844,68.0909204 96.6128573,64.8034025 101.282979,64.2071957 C106.930344,63.4888742 110.279866,66.728504 112.582512,71.5197083 C112.844231,69.7239046 113.26202,68.0669764 114.212852,66.6255446 C116.746003,62.7944968 121.437734,62.0043431 125.322699,63.6445105 C127.742999,64.664527 129.282098,66.5177964 130.561879,68.7517762 C136.999203,80.0054793 143.506159,91.2304495 149.984302,102.467392 C151.869158,105.73336 154.078162,108.836509 155.326729,112.432905 C158.304081,121.009663 157.353249,129.102752 152.111668,136.587662 C150.241219,139.257423 147.69126,141.189708 144.874781,142.813115 C138.631945,146.404722 132.389109,150.046612 126.146273,153.61667 C120.731814,156.703058 115.053234,156.461223 109.300221,154.761195 C104.349172,153.298214 99.8615331,150.769722 95.2034171,148.631519 C83.5341162,143.275235 71.6415138,138.440931 59.7993344,133.489302 C53.6429378,130.915317 51.2010285,123.523789 54.8218733,118.356663 C57.2373706,114.911114 61.960316,113.74025 65.8020612,115.483377 C70.8323463,117.767639 75.9178564,119.929787 80.9793556,122.147006 C81.1234211,122.20926 81.2578822,122.31222 81.4595738,122.147006 C77.5457959,115.385206 73.6304173,108.618618 69.713438,101.847241 C61.4568874,87.6021279 53.198736,73.3594094 44.9389839,59.1190852 C44.305096,58.0248422 43.9521356,56.8180621 43.3758739,55.7046638 C42.8747087,53.8242578 42.8747087,51.9551878 43.3758739,50.0974538 C44.1276216,47.3108529 45.7793094,46.1130144 47.180102,45.060318 C49.3335802,43.8236266 52.0712891,43.8236266 54.0888672,44.2789912 Z\"\n                            id=\"hand\">\n                        </path>\n                    </g>\n                </svg>`;\n            const closeBtn = `<div id=\"ios-hand-close\" style=\"top: 0px;\"><svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path d=\"m14.74 12 8.69-8.69c.76-.76.76-1.99 0-2.74-.76-.76-1.99-.76-2.74 0l-8.69 8.69-8.69-8.69c-.76-.76-1.98-.76-2.74 0-.76.76-.76 1.98 0 2.74l8.69 8.69-8.69 8.69c-.76.76-.76 1.99 0 2.74s1.99.76 2.74 0l8.69-8.69 8.69 8.69c.76.76 1.99.76 2.74 0s.76-1.99 0-2.74z\"></path></svg></div>`;\n            if (this.showHelper() && !this.iosHandDismissed) {\n                this.addElementFromHTML('iOSFullscreen', closeBtn);\n                this.addElementFromHTML('iOSFullscreenAnimation', c);\n                const hand = document.getElementById('iOSFullscreenAnimation');\n                const closeBtnElement = document.getElementById('ios-hand-close');\n                if (closeBtnElement) {\n                    closeBtnElement.addEventListener('click', this.removeIOSHandHandler);\n                }\n                if (hand) {\n                    hand.style.zIndex = '1000';\n\n                    this.setIOSFullscreen();\n                }\n            }\n\n            this.iosHelperAttached = true;\n            window.addEventListener('resize', this.onResizetHandler);\n            // Safari makes document touch listeners passive anyway - blocking touchstart would also block the swipe to fullscreen\n            document.addEventListener('touchstart', this.onTouchStartHandler, { passive: true });\n            document.addEventListener('scroll', this.onScrollHandler);\n            document.addEventListener('gesturestart', this.preventDefaultHandler);\n            document.addEventListener('gesturechange', this.preventDefaultHandler);\n            document.addEventListener('gestureend', this.preventDefaultHandler);\n            document.addEventListener('touchend', this.touchendHandler);\n            document.addEventListener('visibilitychange', this.visibilityChangeHandler);\n            document.addEventListener('fullscreenchange', this.onResizetHandler);\n            document.addEventListener('webkitfullscreenchange', this.onResizetHandler);\n            this.onResize({});\n        } else {\n            if (this.getDeviceType() === 'mobile') {\n                document.addEventListener('touchstart', this.onTouchStartHandler, { passive: true });\n                document.addEventListener('touchend', this.touchendHandler);\n            }\n            // document.addEventListener('mouseup', this.requestFullscreen.bind(this));\n        }\n    }\n\n    private showHelper(): boolean {\n        return this.showHelperWhenAsked || Core.ORIENTATION.value.isLandscape || this.iosVersion < 15;\n    }\n\n    private onResize(_e: any): void {\n        // this.debug('*** resize');\n        // this.checkFullscreenIOS();\n        // e.preventDefault()\n        if (this.touchDown) {\n            return;\n        }\n        this.scheduleCheck();\n        // Safari reports the final innerHeight only after the rotation / toolbar animation has finished\n        clearTimeout(this.resizeSettleTimeout);\n        this.resizeSettleTimeout = setTimeout(() => {\n            this.checkFullscreenIOS();\n            this.scheduleSnap();\n        }, Environment.RESIZE_SETTLE_DELAY);\n    }\n\n    private onScroll(_e: any): void {\n        // this.debug('*** Scroll');\n        // e.preventDefault()\n        if (this.touchDown) {\n            return;\n        }\n        this.scheduleCheck();\n        this.scheduleSnap();\n    }\n\n    /** runs checkFullscreenIOS at most once per frame */\n    private scheduleCheck(): void {\n        // a touchend on a detached popup button can still arrive after removeMobileFullscreen()\n        if (!this.iosHelperAttached) {\n            return;\n        }\n        if (this.checkFrame) {\n            return;\n        }\n        this.checkFrame = requestAnimationFrame(() => {\n            this.checkFrame = 0;\n            this.checkFullscreenIOS();\n        });\n    }\n\n    /**\n     * Puts the page back in the middle of its scroll range once scrolling has ended, so there is\n     * always room for the next swipe. #app-root is fixed, so this is invisible and never fights\n     * Safari's momentum scroll.\n     */\n    private scheduleSnap(): void {\n        if (!this.iosHelperAttached) {\n            return;\n        }\n        clearTimeout(this.snapTimeout);\n        this.snapTimeout = setTimeout(() => {\n            // a pending touchend calls onScroll again, which snaps then\n            if (!this.touchDown) {\n                this.snapToGame();\n            }\n        }, Environment.SNAP_DELAY);\n    }\n\n    private snapToGame(): void {\n        const spacer = document.getElementById(Environment.SCROLL_SPACER_ID);\n        // the spacer starts at 25vh - the scroll position the layout (loading overlay, hand close button) is built for\n        const top = spacer\n            ? Math.round(spacer.getBoundingClientRect().top + window.scrollY)\n            : window.innerHeight * 0.25;\n        if (Math.abs(window.scrollY - top) > 1) {\n            // this.debug(`*** snap -> ${top}`);\n            window.scrollTo(0, top);\n        }\n    }\n\n    private pinElement(id: string): void {\n        const el = document.getElementById(id);\n        if (el) {\n            el.style.position = 'fixed';\n            el.style.top = '0';\n            el.style.left = '0';\n        }\n    }\n\n    private unpinElement(id: string): void {\n        const el = document.getElementById(id);\n        if (el && el.style.position === 'fixed') {\n            // back to the stylesheet (absolute)\n            el.style.position = '';\n            el.style.top = '0';\n        }\n    }\n\n    /** keeps the page scrollable (25vh + 150vh, as with the old absolute #app-root) while #app-root is fixed */\n    private addScrollSpacer(): void {\n        if (document.getElementById(Environment.SCROLL_SPACER_ID)) {\n            return;\n        }\n        const spacer = document.createElement('div');\n        spacer.id = Environment.SCROLL_SPACER_ID;\n        spacer.style.cssText =\n            'position:absolute;top:25vh;left:0;width:1px;height:150vh;visibility:hidden;pointer-events:none';\n        document.body.appendChild(spacer);\n    }\n\n    private visibilityChange(): void {\n        if (document.hidden) {\n            this.touchDown = false;\n        }\n    }\n\n    private removeIOSHand(): void {\n        this.iosHandDismissed = true;\n        const closeBtnElement = document.getElementById('ios-hand-close');\n        if (closeBtnElement) {\n            closeBtnElement.removeEventListener('click', this.removeIOSHandHandler);\n        }\n        const el = document.getElementById('iOSFullscreenAnimation') as HTMLDivElement;\n        if (el && el.parentElement) {\n            el.parentElement.removeChild(el);\n        }\n        const el2 = document.getElementById('iOSFullscreen') as HTMLDivElement;\n        if (el2 && el2.parentElement) {\n            el2.parentElement.removeChild(el2);\n        }\n\n        this.snapToGame();\n    }\n\n    private onTouchStart(a: TouchEvent): void {\n        // this.debug('*** touchstart');\n        this.touchDown = true;\n        if (!this.touchSeen) {\n            // before the first swipe the toolbar is shown - start the observed growth from here\n            this.touchSeen = true;\n            const key: 'portrait' | 'landscape' = window.innerHeight > window.innerWidth ? 'portrait' : 'landscape';\n            this.initialInnerHeight = { portrait: 0, landscape: 0 };\n            this.maxInnerHeight = { portrait: 0, landscape: 0 };\n            this.initialInnerHeight[key] = window.innerHeight;\n            this.maxInnerHeight[key] = window.innerHeight;\n        }\n        // Keep window from seeing touchstart outside fullscreen, as before: Core.onTouchEvent would otherwise\n        // turn on #multitouchprotect, and only a window touchend turns it off. preventDefault is not possible\n        // in this passive listener, stopPropagation is.\n        if (!this.isFullscreen) {\n            a.stopPropagation();\n        }\n        // Popups (gift spins info, help...) close on touchstart and remove their button from the DOM.\n        // A touchend on a detached element never bubbles to document, so touchDown would stay true\n        // and every resize / scroll check would be skipped. Listen on the target itself as well.\n        const target = a.target;\n        if (target instanceof Node) {\n            target.addEventListener('touchend', this.targetTouchEndHandler);\n            target.addEventListener('touchcancel', this.targetTouchEndHandler);\n        }\n    }\n\n    private onTargetTouchEnd(e: TouchEvent): void {\n        const target = e.currentTarget as Node;\n        target.removeEventListener('touchend', this.targetTouchEndHandler);\n        target.removeEventListener('touchcancel', this.targetTouchEndHandler);\n        if (e.type === 'touchcancel') {\n            this.touchDown = false;\n            this.onScroll(e);\n        } else if (!target.isConnected) {\n            // still attached -> the document touchend listener handles it\n            this.requestFullscreen(e);\n        }\n    }\n\n    private needsIOSFullscreenHelper(): boolean {\n        // iPads are included although they report Fullscreen API support: like on iPhone, the hand asks for the\n        // swipe that collapses Safari's toolbar and the app is stretched over the visible screen; the Fullscreen\n        // API is not requested here (requestFullscreen). Kept out of isMobileIos() so the lobby and other\n        // callers keep their non-iOS path on iPads with Fullscreen API support.\n        return (this.isMobileIos() || this.isIpadDevice()) && !this.inIframe() && !this.isStandalone();\n    }\n\n    /** iPad with either UA: \"iPad\" or the desktop one iPadOS 13+ sends by default */\n    private isIpadDevice(): boolean {\n        return this.isIpad() || /(iPad)/i.test(navigator.userAgent);\n    }\n\n    /** started from the home screen - there is no browser toolbar to hide */\n    private isStandalone(): boolean {\n        return (navigator as any).standalone === true || window.matchMedia?.('(display-mode: standalone)').matches;\n    }\n\n    // create div with id and add it after boddy\n    private addElementFromHTML(id: string, html: string): HTMLElement {\n        const div = document.createElement('div');\n        div.id = id;\n        div.innerHTML = html.trim();\n        div.classList.add('noselect');\n        document.body.insertAdjacentElement('afterbegin', div);\n        return div;\n    }\n\n    private hide(id: string): HTMLElement | null {\n        const el = document.getElementById(id);\n        if (el) {\n            el.style.display = 'none';\n        }\n        return el;\n    }\n\n    private show(id: string): HTMLElement | null {\n        const el = document.getElementById(id);\n        if (el) {\n            el.style.display = 'unset';\n        }\n        return el;\n    }\n\n    private isWebglSupported(): boolean {\n        this.browserCompatibilityErrorCode = 9001;\n        return utils.isWebGLSupported();\n    }\n\n    private isFetchSupported(): boolean {\n        this.browserCompatibilityErrorCode = 9003;\n        const testPassed: boolean = 'fetch' in window;\n        return testPassed;\n    }\n\n    private isCssgridSupported(): boolean {\n        this.browserCompatibilityErrorCode = 9002;\n        let testPassed: boolean = false;\n        try {\n            const div = document.createElement('div');\n            testPassed = typeof div.style.grid === 'string';\n        } catch (_e) {\n            testPassed = false;\n        }\n        // console.log('Feature CSS', testPassed);\n        return testPassed;\n    }\n    // TEMP DEBUG: overlay used to compare Safari Normal vs. Incognito / Advanced Tracking Protection.\n    // Remove this method and its call sites once the fullscreen-detection issue is resolved.\n    private debug(s: any): void {\n        let debugEl = document.getElementById('debug') as HTMLTextAreaElement;\n        if (!debugEl) {\n            const div = document.createElement('div');\n            div.id = 'debugContainer';\n            div.innerHTML = `\n                <textarea id='debug' readonly style='\n                    position: fixed;\n                    z-index: 99999;\n                    font-size: 11px;\n                    line-height: 1.3;\n                    bottom: 0;\n                    left: 0;\n                    width: 100vw;\n                    height: 30vh;\n                    margin: 0;\n                    padding: 4px 4px 4px 4px;\n                    background: rgba(0, 0, 0, 0.85);\n                    color: #0f0;\n                    font-family: monospace;\n                    white-space: pre;\n                    border: 0;\n                    -webkit-user-select: text;\n                    user-select: text;\n                    overflow: auto;\n                    pointer-events: auto;\n                '></textarea>\n                <button id='debugClear' style='\n                    position: fixed;\n                    z-index: 100000;\n                    bottom: calc(30vh - 4px);\n                    right: 4px;\n                    padding: 4px 10px;\n                    font-size: 12px;\n                    background: #900;\n                    color: #fff;\n                    border: 0;\n                    border-radius: 4px;\n                    cursor: pointer;\n                '>CLEAR</button>`;\n            document.body.insertAdjacentElement('afterbegin', div);\n            debugEl = document.getElementById('debug') as HTMLTextAreaElement;\n            const clearBtn = document.getElementById('debugClear');\n            if (clearBtn) {\n                clearBtn.addEventListener('click', (ev) => {\n                    ev.stopPropagation();\n                    if (debugEl) {\n                        debugEl.value = '';\n                    }\n                });\n            }\n        }\n        if (debugEl) {\n            const today = new Date();\n            const time =\n                today.getHours().toString().padStart(2, '0') +\n                ':' +\n                today.getMinutes().toString().padStart(2, '0') +\n                ':' +\n                today.getSeconds().toString().padStart(2, '0');\n            const msg = typeof s === 'string' ? s : JSON.stringify(s);\n            debugEl.value = `${time} ${msg}\\n${debugEl.value}`;\n        }\n    }\n\n    // TEMP DEBUG: logs a single snapshot of everything relevant to the fullscreen detection.\n    private debugSnapshot(tag: string): void {\n        const b = this.getBrowser();\n        const vv = window.visualViewport;\n        this.debug(\n            `[${tag}] inner=${window.innerWidth}x${window.innerHeight} ` +\n                `screen=${window.screen.width}x${window.screen.height} ` +\n                `vv=${vv ? `${Math.round(vv.width)}x${Math.round(vv.height)}@${vv.scale}` : 'n/a'} ` +\n                `browser=${b.name}/${b.version}(m${b.major}) ` +\n                `isMobileIos=${this.isMobileIos()} inIframe=${this.inIframe()} ` +\n                `isFS=${this.isFullscreen} iosV=${this.iosVersion}`,\n        );\n    }\n\n    private updateTopForElement(elementId, top): void {\n        const element = document.getElementById(elementId);\n        if (element) {\n            element.style.top = top;\n        }\n    }\n\n    private async activateNoSleep() {\n        if (!Core.noSleep.isEnabled) {\n            return Core.noSleep.enable();\n        }\n    }\n\n    private getPageZoomPercent() {\n        const vv = window.visualViewport;\n        const scale = vv?.scale;\n        if (typeof scale === 'number' && scale > 0) return Math.round(scale * 100);\n        return 100;\n    }\n}\n","import { gsap } from 'gsap';\nimport React from 'react';\nimport { flushSync } from 'react-dom';\nimport { createRoot, type Root } from 'react-dom/client';\nimport Core, { AnalyticsDispatcher, PostMessageDispatcher, Timers } from './Core';\nimport Maintenance from './components/Maintenance';\nimport Modal from './components/Modal';\nimport ErrorTypes from './enums/ErrorTypes';\nimport { IErrorData } from './interfaces/IErrorData';\nimport Log from './utils/Log';\n\n// Module-level cache (not an instance field): show/hide are subscribed unbound in Core.ts,\n// so `this` inside them is not the ErrorManager instance. A root must be created only once\n// per container and cannot be reused after unmount.\nlet errorsRoot: Root | null = null;\n\n// flushSync keeps the legacy synchronous commit: callers freeze the app (GAME_LOCK_ERROR)\n// or remove #app-root (MAINTENANCE) right after rendering.\nfunction renderIntoErrors(node: React.ReactElement): void {\n    errorsRoot ??= createRoot(document.getElementById('errors') as HTMLElement);\n    flushSync(() => {\n        errorsRoot!.render(node);\n    });\n}\n\nexport default class ErrorManager {\n    // TODO: rework after release - change help css to use em instead rem\n    // https://jira.egt-digital.com/browse/ON-13204\n    private currentRootFontSize: any;\n    public hide(): void {\n        if (Core.configuration.gameKey === '') {\n            document.body.style.removeProperty('overflow');\n        }\n        if (this.currentRootFontSize) {\n            document.documentElement.style.fontSize = this.currentRootFontSize;\n        }\n        Core.UI_BLOCKER.next(false);\n        Core.DISABLE_KEYBOARD_EVENTS.next(false);\n        errorsRoot?.unmount();\n        errorsRoot = null;\n    }\n\n\n    public show(e: IErrorData): void {\n        Log.error(e, this.constructor.name, e);\n        if (Core.configuration.gameKey === '') {\n            document.body.style.overflow = 'hidden';\n        }\n        this.currentRootFontSize = document.documentElement.style.fontSize;\n        document.documentElement.style.removeProperty('font-size');\n        Core.UI_BLOCKER.next(true);\n        Core.DISABLE_KEYBOARD_EVENTS.next(true);\n        // const hasButton =\n        //     (e.type === ErrorTypes.GAME_LOCK_ERROR && Core.configuration.closeUrl !== undefined) ||\n        //     e.type === ErrorTypes.BROWSER_NOT_SUPPORTED_ERROR ||\n        //     e.type === ErrorTypes.GAME_ERROR;\n        const hasButton = e.type !== ErrorTypes.CONNECTION_ERROR;\n        let errorMessage: string = '';\n        let buttonText;\n\n\n\n\n        if (e.errorName && Core.translator.hasTranslateFor(e.errorName)) {\n            errorMessage = Core.translator.translate(e.errorName);\n        } else if (Core.translator.hasTranslateFor(e.code)) {\n            errorMessage = Core.translator.translate(e.code);\n        } else {\n            errorMessage = Core.translator.translate('unhandledError');\n        }\n\n\n        errorMessage = errorMessage.replace('##ERROR_CODE##', e.code);\n        // errorMessage = errorMessage.replace('(##ERROR_CODE##)', '');\n\n        if (e.type === ErrorTypes.MAINTENANCE) {\n            const appNode = document.getElementById('app-root') as HTMLBodyElement\n            document.body.removeChild(appNode);\n\n            renderIntoErrors(<Maintenance\n                message={errorMessage} />);\n            return\n        }\n\n        if (hasButton) {\n            switch (e.type) {\n                case ErrorTypes.GAME_ERROR:\n                    buttonText = Core.translator.translate('ButErrorOK');\n                    break;\n                case ErrorTypes.LOBBY_ERROR:\n                    buttonText = Core.translator.translate('ButErrorOK');\n                    break;\n                default:\n                    buttonText = Core.translator.translate('ButErrorClose');\n            }\n        }\n        if (e.type === ErrorTypes.CONFIRMATION) {\n            errorMessage = e.code\n            buttonText = e.btnText;\n        } else {\n            AnalyticsDispatcher.sendErrorEvent(e.type, `code: ${e.code}`, errorMessage);\n            PostMessageDispatcher.errorMessageDisplayed();\n        }\n        renderIntoErrors(\n            <Modal\n                message={errorMessage}\n                heading={e.code}\n                hasButton={hasButton}\n                buttonText={buttonText}\n                errType={e.type}\n                hasConfirmButton={e.hasConfirmButton}\n                confirmButtonText={e.confirmButtonText}\n                callback={e.callback}\n            />,\n        );\n\n        if (e.type === ErrorTypes.GAME_LOCK_ERROR) {\n            Core.sounds.stopAll();\n            Core.sounds.reset();\n            gsap.globalTimeline.pause();\n            Timers.clearTimeoutAll();\n            Timers.clearIntervalAll();\n            Core.spineAnimations.unLoadSpineAnimations();\n            window.addEventListener(\n                'resize',\n                () => {\n                    const ticker = Core?.stage?.ticker;\n\n                    // Exit early if ticker is not available\n                    if (!ticker || typeof ticker.start !== 'function') {\n                        return;\n                    }\n\n                    // Restart the ticker\n                    ticker.start();\n\n                    // Update and stop ticker on next frame\n                    Timers.setTimeout(() => {\n                        if (ticker?.update) ticker.update(0);\n                        if (ticker?.stop) ticker.stop();\n                    }, 0);\n                },\n                false,\n            );\n        }\n    }\n}\n","import { Subject } from 'rxjs';\nimport { injectable, singleton } from 'tsyringe';\nimport Core from './Core';\nimport { IAsset } from './interfaces/IAsset';\nimport Log from './utils/Log';\n\n@injectable()\n@singleton()\nexport default class FontsLoader {\n    public readonly FONTS_LOADED = new Subject<any>();\n    private _fontAssets: IAsset[];\n\n    public get fontAssets(): IAsset[] {\n        return this._fontAssets;\n    }\n\n    constructor() {\n        this._fontAssets = [];\n        // Core.ON_GAME_UNLOADED.subscribe(this.reset.bind(this));\n    }\n\n    /**\n     * Adds provided assets to the asset queue.\n     * @param {[IAsset]} assets\n     */\n    public addAssets(assets: IAsset[]): this {\n        if (Core.configuration.resourcesRootDir !== '') {\n            Core.assets.getAssetsQueue().forEach((el) => {\n                if (Array.isArray(el.url)) {\n                    el.url = el.url.map((url) => this.replaceUrl(url));\n                } else {\n                    el.url = this.replaceUrl(el.url);\n                }\n            });\n        }\n        assets.forEach((asset) => this.addAsset(asset));\n        return this;\n    }\n\n    public addAsset(font: IAsset): void {\n        this._fontAssets.push(font);\n    }\n\n    // load all fonts from fontAssets for the game\n    // if font is already loaded - iit\n    // if font is available by default for the browser / os - it is skipped\n    public load(): void {\n        if (this._fontAssets.length === 0) {\n            this.FONTS_LOADED.next();\n            return;\n        }\n        (document as any).fonts.ready.then(() => {\n            Log.debug('FONTS LOADED', this.constructor.name, this._fontAssets.length);\n            this.FONTS_LOADED.next();\n        });\n        this._fontAssets.forEach((f) => {\n            const id = f.id.replace(/\\W/g, '_');\n            Log.debug(f.id, this.constructor.name, Boolean(document.getElementById(`font_${id}`)));\n            if (!document.getElementById(`font_${id}`)) {\n                const link = document.createElement('link');\n                link.setAttribute('rel', 'preload');\n                link.setAttribute('as', 'font');\n                link.setAttribute('type', 'font/ttf');\n                link.setAttribute('crossorigin', 'anonymous');\n                link.setAttribute('href', `${f.url}?${Core.hash}`);\n                link.id = `font_${id}`;\n                document.getElementsByTagName('head')[0].appendChild(link);\n\n                const style = document.createElement('style');\n                style.id = `style_${id}`;\n                style.appendChild(\n                    document.createTextNode(`\n                @font-face {\n                    font-family: '${f.id}';\n                    src: url('${f.url}?${Core.hash}') format('truetype');\n                }`),\n                );\n                document.getElementsByTagName('head')[0].appendChild(style);\n                this.createDomElementWithStyle(f.id, id);\n            }\n        });\n    }\n\n    // remove all loadedd fonts - called when game is quited (as assets.reset)\n    public reset(): void {\n        this._fontAssets.forEach((f) => {\n            const id = f.id.replace(/\\W/g, '_');\n            const style = document.getElementById(`style_${id}`);\n            if (style) {\n                (style.parentElement as HTMLElement).removeChild(style);\n            }\n\n            const font = document.getElementById(`font_${id}`);\n            if (font) {\n                (font.parentElement as HTMLElement).removeChild(font);\n            }\n\n            const element = document.getElementById(`dom_${id}`);\n            if (element) {\n                (element.parentElement as HTMLElement).removeChild(element);\n            }\n        });\n        this._fontAssets = [];\n    }\n\n    private replaceUrl(url: string): string {\n        // This is a case with translator and common translation json-s\n        // They are not destroyed after the game is destoryed becaouse tey are used in\n        // All places includin lobby\n        if (url.includes(Core.configuration.resourcesRootDir)) {\n            return url;\n        } else {\n            return Core.configuration.resourcesRootDir + url;\n        }\n    }\n\n    // we need to add element in dom with this fontfamily\n    // in order font to be really loaded and used from PIXI\n    private createDomElementWithStyle(fontFamily: string, id: string): void {\n        // add language depend char in dom in order font set for this unicode to be loaded\n        // some google fonts when downloaded from the google site are in different files woff2\n        // for different language https://fonts.googleapis.com/css2?family=Lobster&display=swap\n        if (!document.getElementById(`dom_${id}`)) {\n            let languageDependChar: string = '';\n            switch (Core.configuration.language) {\n                case 'bg':\n                    languageDependChar = 'Б';\n                    break;\n            }\n            const html = `<i id='dom_${id}' style='\n            font-family: \"${fontFamily}\";\n            position:absolute; \n            top: -2000px; \n            color: transparent;'>A${languageDependChar}</i>`;\n            document.body.insertAdjacentHTML('afterbegin', html);\n        }\n    }\n}\n","import { Application, Container, Rectangle, Renderer, Ticker } from 'pixi.js';\nimport { injectable, singleton } from 'tsyringe';\nimport { IStageOptions } from './Core';\nimport { IMediaInfoData } from './interfaces/IMediaInfoData';\nimport { IPerfData } from './interfaces/IPerfData';\nimport { IStage } from './interfaces/IStage';\nimport Align from './utils/align/Align';\nimport Scale from './utils/scale/Scale';\n\n@injectable()\n@singleton()\nexport default class HtmlStage implements IStage {\n    public stageInititalized: boolean = true;\n    public shouldResize: boolean = true;\n\n    get initialHeight(): number {\n        return this._height;\n    }\n\n    get initialWidth(): number {\n        return this._width;\n    }\n\n    get stage(): Container {\n        // @ts-ignore\n        // biome-ignore lint/suspicious/noEmptyBlockStatements: <explanation>\n        return { addChild: (_a) => {} };\n    }\n\n    get ticker(): Ticker {\n        return (\n            this._app?.ticker || {\n                remove: () => {\n                    //\n                },\n            }\n        );\n    }\n\n    get renderer(): Renderer {\n        // @ts-ignore\n        return null;\n    }\n\n    get screen(): Rectangle {\n        return this._app.screen;\n    }\n\n    get view(): HTMLCanvasElement {\n        return this._app.view;\n    }\n\n    get gameContainer(): Container {\n        // @ts-ignore\n        return null;\n    }\n\n    public get app(): Application {\n        return this._app;\n    }\n    public updatePerfomanceInfo: boolean = false;\n\n    private _width: number;\n    private _height: number;\n    private _landscape: boolean = true;\n    private _app: Application;\n\n    private stageOptions: any;\n\n    constructor() {\n        //\n    }\n\n    public clear(): void {\n        // implement for Html context\n    }\n\n    public initStage(options: IStageOptions): void {\n        this.stageOptions = options;\n    }\n\n    /**\n     * Returns media info from the application.\n     * @returns {MediaInfoData} Media info\n     */\n    public getMediaInfo(): IMediaInfoData {\n        return {\n            display: {\n                screen: {\n                    width: screen.width,\n                    height: screen.height,\n                },\n                view: {\n                    width: window.innerWidth,\n                    height: window.innerHeight,\n                },\n                stage: {\n                    x: 0,\n                    y: 0,\n                    width: window.innerWidth,\n                    height: window.innerHeight,\n                    initialWidth: window.innerWidth,\n                    initialHeight: window.innerHeight,\n                    currentWidth: Math.ceil(window.innerWidth),\n                    currentHeight: Math.ceil(window.innerHeight),\n                    scaleX: '1',\n                    scaleY: '1',\n                    scaling: Scale.NONE,\n                    alignment: Align.TOP_LEFT,\n                    orientation: this._landscape ? 'landscape' : 'portrait',\n                },\n            },\n        };\n    }\n    /**\n     * Returns media info from the application.\n     * @returns {MediaInfoData} Media info\n     */\n    public getPerfomanceInfo(fps: number = 0): IPerfData {\n        return {\n            fps,\n            drawCalls: 0,\n            peakDrawCalls: 0,\n            texturesCount: 0,\n            peakTexturesCount: 0,\n            spineAnimationsCount: 0,\n        };\n    }\n\n    public setDefaultCursor(): void {\n        // implement for Html context\n    }\n}\n","import { inject, injectable, singleton } from 'tsyringe';\nimport Core, { FeatureFlags, Log } from './Core';\nimport AssetPriority from './enums/AssetPriority';\nimport Language from './enums/Language';\nimport { IAsset } from './interfaces/IAsset';\nimport { IConfiguration } from './interfaces/IConfiguration';\nimport { ITranslator } from './interfaces/ITranslator';\nimport { IFeatureFlag } from '@egt/core';\n\n/**\n * Internationalization (i18n) manager for loading and resolving translations.\n *\n * Responsibilities:\n * - Manage current and default languages\n * - Prepare core/common translation assets and module-specific assets\n * - Merge loaded JSON keys into an in-memory map per language\n * - Resolve translation keys with support for:\n *   - Desktop overrides via `DESKTOP.` prefix\n *   - Restriction-based prefixes coming from the Core flags store (`Core.flags.all`)\n * - Provide helpers for string replacement and existence checks\n *\n * This class is a singleton and is resolved through DI.\n *\n * Usage example:\n * ```ts\n * const i18n = container.resolve(I18n);\n * const label = i18n.translate('BUTTON.PLAY');\n * ```\n */\n@injectable()\n@singleton()\nexport default class I18n implements ITranslator {\n    /** Current active language code (e.g. 'en'). */\n    public currentLanguage: string;\n    /** Default fallback language when a key or language is missing. */\n    public readonly defaultLanguage: string = Language.EN;\n    /** Core/common translation assets (one per supported language). */\n    public readonly assets: IAsset[] = [];\n    /** Module-specific translation assets. */\n    public moduleAssets: IAsset[] = [];\n    private languages: object = {};\n    private pathToCommon: string = '../assets/commons/translations/';\n    private pathToCore: string = './errors/';\n\n    /**\n     * Create an i18n manager and prepare asset descriptors for all supported languages.\n     * Also sets `currentLanguage` from configuration and preloads error messages.\n     *\n     * @param config Game configuration providing initial language.\n     */\n    constructor(@inject('IConfiguration') private config: IConfiguration) {\n        // This creates the assets objects for all of supported Languages\n        Object.values(Language).forEach((lang) => {\n            this.assets.push({\n                id: lang,\n                url: this.pathToCommon + lang + '.json',\n                priority: AssetPriority.HIGHEST,\n                type: 'translation',\n            });\n\n            this.languages[lang] = {};\n        });\n        const languageIndex = Object.values(Language).indexOf(this.config.language as Language);\n        if (languageIndex > -1) {\n            this.currentLanguage = Object.values(Language)[languageIndex];\n        } else {\n            this.currentLanguage = this.defaultLanguage;\n        }\n        this.moduleAssets = [];\n        this.loadErrorAsset();\n    }\n\n    /**\n     * Reset the current language map (keeps selected language, clears keys).\n     */\n    public reset(): void {\n        this.languages[this.currentLanguage] = {};\n    }\n\n    /**\n     * Load core error messages JSON for the current language and merge into the map.\n     */\n    public loadErrorAsset(): void {\n        const json = require(this.pathToCore + this.currentLanguage + '.json');\n        Object.assign(this.languages[this.currentLanguage], json);\n    }\n\n    /**\n     * Get the asset descriptor for a specific language, falling back to default when unknown.\n     *\n     * @param requestedLanguage Language code to look up.\n     * @returns The matching `IAsset` descriptor.\n     */\n    public getAssetFor(requestedLanguage: string): IAsset {\n        let requestedAsset;\n        if (this.languages.hasOwnProperty(requestedLanguage)) {\n            requestedAsset = this.assets.find((element) => {\n                return element.id === requestedLanguage;\n            });\n        } else {\n            requestedAsset = this.assets.find((element) => {\n                return element.id === this.defaultLanguage;\n            });\n        }\n        return requestedAsset;\n    }\n\n    /**\n     * Get a module-specific asset by module key (e.g. `_en`).\n     * Falls back to the default-language module asset when the language is unknown.\n     *\n     * @param key Module language key, expected format `_<lang>`.\n     * @returns The matching module `IAsset` descriptor.\n     */\n    public getModuleAssetFor(key: string): IAsset {\n        let requestedAsset;\n        if (this.languages.hasOwnProperty(key.substring(1))) {\n            requestedAsset = this.moduleAssets.find((element) => {\n                return element.id === key;\n            });\n        } else {\n            requestedAsset = this.moduleAssets.find((element) => {\n                return element.id === '_' + this.defaultLanguage;\n            });\n        }\n\n        return requestedAsset;\n    }\n\n    /**\n     * Register a module translation JSON to be loaded.\n     *\n     * @param moduleKey Module language key, expected format `_<lang>`.\n     * @param urlStr URL/path to the JSON file.\n     */\n    public addModuleAsset(moduleKey: string, urlStr: string): void {\n        const asset = {\n            id: moduleKey,\n            url: urlStr,\n            priority: AssetPriority.HIGHEST,\n            type: 'translation',\n        };\n        this.moduleAssets.push(asset);\n    }\n\n    /**\n     * Replace placeholder occurrences in a translated string for the current language.\n     *\n     * Example: replaceString('WELCOME', ['{name}'], ['John'])\n     *\n     * @param stringID Translation key to mutate.\n     * @param key Array of placeholder tokens to replace.\n     * @param values Replacement values corresponding to each token.\n     */\n    public replaceString(stringID: string, key: string[], values: string[]): void {\n        let str = this.languages[this.currentLanguage][stringID];\n        for (let i = 0; i < key.length; i++) {\n            str = str.replace(key[i], values[i]);\n        }\n        this.languages[this.currentLanguage][stringID] = str;\n    }\n\n    /**\n     * Merge translated keys into a language map and optionally switch current language.\n     *\n     * @param lang Language code for the provided keys.\n     * @param keys Plain object with translation pairs.\n     */\n    public addKeysTo(lang: string, keys: object): void {\n        if (lang !== this.currentLanguage) {\n            this.currentLanguage = lang;\n        }\n        Object.assign(this.languages[lang], keys);\n    }\n\n    /**\n     * Check if a translation exists for the given key in the current language.\n     *\n     * @param key Translation key to check.\n     * @returns True if the key exists in the current language map.\n     */\n    public hasTranslateFor(key: string): boolean {\n        if (this.languages[this.currentLanguage].hasOwnProperty(key)) {\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * Resolve a translation for the provided key.\n     *\n     * Resolution order:\n     * 1. Apply restriction-based key remapping (see `checkForRestriction`).\n     * 2. If desktop mode and `DESKTOP.<key>` exists, use it.\n     * 3. Otherwise use `<key>` if present.\n     * 4. When missing, fall back to the default language, log a warning.\n     * 5. When missing in default language, log a warning and return the key itself.\n     *\n     * @param key Translation key to resolve.\n     * @returns Localized string or the key when missing.\n     */\n    public translate(key: string): string {\n        key = this.checkForRestriction(key);\n\n        if (Core.isDesktopMode && this.languages[this.currentLanguage].hasOwnProperty('DESKTOP.' + key)) {\n            return this.languages[this.currentLanguage]['DESKTOP.' + key];\n        } else if (this.languages[this.currentLanguage].hasOwnProperty(key)) {\n            return this.languages[this.currentLanguage][key];\n        } else {\n            Log.warn(\n                \"There is no translation in '\" + this.currentLanguage + \"' language for key:\" + key,\n                this.constructor.name,\n            );\n\n            if (Core.isDesktopMode && this.languages[this.defaultLanguage].hasOwnProperty('DESKTOP.' + key)) {\n                return this.languages[this.defaultLanguage]['DESKTOP.' + key];\n            } else if (this.languages[this.defaultLanguage].hasOwnProperty(key)) {\n                return this.languages[this.defaultLanguage][key];\n            } else {\n                Log.warn(\n                    \"There is no translation in '\" + this.defaultLanguage + \"' language for key:\" + key,\n                    this.constructor.name,\n                );\n                return key;\n            }\n        }\n    }\n\n    /**\n     * Alternate restriction check that reads from the Core flags store (`Core.flags.all`)\n     * @param key Base translation key.\n     * @returns Potentially modified key including restriction prefixes.\n     */\n    private checkForRestriction(key: string): string {\n        const flags: Map<FeatureFlags, IFeatureFlag> = Core.flags.all;\n\n        const allResultsForKey = Object.keys(this.languages[this.currentLanguage]).filter((el) => {\n            return el.includes(key);\n        });\n\n        const activeFlags: IFeatureFlag[] = [];\n        flags.forEach((flag) => {\n            if (flag.isActive && flag.translationPrefix) {\n                activeFlags.push(flag);\n            }\n        });\n\n        const resultsForEveryFlag = activeFlags.map((flag) => {\n            return allResultsForKey.reduce((acc: string[], el: string) => {\n                if (flag.translationPrefix && el.includes(flag.translationPrefix)) {\n                    acc.push(el);\n                }\n                return acc;\n            }, []);\n        });\n        const viableResultsForEveryFlag = resultsForEveryFlag.filter((el: string[]) => {\n            return el.length > 0;\n        });\n        if (viableResultsForEveryFlag.length > 0) {\n            const resultsIntersection = viableResultsForEveryFlag.reduce((acc, arrayWithMatches) =>\n                acc.filter((e) => arrayWithMatches.includes(e)),\n            );\n            const resultWithoutExclusiveFlags = resultsIntersection.find((testString) => {\n                const flagPrefixesInKey = testString\n                    .replace(key, '')\n                    .split('.')\n                    .filter((segment) => segment.length > 0);\n                return flagPrefixesInKey.reduce((acc, el) => {\n                    const isFlagActive = activeFlags.reduce((flagsAcc, flag) => {\n                        return flagsAcc || (flag.translationPrefix != null && flag.translationPrefix === el);\n                    }, false);\n                    return acc && isFlagActive;\n                }, true);\n            });\n            if (resultWithoutExclusiveFlags) {\n                return resultWithoutExclusiveFlags;\n            }\n        }\n\n        return key;\n    }\n}\n","import gsap from 'gsap';\nimport Core, { BalanceRequest } from './Core';\n\nexport default class IFrameEventListener {\n    protected static _allSoundsMuted: boolean;\n\n    public static processEvent(message): void {\n        switch (message?.data?.command) {\n            case 'pauseGame':\n                if (!Core.ON_RENDERER_PAUSED.value) {\n                    Core.ON_RENDERER_PAUSED.next(true);\n                    gsap.globalTimeline.timeScale(0);\n                    Core.stage.ticker.speed = 0;\n                    this.allSoundsMuted = Core.sounds.ON_SOUND_MUTED.value;\n                    Core.sounds.ON_SOUND_MUTED.next(true);\n                }\n                break;\n            case 'resumeGame':\n                if (Core.ON_RENDERER_PAUSED.value) {\n                    gsap.globalTimeline.timeScale(1);\n                    Core.stage.ticker.speed = 1;\n                    Core.ON_RENDERER_PAUSED.next(false);\n                    if (!this.allSoundsMuted) {\n                        Core.sounds.ON_SOUND_MUTED.next(false);\n                    }\n                }\n                break;\n            case 'updateBalance':\n                Core.sendMessage(new BalanceRequest());\n                break;\n        }\n    }\n\n    public static get allSoundsMuted(): boolean {\n        return this._allSoundsMuted;\n    }\n\n    public static set allSoundsMuted(val: boolean) {\n        this._allSoundsMuted = val;\n    }\n}\n","import { gsap } from 'gsap';\nimport { BehaviorSubject, Subject, Subscription } from 'rxjs';\nimport { filter, take } from 'rxjs/operators';\nimport { injectable, singleton } from 'tsyringe';\nimport { Logger } from 'unicorn.console-logger';\nimport Core, {\n    BalanceResponse,\n    DefenceCodeRequest,\n    ErrorTypes,\n    IErrorData,\n    PostMessageDispatcher,\n    Timers,\n} from './Core';\nimport Language from './enums/Language';\nimport LobbyOpenType from './enums/LobbyOpenType';\nimport LobbyStyle from './enums/LobbyStyle';\n\nconst LAST_PLAYED_STORAGE_KEY = 'egtd_last_played';\n\nexport interface ILobbyOptions {\n    host: string;\n    playerId: string;\n    mode: string;\n    gameKey: string;\n    languageCode: string;\n    openType: 'fullscreen' | 'ingame';\n    mute: boolean;\n    balance: number;\n    units: number;\n    currency: string;\n    apiHost: string;\n    redirectHost: string;\n    bgMusicMute: boolean;\n    closeUrl: string;\n    sendOpenLobbyEvent: boolean;\n    mountLobby: boolean; // Indicate if we want to initialize the Lobby Store (make all lobby requests) upon Lobby init\n    tournamentHost: string;\n    prizePopServiceHost: string;\n    sessionKey: string;\n    openSection?: string;\n}\n\n/**\n * Representing adjustable Lobby props like\n * Also allows to pass additional configuration received on later stage\n * openType -> dynamically allowing to change the lobby Style from fullscreen to InGame and etc.\n */\nexport interface IDynamicLobbyOptions {\n    openType?: 'fullscreen' | 'ingame';\n    sendOpenLobbyEvent?: boolean;\n    tournamentsOnly?: boolean; // If Tournament Icon is clicked, the lobby should open and display directly the tournaments section only\n    campaignOnly?: { type: string; campaignID: number | string };\n    isSearchOpen?: boolean;\n    sessionKey?: string;\n}\n\n@injectable()\n@singleton()\nexport default class LobbyStore {\n    public isFullScreen: boolean = false;\n    public isInGame: boolean = false;\n    public lobbyStyle: LobbyStyle = LobbyStyle.SIMPLE;\n    public defenceCodeReceived: boolean = false;\n    public gameSoundMuted: boolean;\n    public bgMusicMuted: boolean;\n    public element: HTMLElement;\n    public useDefenceCode: boolean = true;\n    public ON_LOBBY_CLOSED: Subject<any> = new Subject<any>();\n    public operatorLobbyButtonClicked: boolean = false;\n    public selectedLanguage: Language;\n    public isLobbyOpened: boolean = false;\n    public tournamentsOnly: boolean = false;\n\n    private turnOfSoundsTimeout: any;\n    private _sendOpenLobbyEvent: boolean = true;\n    private LOBBY_CHANNEL: Subject<any>;\n    private _onGameMessageSubscription: Subscription;\n    private _balanceResponse: BalanceResponse;\n    private remoteLobbyScriptLoadingState: 'notLoaded' | 'loaded' = 'notLoaded';\n    public LOBBY_INITIALIZED: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n\n    public get channel(): Subject<any> | null {\n        return this.LOBBY_CHANNEL;\n    }\n\n    public set channel(c: Subject<any> | null) {\n        if (c) {\n            this.LOBBY_CHANNEL = c;\n            this.attachChannelListeners();\n        }\n    }\n\n    public get sendOpenLobbyEvent(): boolean {\n        return this._sendOpenLobbyEvent;\n    }\n\n    constructor() {\n        // We can't extend BaseStore in LobbyStore because this creates circular dependencies between Core and LobbyStore\n        Logger.logModelMessage(['Created'], this.constructor.name);\n    }\n\n    public init(): void {\n        Core.sounds.ON_SOUND_MUTED.subscribe((value) => {\n            if (!this.isLobbyOpened) {\n                this?.channel?.next({ event: 'mute', value });\n            }\n        });\n        Core.ON_SERVER_RESPONSE.subscribe(this.onMessage.bind(this));\n        Core.SHOW_ERROR.subscribe(this.onClientError.bind(this));\n    }\n\n    public setLobbyOptions(lobbyHome: string | null | undefined, jurisdiction?: any): void {\n        if (lobbyHome) {\n            Core.configuration.hasPortal = lobbyHome !== LobbyOpenType.OPERATOR;\n            switch (lobbyHome) {\n                case LobbyOpenType.IN_GAME:\n                    this.isInGame = true;\n                    Core.configuration.lobbyOpenType = 'ingame';\n                    break;\n                case LobbyOpenType.FULLSCREEN:\n                    this.isFullScreen = true;\n                    Core.configuration.lobbyOpenType = 'fullscreen';\n                    break;\n                default:\n                    break;\n            }\n        } else {\n            Core.configuration.hasPortal = jurisdiction?.navigateToLobbyOnHome;\n        }\n        if (jurisdiction && jurisdiction.lobbyStyle) {\n            this.lobbyStyle = jurisdiction.lobbyStyle;\n        }\n        if (typeof jurisdiction?.lobbyDefenceCode !== 'undefined') {\n            this.useDefenceCode = Boolean(jurisdiction?.lobbyDefenceCode);\n        }\n\n        if (typeof jurisdiction?.openLobby !== 'undefined') {\n            this._sendOpenLobbyEvent = Boolean(jurisdiction?.openLobby);\n        }\n\n        this.selectedLanguage =\n            (Core.translator.currentLanguage.toLowerCase() as Language) || Core.configuration.language;\n    }\n\n    public setCurrentGame(gameKey: string): void {\n        // add to the local storage\n        const lastPlayedStorageKey = `${LAST_PLAYED_STORAGE_KEY}_${Core.configuration.playerId}`;\n        try {\n            if (window.localStorage) {\n                const lastPlayedGames: string[] = JSON.parse(localStorage.getItem(lastPlayedStorageKey) || '[]');\n                if (lastPlayedGames.includes(gameKey)) {\n                    const gamePos = lastPlayedGames.indexOf(gameKey);\n                    lastPlayedGames.splice(gamePos, 1);\n                }\n                lastPlayedGames.unshift(gameKey);\n\n                localStorage.setItem(\n                    lastPlayedStorageKey,\n                    JSON.stringify(lastPlayedGames.filter((game) => Boolean(game))),\n                );\n            }\n        } catch (_err) {\n            // HINT: Leave it empty as we are not going to do anything\n        }\n    }\n\n    public setBalance(balanceResponse: any): void {\n        const prevBalance = this._balanceResponse;\n        if (!balanceResponse.data) {\n            this._balanceResponse = new BalanceResponse(balanceResponse);\n        } else {\n            if (typeof balanceResponse.data.balance === 'object') {\n                this._balanceResponse = new BalanceResponse({\n                    balance: {\n                        ...balanceResponse.data.balance,\n                        currency: Core.PLAYER_BALANCE.value.currency,\n                    },\n                });\n            } else {\n                this._balanceResponse = new BalanceResponse({\n                    balance: {\n                        ...balanceResponse.data,\n                        currency: Core.PLAYER_BALANCE.value.currency,\n                    },\n                });\n            }\n        }\n        if (prevBalance && prevBalance.balance !== this._balanceResponse.balance) {\n            this.onBalanceUpdated(this._balanceResponse.balance);\n        }\n    }\n\n    /**\n     * Makes the lobby visible.\n     * Can pass settings to Lobby.\n     * Save sound states.\n     */\n    public showLobby(settings: IDynamicLobbyOptions = { tournamentsOnly: false }): void {\n        // call this to ensure proper dimensions are set\n        this.setMountElementDimensions();\n        this.showElement();\n\n        /**\n         * In order to avoid race conditions between Game settings received and lobby initialization finished\n         * pass the settings upon display intent\n         */\n        let config = {\n            openType: Core.configuration.lobbyOpenType, // possible new setting\n            sendOpenLobbyEvent: this._sendOpenLobbyEvent, // possible new setting\n            sessionKey: Core.configuration.sessionKey, // this configuration comes after game is loaded so pass it here to have latest value\n            mute: Core.sounds.ON_SOUND_MUTED.value, // possible new setting\n            bgMusicMute: Core.sounds.ON_BACKGROUND_SOUNDS_MUTED.value, // possible new setting\n            gameKey: Core.configuration.gameKey,\n        };\n\n        /**\n         * Add the ability to dynamically change the config\n         */\n        if (settings) {\n            config = {\n                ...config,\n                ...settings,\n            };\n        }\n\n        // Update local cached settings\n        this.isInGame = config.openType === 'ingame';\n\n        // Signals to the iFrame App that new settings arrived\n        this.channel?.next({\n            event: 'settings',\n            value: config,\n        });\n\n        // Balance is set after lobby initialization, so we need to update it prior showing the Lobby\n        this.channel?.next({\n            event: 'balance',\n            value: {\n                balance: Core.PLAYER_BALANCE.value.balance,\n                units: Core.PLAYER_BALANCE.value.units,\n                currency: Core.PLAYER_BALANCE.value.currency,\n            },\n        });\n        // console.log('send settings to iframe app', config);\n        if (Core.environment.isMobileIos() && !this.isInGame) {\n            Core.configuration.hideHandCursor = true;\n            Core.environment.removeMobileFullscreen();\n            setTimeout(() => {\n                const top = window.innerHeight * 0.25;\n                window.scrollTo(0, top);\n            }, 1);\n        }\n\n        // Signals to the Lobby that is visible\n        Core.lobbyStore.channel?.next({\n            event: 'display',\n            value: true,\n        });\n        this.saveSoundStateAndMuteSounds();\n    }\n\n    protected onBalanceUpdated(value: number): void {\n        this?.channel?.next({\n            event: 'balance',\n            value: {\n                balance: value,\n                units: Core.PLAYER_BALANCE.value.units,\n                currency: Core.PLAYER_BALANCE.value.currency,\n            },\n        });\n    }\n\n    protected startGameWithoutDefenceCode(gameKey: string): void {\n        this?.channel?.next({\n            event: 'display',\n            value: false,\n        });\n        Core.configuration.language = this.selectedLanguage;\n        Core.translator.currentLanguage = this.selectedLanguage;\n        this.hideElement();\n        Core.openGame(gameKey);\n    }\n\n    protected loadGameWithoutDefenceCode(gameKey: string): void {\n        if (this.isInGame) {\n            Core.ON_GAME_UNLOADED.pipe(take(1)).subscribe(() => {\n                this.startGameWithoutDefenceCode(gameKey);\n            });\n            Core.closeGame();\n        } else if (this.isFullScreen) {\n            this.startGameWithoutDefenceCode(gameKey);\n        }\n    }\n\n    protected onLobbyChannelEvent({ event, value }: { event: string; value: any }): void {\n        switch (event) {\n            case 'defenceCodeRequired':\n                if (this.useDefenceCode) {\n                    Core.sendMessage(new DefenceCodeRequest(value));\n                } else {\n                    this.loadGameWithoutDefenceCode(value);\n                }\n                break;\n            case 'display':\n                if (!value) {\n                    this.ON_LOBBY_CLOSED.next();\n                    this.isLobbyOpened = false;\n                } else {\n                    this.showElement();\n                    this.isLobbyOpened = true;\n                }\n                break;\n            case 'error':\n                Core.SHOW_ERROR.next(value);\n                break;\n            case 'mute':\n                this.gameSoundMuted = value;\n                break;\n            case 'bgMusicMute':\n                this.bgMusicMuted = value;\n                break;\n            case 'lobbyInitialized':\n                this.LOBBY_INITIALIZED.next(value);\n                break;\n            case 'language':\n                Core.configuration.language = value;\n                Core.translator.currentLanguage = value;\n                Core.translator.loadErrorAsset();\n                this.selectedLanguage = value;\n                break;\n            case 'getLastPlayed':\n                try {\n                    if (window.localStorage) {\n                        const lastPlayedKey = `${LAST_PLAYED_STORAGE_KEY}_${Core.configuration.playerId}`;\n                        const lastPlayedData = localStorage.getItem(lastPlayedKey);\n                        this.channel?.next({\n                            event: 'lastPlayedGames',\n                            value: lastPlayedData ? JSON.parse(lastPlayedData) : [],\n                        });\n                    }\n                } catch (_err) {\n                    // Silently handle localStorage errors (e.g., in incognito mode)\n                    this.channel?.next({\n                        event: 'lastPlayedGames',\n                        value: [],\n                    });\n                }\n                break;\n            case 'deposit':\n                PostMessageDispatcher.balanceTooLow();\n                break;\n            case 'gameAddedToFavorites':\n                PostMessageDispatcher.gameAddedToFavorites(value);\n                break;\n            case 'gameRemovedFromFavorites':\n                PostMessageDispatcher.gameRemovedFromFavorites(value);\n                break;\n            default:\n                break;\n        }\n    }\n\n    protected onCloseLobby(): void {\n        gsap.globalTimeline.resume();\n        this.hideElement();\n        this.tournamentsOnly = false;\n\n        if (Core.sounds.ON_SOUND_MUTED.value !== this.gameSoundMuted) {\n            Core.sounds.ON_SOUND_MUTED.next(this.gameSoundMuted);\n        }\n\n        if (Core.sounds.ON_BACKGROUND_SOUNDS_MUTED.value !== this.bgMusicMuted) {\n            Core.sounds.ON_BACKGROUND_SOUNDS_MUTED.next(this.bgMusicMuted);\n        }\n        if (this.turnOfSoundsTimeout) {\n            Timers.clearTimeout(this.turnOfSoundsTimeout);\n        }\n        Core.sounds.play('homeSound');\n        Core.UI_BLOCKER.next(false);\n    }\n\n    private saveSoundStateAndMuteSounds(): void {\n        this.gameSoundMuted = Core.sounds.ON_SOUND_MUTED.value;\n        this.bgMusicMuted = Core.sounds.ON_BACKGROUND_SOUNDS_MUTED.value;\n        const homeSoundDuration = Core.sounds.getSoundDuration('mainSounds', 'homeSound');\n\n        Core.sounds.ON_BACKGROUND_SOUNDS_MUTED.next(true);\n        Core.sounds.play('homeSound');\n\n        this.turnOfSoundsTimeout = Timers.setTimeout(() => {\n            Core.sounds.ON_SOUND_MUTED.next(true);\n            Timers.clearTimeout(this.turnOfSoundsTimeout);\n        }, homeSoundDuration);\n    }\n\n    private attachChannelListeners(): void {\n        this?.channel?.subscribe(this.onLobbyChannelEvent.bind(this));\n        this.ON_LOBBY_CLOSED.subscribe(this.onCloseLobby.bind(this));\n\n        Core.sounds.ON_SOUND_MUTED.pipe(filter((_) => !this.isLobbyOpened)).subscribe((value) =>\n            this?.channel?.next({ event: 'mute', value }),\n        );\n\n        Core.sounds.ON_BACKGROUND_SOUNDS_MUTED.pipe(filter((_) => !this.isLobbyOpened)).subscribe((value) =>\n            this?.channel?.next({ event: 'bgMusicMute', value }),\n        );\n\n        // Pass exit intent to the Lobby so it can handle the routing\n        Core.EXIT_APPLICATION.subscribe(() => this?.channel?.next({ event: 'exit' }));\n\n        Core.STAGE_RESIZE_END.subscribe(() => {\n            if (this.isInGame) {\n                this.setMountElementDimensions();\n            }\n        });\n    }\n\n    private onClientError(e: IErrorData): void {\n        if (\n            Core.configuration.mode === 'kiosk' && // for now using the mode parameter to handle the errors and return to lobby\n            ([\n                ErrorTypes.CONNECTION_ERROR,\n                ErrorTypes.GAME_LOCK_ERROR,\n                ErrorTypes.SOCKET_ERROR,\n                ErrorTypes.MAINTENANCE,\n            ].includes(e.type) ||\n                [\n                    '1002',\n                    '1006',\n                    '2000',\n                    '4605',\n                    '4606',\n                    '4607',\n                    '4805',\n                    '4811',\n                    '4812',\n                    '4819',\n                    '1892',\n                    'unhandledError',\n                    'errorWhileReconnecting',\n                ].includes(e.code))\n        ) {\n            setTimeout(() => {\n                this.operatorLobbyButtonClicked = true;\n                Core.closeGame();\n                Core.EXIT_APPLICATION.next();\n            }, 5000);\n        }\n    }\n\n    private onMessage(response: any): void {\n        // if it is collect do not change balance - it will be done after the balance bangup animation\n        if (response.balance !== undefined && response.event !== 'collect') {\n            this.setBalance(response);\n        }\n        if (response.data && response.data.balance !== undefined && response.event !== 'collect') {\n            this.setBalance(response);\n        }\n\n        switch (response.event) {\n            case 'defenceCode':\n                this.defenceCodeReceived = true;\n                this?.channel?.next({\n                    event: 'defenceCode',\n                    value: response.secret || response.data.secret,\n                });\n                break;\n        }\n    }\n\n    /**\n     * Creates the mounting element, onto which the Lobby will be attached\n     */\n    private createMountElement(): void {\n        this.element = document.createElement('div');\n        this.element.setAttribute('id', 'react-lobby-remote-root');\n        this.element.style.display = 'block';\n        this.setMountElementDimensions();\n\n        // the iOS fullscreen helper scrolls the page (iPads with Fullscreen API support included)\n        if (Core.environment.isIOSScrollLayout()) {\n            this.element.style.position = 'fixed';\n        }\n\n        document.body.appendChild(this.element);\n    }\n\n    /**\n     * Sets the dimensions of the lobby mount element\n     */\n    private setMountElementDimensions(): void {\n        if (!Core?.stage?.stageInititalized) {\n            // Game client hasn't loaded the stage yet\n            return;\n        }\n        const { currentWidth: lobbyPanelWidth, currentHeight: lobbyPanelHeight } =\n            Core.stage.getMediaInfo().display.stage;\n\n        this.element?.style.setProperty('--lobby-container-width', lobbyPanelWidth ? lobbyPanelWidth + 'px' : '100vw');\n        this.element?.style.setProperty(\n            '--lobby-container-height',\n            lobbyPanelHeight ? lobbyPanelHeight + 'px' : '100vh',\n        );\n    }\n\n    private hideElement(): void {\n        if (!this.element) {\n            return;\n        }\n\n        this.element.style.opacity = '0';\n        this.element.style.zIndex = '-1';\n        document.removeEventListener('touchmove', this.preventPageScroll);\n    }\n\n    private showElement(): void {\n        if (!this.element) {\n            return;\n        }\n\n        // Delay the style change slightly to allow potential state updates\n        // in the embedded app to render before making the container visible.\n        setTimeout(() => {\n            // Check element exists again in case it was destroyed during the timeout\n            if (this.element) {\n                this.element.style.opacity = '1';\n                this.element.style.zIndex = '11';\n                document.addEventListener('touchmove', this.preventPageScroll, { passive: false });\n            }\n        }, 0);\n    }\n\n    /**\n     * Blocks page scroll behind the lobby. Touches inside the lobby iframe never reach this document.\n     * The iOS swipe-to-fullscreen overlay stays scrollable.\n     */\n    private preventPageScroll = (e: TouchEvent): void => {\n        if (!(e.target as Element).closest?.('#iOSFullscreen')) {\n            e.preventDefault();\n        }\n    };\n\n    /**\n     * This method loads the lobby main.js file and mounts it\n     * @returns\n     */\n    public loadLobbyScript(): Promise<void> {\n        return new Promise((resolve, reject) => {\n            const id = 'react-lobby-remote-script';\n            let remoteScript: HTMLElement | null = document.getElementById(id);\n\n            if (remoteScript) {\n                // Script is already loaded\n                resolve();\n                return;\n            }\n\n            const onLoadHandler = function (): void {\n                this.remoteLobbyScriptLoadingState = 'loaded';\n                this.initializeLobby();\n                resolve();\n            }.bind(this);\n            const onErrorHandler = function (): void {\n                this.remoteLobbyScriptLoadingState = 'notLoaded';\n                reject();\n            }.bind(this);\n\n            if (this.remoteLobbyScriptLoadingState === 'notLoaded') {\n                remoteScript = document.createElement('script');\n                remoteScript.setAttribute('id', id);\n                remoteScript.setAttribute('src', `${Core.configuration.lobbyHost}/static/js/main.js`);\n                remoteScript.onload = onLoadHandler;\n                remoteScript.onerror = onErrorHandler;\n                document.head.appendChild(remoteScript);\n            } else if (this.remoteLobbyScriptLoadingState === 'loaded') {\n                resolve();\n            }\n        });\n    }\n\n    /**\n     * This method is responsible for creating Lobby Iframe App\n     */\n    private initializeLobby() {\n        this.createMountElement();\n\n        // @ts-ignore\n        if (window.reactLobby) {\n            const settings: ILobbyOptions = {\n                host: Core.configuration.lobbyHost,\n                playerId: Core.configuration.playerId,\n                mode: Core.configuration.mode || (Core.isDesktopMode ? 'desktop' : 'mobile'),\n                gameKey: Core.configuration.gameKey,\n                languageCode: Core.configuration.language,\n                openType: Core.configuration.lobbyOpenType,\n                mute: Core.sounds.ON_SOUND_MUTED.value,\n                balance: Core.PLAYER_BALANCE.value.balance,\n                units: Core.PLAYER_BALANCE.value.units,\n                currency: Core.PLAYER_BALANCE.value.currency,\n                apiHost: Core.configuration.apiIntegrationHost,\n                redirectHost: Core.configuration.lobbyRedirectHost,\n                bgMusicMute: Core.sounds.ON_BACKGROUND_SOUNDS_MUTED.value,\n                closeUrl: Core.configuration.closeUrl,\n                sendOpenLobbyEvent: this._sendOpenLobbyEvent,\n                /**\n                 * The LobbyApp will be mounted on later stage, whenever the user presses the show lobby button.\n                 * Exception is in case of Portal (only lobby) when there is no GameKey, mount it directly.\n                 */\n                mountLobby: !Core.configuration.gameKey ? true : false,\n                tournamentHost: Core.configuration.tournamentHost,\n                prizePopServiceHost: Core.configuration.prizePopServiceHost,\n                sessionKey: Core.configuration.sessionKey,\n                openSection: undefined,\n            };\n\n            if (Core.configuration.openSection) {\n                settings.openSection = Core.configuration.openSection.toUpperCase();\n            }\n\n            /**\n             * This method will get injected by the Lobby main.js file\n             * It will instantiate the IFrame Application used to mediate between game client and lobby app\n             */\n            // @ts-ignore\n            const { CHANNEL: LOBBY_CHANNEL, element } = window.reactLobby('react-lobby-remote-root', settings);\n\n            // console.log('lobby iframe app mounted with', settings);\n\n            this.channel = LOBBY_CHANNEL;\n            this.element = element;\n\n            this.hideElement();\n        }\n    }\n}\n","import { injectable } from 'tsyringe';\nimport { Log } from './Core';\n\n@injectable()\nexport default class LocalStorageManager {\n    private isLocalStorageAvailable(): boolean {\n        try {\n            const testKey = '__test';\n            localStorage.setItem(testKey, testKey);\n            localStorage.removeItem(testKey);\n            return true;\n        } catch (_e) {\n            return false;\n        }\n    }\n\n    public readSetting(key: string, defaultValue: any = null): any {\n        if (!this.isLocalStorageAvailable()) {\n            Log.debug('Local Storage is not available.', this.constructor.name);\n            return defaultValue;\n        }\n\n        const value = localStorage.getItem(key);\n        if (value === null) {\n            return defaultValue;\n        }\n\n        try {\n            return JSON.parse(value);\n        } catch (_e) {\n            Log.error('Error parsing JSON from local storage', this.constructor.name);\n            return defaultValue;\n        }\n    }\n\n    public writeSetting(key: string, value: any): void {\n        if (!this.isLocalStorageAvailable()) {\n            Log.error('Local Storage is not available.', this.constructor.name);\n            return;\n        }\n\n        try {\n            const stringValue = JSON.stringify(value);\n            localStorage.setItem(key, stringValue);\n        } catch (_e) {\n            Log.error('Error writing JSON to local storage', this.constructor.name);\n        }\n    }\n\n    public removeSetting(key: string): void {\n        if (!this.isLocalStorageAvailable()) {\n            Log.error('Local Storage is not available.', this.constructor.name);\n            return;\n        }\n\n        localStorage.removeItem(key);\n    }\n}\n","import { Features, SlotComponents } from '@egt/slot';\nimport Core from './Core';\nimport { IPosition } from './interfaces/IPosition';\n\nexport default class PositionObject {\n    public positionData: IPosition;\n    public configs: Array<{ value: IPosition; priority: number; priorityType: { feature: any; mode: any } }>;\n    public activePriorityIndex: number;\n\n    constructor(dataNew: IPosition, data?: PositionObject) {\n        if (!data) {\n            this.positionData = dataNew;\n        } else {\n            this.replacePositionData(dataNew, data);\n        }\n    }\n\n    public updatePriorities(): void {\n        if (this.configs) {\n            this.activePriorityIndex = this.getConfigIndex(this.configs);\n            if (this.activePriorityIndex !== -1) {\n                this.replacePositionData(this.configs[this.activePriorityIndex].value, this);\n            }\n        }\n    }\n\n    public getConfigIndex(\n        configs: Array<{ value: IPosition; priority: number; priorityType: { feature: any; mode: any } }>,\n    ): number {\n        let biggerPriority: number = -1;\n        let configIndex: number = -1;\n        for (let i: number = 0; i < configs.length; i++) {\n            const isComponent: boolean = configs[i].priorityType.mode\n                ? Core.hasComponent(configs[i].priorityType.feature, configs[i].priorityType.mode)\n                : this.hasComponent(configs[i].priorityType.feature as SlotComponents);\n            const isFeature: boolean = Core.hasFeature(configs[i].priorityType.feature as Features);\n\n            if ((isComponent || isFeature) && biggerPriority < configs[i].priority) {\n                biggerPriority = configs[i].priority;\n                configIndex = i;\n            }\n        }\n        return configIndex;\n    }\n\n    public hasComponent(componentType: SlotComponents): boolean {\n        const components = Core.getGameComponents();\n        return components.filter((componentArr) => componentArr.componentType === componentType).length > 0;\n    }\n\n    public get x(): number {\n        if (Core.isDesktopMode && this.positionData.desktop) {\n            return this.positionData.desktop.x;\n        } else if (Core.ORIENTATION.value.isLandscape && this.positionData.landscape) {\n            return Core.LEFT_HAND_MODE.value && this.positionData.landscape.leftHandX\n                ? this.positionData.landscape.leftHandX\n                : this.positionData.landscape.x;\n        } else if (Core.ORIENTATION.value.isPortrait && this.positionData.portrait) {\n            return this.positionData.portrait.x;\n        } else {\n            return this.positionData.landscape ? this.positionData.landscape.x : 0;\n        }\n    }\n\n    public get y(): number {\n        if (Core.isDesktopMode && this.positionData.desktop) {\n            return this.positionData.desktop.y;\n        } else if (Core.ORIENTATION.value.isLandscape && this.positionData.landscape) {\n            return Core.LEFT_HAND_MODE.value && this.positionData.landscape.leftHandY\n                ? this.positionData.landscape.leftHandY\n                : this.positionData.landscape.y;\n        } else if (Core.ORIENTATION.value.isPortrait && this.positionData.portrait) {\n            return this.positionData.portrait.y;\n        } else {\n            return this.positionData.landscape ? this.positionData.landscape.y : 0;\n        }\n    }\n\n    public get scale(): number {\n        if (Core.isDesktopMode && this.positionData.desktop) {\n            return this.positionData.desktop.scale ? this.positionData.desktop.scale : 1;\n        } else if (Core.ORIENTATION.value.isLandscape) {\n            return this.positionData.landscape?.scale ? this.positionData.landscape.scale : 1;\n        } else {\n            return this.positionData.portrait?.scale ? this.positionData.portrait.scale : 1;\n        }\n    }\n\n    public get visible(): boolean {\n        if (Core.isDesktopMode && this.positionData.desktop) {\n            return this.positionData.desktop.visible !== undefined ? this.positionData.desktop.visible : true;\n        } else if (Core.ORIENTATION.value.isLandscape) {\n            return this.positionData.landscape?.visible !== undefined ? this.positionData.landscape.visible : true;\n        } else {\n            return this.positionData.portrait?.visible !== undefined ? this.positionData.portrait.visible : true;\n        }\n    }\n\n    public get width(): number {\n        if (Core.isDesktopMode && this.positionData.desktop) {\n            return this.positionData.desktop.width !== undefined ? this.positionData.desktop.width : 100;\n        } else if (Core.ORIENTATION.value.isLandscape) {\n            return this.positionData.landscape?.width !== undefined ? this.positionData.landscape.width : 100;\n        } else {\n            return this.positionData.portrait?.width !== undefined ? this.positionData.portrait.width : 100;\n        }\n    }\n\n    public get height(): number {\n        if (Core.isDesktopMode && this.positionData.desktop) {\n            return this.positionData.desktop.height !== undefined ? this.positionData.desktop.height : 100;\n        } else if (Core.ORIENTATION.value.isLandscape) {\n            return this.positionData.landscape?.height !== undefined ? this.positionData.landscape.height : 100;\n        } else {\n            return this.positionData.portrait?.height !== undefined ? this.positionData.portrait.height : 100;\n        }\n    }\n\n    public get alpha(): number {\n        if (Core.isDesktopMode && this.positionData.desktop) {\n            return this.positionData.desktop.alpha !== undefined ? this.positionData.desktop.alpha : 1;\n        } else if (Core.ORIENTATION.value.isLandscape) {\n            return this.positionData.landscape?.alpha !== undefined ? this.positionData.landscape.alpha : 1;\n        } else {\n            return this.positionData.portrait?.alpha !== undefined ? this.positionData.portrait.alpha : 1;\n        }\n    }\n\n    public replacePositionData(dataNew: IPosition, data: PositionObject): void {\n        const posData = data.positionData;\n        for (const key in dataNew) {\n            if (posData[key]) {\n                posData[key] = Object.assign(posData[key], dataNew[key]);\n            } else {\n                posData[key] = dataNew[key];\n            }\n        }\n        this.positionData = posData;\n    }\n}\n","import Core from './Core';\nexport default class PostMessageDispatcher {\n    public static gameOpened(): void {\n        // **** this is for integration problem with iOS go to fullscreen ****\n        if (Core.environment.inIframe() && Core.configuration.gameKey) {\n            window.parent.postMessage({ command: 'openGame', type: Core.configuration.gameKey }, '*');\n        }\n        // **** this is for tournaments module ****\n    }\n\n    /**\n     * Deprecated method !\n     * This logic is moved into the Lobby App.\n     * the code is left here only for reference.\n     */\n    public static lobbyOpened(): void {\n        // if (Core.environment.inIframe() && Core.lobbyStore.sendOpenLobbyEvent) {\n        //     window.parent.postMessage({ command: 'openLobby' }, '*');\n        // }\n    }\n\n    public static openFullScreen(): void {\n        if (Core.environment.inIframe()) {\n            window.parent.postMessage({ command: 'openFullScreen' }, '*');\n        }\n    }\n\n    public static closeFullScreen(): void {\n        if (Core.environment.inIframe()) {\n            window.parent.postMessage({ command: 'closeFullScreen' }, '*');\n        }\n    }\n\n    public static exit(): void {\n        // This logic is moved into the Lobby App\n        // the code is left here only for reference\n        // window.parent.postMessage({ command: 'exit' }, '*');\n    }\n\n    public static htmlOpened(htmlType: any): void {\n        // **** this is for integration problem with iOS go to fullscreen ****\n        if (Core.environment.inIframe()) {\n            window.parent.postMessage({ command: 'openHTML', type: htmlType }, '*');\n        }\n    }\n\n    public static htmlClosed(htmlType: any): void {\n        // **** this is for integration problem with iOS go to fullscreen ****\n        if (Core.environment.inIframe()) {\n            window.parent.postMessage({ command: 'closeHTML', type: htmlType }, '*');\n        }\n    }\n\n    public static autoPlayStarted(numberOfAutoplays: number): void {\n        // **** this is for integration problem with operator handling the autoplay functionality ****\n        if (Core.environment.inIframe()) {\n            window.parent.postMessage(\n                { command: 'autoPlayStarted', type: Core.configuration.gameKey, numberOfBets: numberOfAutoplays },\n                '*',\n            );\n        }\n    }\n\n    public static autoPlayStopped(): void {\n        // **** this is for integration problem with operator handling the autoplay functionality ****\n        if (Core.environment.inIframe()) {\n            window.parent.postMessage({ command: 'autoPlayStopped', type: Core.configuration.gameKey }, '*');\n        }\n    }\n\n    public static reelsStopped(): void {\n        // **** this is for integration problem with operator handling the autoplay functionality ****\n        if (Core.environment.inIframe()) {\n            window.parent.postMessage({ command: 'reelsStopped', type: Core.configuration.gameKey }, '*');\n        }\n    }\n\n    public static gameLoadStarted(): void {\n        if (Core.environment.inIframe()) {\n            window.parent.postMessage({ command: 'gameLoadStarted' }, '*');\n        }\n    }\n\n    public static gameLoadProgress(progress: any): void {\n        if (Core.environment.inIframe()) {\n            window.parent.postMessage({ command: 'gameLoadProgress', value: progress }, '*');\n        }\n    }\n    public static gameLoadComplete(): void {\n        if (Core.environment.inIframe()) {\n            window.parent.postMessage({ command: 'gameLoadComplete' }, '*');\n        }\n    }\n    public static reelsStarted(): void {\n        if (Core.environment.inIframe()) {\n            window.parent.postMessage({ command: 'reelsStarted', type: Core.configuration.gameKey }, '*');\n        }\n    }\n    public static toggleMenu(val: boolean): void {\n        if (Core.environment.inIframe()) {\n            window.parent.postMessage({ command: 'toggleMenu', value: val }, '*');\n        }\n    }\n    public static toggleSound(val: boolean): void {\n        if (Core.environment.inIframe()) {\n            window.parent.postMessage({ command: 'toggleSound', value: val }, '*');\n        }\n    }\n    public static fastPlayChange(val: any): void {\n        if (Core.environment.inIframe()) {\n            window.parent.postMessage({ command: 'changeSpinSpeed', value: val }, '*');\n        }\n    }\n    public static playModeUpdate(val: any): void {\n        if (Core.environment.inIframe()) {\n            window.parent.postMessage({ command: 'spinModeChanged', value: val }, '*');\n        }\n    }\n    public static errorMessageDisplayed(): void {\n        if (Core.environment.inIframe()) {\n            window.parent.postMessage({ command: 'errorMessageDisplayed' }, '*');\n        }\n    }\n    public static balanceTooLow(): void {\n        if (Core.environment.inIframe()) {\n            window.parent.postMessage({ command: 'insufficientFunds' }, '*');\n        }\n    }\n    // **** this is used in multiplayer games - operator will know is it safe and ok to pause gameplay ****\n    public static multiplayerGameState(state: any): void {\n        if (Core.environment.inIframe()) {\n            window.parent.postMessage({ command: 'multiplayerGameState', value: state }, '*');\n        }\n    }\n    // **** this is used in multiplayer games - operator will know is it safe and ok to pause gameplay ****\n    public static multiplayerGamePlayerInBet(state: any): void {\n        if (Core.environment.inIframe()) {\n            window.parent.postMessage({ command: 'multiplayerGamePlayerInBet', value: state }, '*');\n        }\n    }\n    public static openPlayerHistory(): void {\n        if (Core.environment.inIframe()) {\n            window.parent.postMessage({ command: 'openPlayerHistory' }, '*');\n        }\n    }\n    public static openDepositModal(): void {\n        if (Core.environment.inIframe()) {\n            window.parent.postMessage({ command: 'openDepositModal' }, '*');\n        }\n    }\n    public static gameAddedToFavorites(gameKey: string): void {\n        if (Core.environment.inIframe()) {\n            window.parent.postMessage({ command: 'gameAddedToFavorites', gameKey }, '*');\n        }\n    }\n    public static gameRemovedFromFavorites(gameKey: string): void {\n        if (Core.environment.inIframe()) {\n            window.parent.postMessage({ command: 'gameRemovedFromFavorites', gameKey }, '*');\n        }\n    }\n}\n","import Core, { AnalyticsDispatcher, IErrorData } from '@egt/core';\nimport axios, { AxiosResponse, AxiosRequestConfig } from 'axios';\nimport { injectable, singleton } from 'tsyringe';\nimport ErrorTypes from './enums/ErrorTypes';\nimport { IContentLoadData } from './interfaces/IContentLoadData';\n\n// Test request delay\n/* const asyncTimeout = (time: number): Promise<any> => {\n    return new Promise((resolve) => {\n        setTimeout(() => {\n            resolve(time)\n        }, time)\n    })\n} */\n\n@injectable()\n@singleton()\nexport default class RequestManager {\n    private loadingUrl: string[] = [];\n    public loadContent(url: string, param: any): void {\n        const isLoading = this.loadingUrl.indexOf(url);\n        if (isLoading === -1) {\n            this.loadingUrl.push(url);\n            fetch(url)\n                .then((response) => {\n                    if (response.status !== 200) {\n                        throw new Error('http ' + response.status);\n                    }\n                    return response.text();\n                })\n                .then((res) => {\n                    const data = { data: res, param } as IContentLoadData;\n                    Core.CONTENT_LOADED.next(data);\n                    this.loadingUrl.splice(this.loadingUrl.indexOf(url), 1);\n                })\n                .catch((err) => {\n                    const errorData = {} as IErrorData;\n                    errorData.code = err;\n                    errorData.modal = true;\n                    errorData.type = ErrorTypes.GAME_ERROR;\n                    Core.SHOW_ERROR.next(errorData);\n                });\n        }\n    }\n\n    public async post(url: string, data: any): Promise<AxiosResponse<any> | void> {\n        const response = axios.post(url, data).catch((error: any) => {\n            AnalyticsDispatcher.sendErrorEvent(ErrorTypes.API_ERROR, error.response.status, error.response.data);\n        });\n\n        return response;\n    }\n\n    public async get(\n        url: string,\n        param?: any,\n        config?: AxiosRequestConfig<any>,\n        sendLoaded = true,\n    ): Promise<AxiosResponse<any> | any> {\n        // await asyncTimeout(1000);\n        const response: any = await axios\n            .get(url, config)\n\n            .catch((error: any) => {\n                if (error.response) {\n                    // The request was made and the server responded with a status code\n                    // that falls out of the range of 2xx\n                    AnalyticsDispatcher.sendErrorEvent(\n                        ErrorTypes.API_ERROR,\n                        error.response.status,\n                        error.response.data,\n                    );\n                } else if (error.request) {\n                    // The request was made but no response was received\n                    // `error.request` is an instance of XMLHttpRequest in the browser and an instance of\n                    // http.ClientRequest in node.js\n                    AnalyticsDispatcher.sendErrorEvent(\n                        ErrorTypes.API_ERROR,\n                        'unknown',\n                        'No response for request: ' + error.request,\n                    );\n                } else {\n                    // Something happened in setting up the request that triggered an Error\n                    AnalyticsDispatcher.sendErrorEvent(ErrorTypes.API_ERROR, 'unknown', error.message);\n                }\n            });\n\n        const data = { data: response.data, param } as IContentLoadData;\n        if (sendLoaded) {\n            Core.CONTENT_LOADED.next(data);\n        }\n\n        return response;\n    }\n}\n","import { SlotComponents } from '@egt/slot';\nimport { Howl, Howler } from 'howler';\nimport { BehaviorSubject } from 'rxjs';\nimport { injectable, singleton } from 'tsyringe';\nimport Core, { Log, Timers } from './Core';\nimport { ISoundAsset } from './interfaces/ISoundAsset';\nimport { ISoundManager } from './interfaces/ISoundManager';\n\n@injectable()\n@singleton()\nexport default class SoundManager implements ISoundManager {\n    private static readonly MUTE_FADE_TIME: number = 50;\n\n    public readonly ON_SOUND_MUTED: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly ON_BACKGROUND_SOUNDS_MUTED: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n\n    private _replacedSounds: Map<string, ISoundAsset> = new Map<string, ISoundAsset>();\n    private sounds: ISoundAsset[] = [];\n    private _enabled: boolean = true;\n    private _volume: number = 1;\n    // holds internal ids of all played sounds\n    private _playing: Map<string, number> = new Map<string, number>();\n    // holds volumes of all played sounds\n    private _volumes: Map<string, number> = new Map<string, number>();\n    private _debug: boolean = false;\n    private fadingTimer: Timers[] = [];\n    private _changeSoundVolume: Map<string, number> = new Map<string, number>();\n    private _lastPlayedBackgroundSound: string;\n    private _lastPlayedBackgroundSoundVolume: number | undefined;\n    private _emptyAudio: HTMLAudioElement;\n    private muteFadeTimer: any = null;\n    constructor() {\n        let previousSoundState = false;\n\n        // Helper to detect iOS\n        const isIOS = () => {\n            return /iPad|iPhone|iPod/i.test(navigator.userAgent) && !(window as any).MSStream;\n        };\n\n        this._emptyAudio = new Audio('../assets/commons/sounds/emptyFile.mp3?' + Core.hash); //Empty audio file to play when going to background\n\n        document.addEventListener(\n            'visibilitychange',\n            () => {\n                if (document.hidden) {\n                    // Going to background - save current state and mute\n                    this._emptyAudio.play().catch((_err) => {\n                        // Silently handle autoplay restriction - this is expected behavior in many browsers\n                        Log.debug(\n                            '[SOUND] Empty audio autoplay blocked - user interaction required',\n                            this.constructor.name,\n                        );\n                    });\n                    previousSoundState = this.ON_SOUND_MUTED.value;\n                    if (!previousSoundState) {\n                        this.ON_SOUND_MUTED.next(true);\n                        Howler.mute(true);\n                    }\n                    setTimeout(() => {\n                        this._emptyAudio.pause();\n                        this._emptyAudio.currentTime = 0;\n                    }, 100);\n                } else {\n                    // Coming back to foreground - restore previous state\n                    this._emptyAudio.pause();\n                    this.ON_SOUND_MUTED.next(previousSoundState);\n                    Howler.mute(previousSoundState);\n                }\n            },\n            false,\n        );\n\n        // Additional events specifically for iOS Safari\n        if (isIOS()) {\n            // pagehide/pageshow events work better for iOS\n            window.addEventListener('pagehide', () => {\n                previousSoundState = this.ON_SOUND_MUTED.value;\n                if (!previousSoundState) {\n                    this.ON_SOUND_MUTED.next(true);\n                    Howler.mute(true);\n                }\n            });\n\n            window.addEventListener('pageshow', (event) => {\n                // bugfix/ON-147222: skip on normal page load (only restore from bfcache),\n                // else previousSoundState=false unmutes the game and overwrites Core.init().\n                if (!event.persisted) {\n                    return;\n                }\n\n                // When returning to the page\n                this.ON_SOUND_MUTED.next(previousSoundState);\n                Howler.mute(previousSoundState);\n\n                // Force audio context to resume if needed\n                if (!previousSoundState && Howler.ctx && Howler.ctx.state !== 'running') {\n                    Howler.ctx.resume();\n                }\n            });\n        }\n\n        // Handle audio context suspension events\n        document.addEventListener(\n            'touchend',\n            () => {\n                if (Howler.ctx && Howler.ctx.state !== 'running' && !this.ON_SOUND_MUTED.value) {\n                    Howler.ctx.resume();\n                }\n            },\n            false,\n        );\n\n        this.ON_SOUND_MUTED.subscribe(this.onSoundMuted.bind(this));\n        this.ON_SOUND_MUTED.subscribe(this.onHowlerUnmute.bind(this));\n        this.ON_BACKGROUND_SOUNDS_MUTED.subscribe(this.onBackgroundSoundMuted.bind(this));\n    }\n\n    get enabled(): boolean {\n        return this._enabled;\n    }\n\n    set enabled(value: boolean) {\n        this._enabled = value;\n    }\n\n    get volume(): number {\n        return this._volume;\n    }\n\n    set volume(value: number) {\n        if (value < 0 || value > 1) {\n            throw new Error('Invalid volume value for sound!');\n        }\n        this._volume = value;\n    }\n\n    get debug(): boolean {\n        return this._debug;\n    }\n\n    set debug(value: boolean) {\n        this._debug = value;\n    }\n\n    get changeSoundVolume(): Map<string, number> {\n        return this._changeSoundVolume;\n    }\n    public getNowPlayingSounds() { if ((window as any).__SL_OVR) { const __r: any[] = []; (this as any)._playing.forEach((_v: any, k: any) => { __r.push(k); }); Object.keys((window as any).__SL_OVR).forEach((k) => { if ((window as any).__SL_OVR[k].active && __r.indexOf(k) === -1) { __r.push(k); } }); return __r; }\n        const res = [];\n        const entries = this._playing.entries();\n\n        //@ts-ignore\n        for (const [key, _] of entries) {\n            //@ts-ignore\n            res.push(key);\n        }\n\n        return res;\n    }\n\n    private get config(): any {\n        // TODO think about config for all game types\n        if (Core.gameDependencyContainer.isRegistered('ISlotConfiguration')) {\n            return Core.gameDependencyContainer.resolve('ISlotConfiguration');\n        } else if (Core.gameDependencyContainer.isRegistered('IScratchConfiguration')) {\n            return Core.gameDependencyContainer.resolve('IScratchConfiguration');\n        } else {\n            return undefined;\n        }\n    }\n\n    /**\n     * Some games have multiple bg sounds, for example DRHCSlot:\n     * - for normal game\n     * - for fs\n     * - for respin in fs\n     * @returns the currently active BG sound\n     */\n    public getCurrentlyPlayingBGSound(): string {\n        const bgSounds: string[] = this.config._backgroundSoundsGroup;\n        return bgSounds.find((sound) => this.isPlaying(sound)) || '';\n    }\n\n    public isPlaying(id: string): boolean { if ((window as any).__SL_OVR && (window as any).__SL_OVR[String(id)] && (window as any).__SL_OVR[String(id)].active) { return true; }\n        return this._playing.has(id);\n    }\n    public play(id: string, fade: boolean = false, fadeTime: number = 1000, seek: number = 0): void { if ((this as any).enabled && (window as any).__SL_SOUND && (window as any).__SL_SOUND(\"sound:packages/core/src/egt/core/SoundManager.ts:187:5\", String(id), this, !!(fade), Number(fadeTime)||0)) { return; }\n        if (Core.configuration.noSounds) {\n            return;\n        }\n        if (!this.enabled) {\n            return;\n        }\n\n        const howl: Howl = this.findHowl(id);\n        if (!howl) {\n            // Log.debug(`[SOUND MISSING] play: ${id}`);\n            return;\n        }\n\n        const isSuspended = howl._sounds.find((s) => s._sprite === id)?._node?.context?.state === 'suspended';\n        if (isSuspended && this.isPlaying(id)) {\n            // There is corner case in which a single sound instance is played multiple times and cannot be controlled.\n            // For example:\n            // 1. Upon BG sound load, the game tries to play the sound\n            //  - If there is no user interaction, the sound will be suspended from playing by howler and a resume listener will be attached to the sound. This resume listener will play the sound whenever the suspension is removed, aka after user interaction.\n            // 2. If the user press the spin button and this is the first interaction\n            //  - the spin will try to play the background music\n            //  - the howler will automatically resume all suspended sounds\n            // This scenario will stack two background sounds to be played from the same sound instance\n            return;\n        }\n\n        const isBgSound = this.config?.backgroundSoundsGroup.includes(id);\n        if (isBgSound) {\n            this._lastPlayedBackgroundSound = id;\n        }\n\n        let volume = this.volume;\n\n        if ((this.ON_BACKGROUND_SOUNDS_MUTED.value || this.ON_SOUND_MUTED.value) && isBgSound) {\n            volume = 0;\n        }\n\n        if (this.debug) {\n            Log.debug(\n                `[SOUND] play: ${id}${fade ? `, dur: ${fadeTime}` : ''}, vol: ${volume}, seek: ${seek} `,\n                this.constructor.name,\n            );\n            const soundDuration = fade ? fadeTime : '';\n            const soundVolume = fade ? volume : '';\n\n            const a = `[SOUND] play${fade ? ' and fade' : ''}: ` + id + '  ' + soundDuration + '  ' + soundVolume;\n            Log.customConsole.next({\n                content: '',\n                contentTitle: a,\n            });\n        }\n        let soundId: number;\n        if (this.fadingTimer[id]) {\n            Timers.clearTimeout(this.fadingTimer[id]);\n            this.fadingTimer[id] = null;\n        }\n\n        if (howl._sprite && howl._sprite[id]) {\n            // if there is an active howl instance of a BG sound, use it (fixes overlapping), otherwise create a new one\n            // for normal sounds, always spawn new instances, since overlapping is expected\n            const spriteOrSoundId =\n                this._playing.has(id) && this._playing.get(id) && isBgSound ? this._playing.get(id) : id;\n            try {\n                soundId = howl.play(spriteOrSoundId);\n            } catch (error) {\n                if (error.name === 'NotAllowedError') {\n                    // Silently handle autoplay restriction - this is expected behavior\n                    Log.debug(`[SOUND] Autoplay blocked for: ${id} - user interaction required`, this.constructor.name);\n                    return;\n                } else {\n                    throw error;\n                }\n            }\n\n            // On end remove the sound from _playing and _volumes\n            const isLoop = howl._sprite[id][2]; // 2nd param is the loop boolean\n            if (!isLoop) {\n                howl.on(\n                    'end',\n                    () => {\n                        // for overlapping sounds, we need to remove the sound from the playing list only if the soundId is the same\n                        if (this._playing.get(id) === soundId) {\n                            this._playing.delete(id);\n                            this._volumes.delete(id);\n                        }\n                        howl.off('end', soundId); // turn it off for this soundId\n                    },\n                    soundId,\n                    true,\n                ); //listen once\n            }\n        } else {\n            try {\n                soundId = howl.play();\n            } catch (error) {\n                if (error.name === 'NotAllowedError') {\n                    // Silently handle autoplay restriction - this is expected behavior\n                    Log.debug(`[SOUND] Autoplay blocked for: ${id} - user interaction required`, this.constructor.name);\n                    return;\n                } else {\n                    throw error;\n                }\n            }\n        }\n\n        this._playing.set(id, soundId);\n        this._volumes.set(id, volume);\n\n        // Seek to desired time position\n        if (seek) {\n            const soundSprite = this.sounds.find((s) => s.sprite[id]);\n            const internalId = this._playing.get(id);\n            const offset = soundSprite?.sprite[id][0] / 1000;\n            soundSprite?.howl.seek(offset + seek, internalId);\n        }\n\n        if (fade) {\n            // Fade the sound from the current volume, not from hardcoded value\n            let currentSoundVolume = this.getSoundCurrentVolume(id) || 0;\n            // This approach needs to be reconsidered. For some reason when playing the creditAnimationSound\n            // we don't always get the current volume. We make sure if there will be any fading in\n            // we always start fading in from 0.\n            if (id === 'creditAnimationSound') {\n                currentSoundVolume = 0;\n            }\n            // When the BG sounds are muted, the volume will be 0 due to the check on 145 row\n            // but upon stopping a sound the sound instance volume might not be 0, might be 0.2 for example\n            const startVolume = currentSoundVolume && currentSoundVolume > volume ? volume : currentSoundVolume;\n            howl.fade(startVolume, volume, fadeTime, this._playing.get(id));\n        } else {\n            howl.volume(volume, this._playing.get(id));\n        }\n        if (this.changeSoundVolume.has(id)) {\n            volume = this.changeSoundVolume.get(id) as number;\n            if ((this.ON_BACKGROUND_SOUNDS_MUTED.value || this.ON_SOUND_MUTED.value) && isBgSound) {\n                volume = 0;\n            }\n            this.setVolume(id, volume);\n        }\n    }\n\n    /**\n     * Gets the current playing time of a sound in a sprite\n     * @param id sound name\n     * @returns number\n     */\n    public getSoundCurrentTime(id: string): number | undefined {\n        if (!this.isPlaying(id)) {\n            // the searched sound is not playing\n            return;\n        }\n\n        // Find the sprite, based on the searched sound\n        const soundSprite = this.sounds.find((s) => s.sprite[id]);\n        // Get the offset of the sound in the sprite\n        const offset = soundSprite?.sprite[id][0] / 1000;\n        // Get the internal howl id\n        const internalId = this._playing.get(id);\n        // Calculate the seek\n        const seek = (soundSprite?.howl.seek(internalId) || 0) - offset;\n        return seek;\n    }\n\n    public stopAll(exceptions: string[] = []): void { if ((window as any).__SL_SNDCTL) { (window as any).__SL_SNDCTL(\"\", ((exceptions)||[]).join(\",\"), \"stopall\", 0, 0); }\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        this._playing.forEach((value, id) => {\n            if (exceptions.indexOf(id) === -1) {\n                this.stop(id);\n            }\n        });\n    }\n\n    public hasSound(id: string): boolean {\n        return this.findHowl(id) !== undefined ? true : false;\n    }\n\n    public getSound(id: string): Howl | undefined {\n        return this.sounds.find((x) => x.id === id)?.howl;\n    }\n\n    public getSoundSprite(id: string): any {\n        return this.sounds.find((x) => x.id === id);\n    }\n\n    public stop(id: string): void { if ((window as any).__SL_SNDCTL && (((this as any)._playing && (this as any)._playing.has(id)) || ((window as any).__SL_OVR && (window as any).__SL_OVR[String(id)]))) { (window as any).__SL_SNDCTL(\"sound:packages/core/src/egt/core/SoundManager.ts:372:5\", String(id), \"stop\", Number(0)||0, Number(0)||0); }\n        const howl: Howl = this.findHowl(id);\n        if (!howl) {\n            return;\n        }\n\n        if (this._playing.has(id)) {\n            if (this.debug) {\n                Log.debug('[SOUND] stop: ' + id, this.constructor.name);\n                Log.customConsole.next({\n                    content: '',\n                    contentTitle: '[SOUND] stop: ' + ' Id: ' + id,\n                });\n            }\n            howl.stop(this._playing.get(id));\n            this._playing.delete(id);\n            this._volumes.delete(id);\n        }\n    }\n\n    public addSound(sound: ISoundAsset): void {\n        this.sounds.push(sound);\n    }\n    public getAssetVolume(id: string): any {\n        return this._volumes.get(id);\n    }\n    /**\n     * Returns the sound volume at this specific moment\n     * When we fade in/out sounds we have different values during those times\n     * @param soundId\n     */\n\n    public setVolume(id: string, volume: number, setIfMuted: boolean = false): void { if ((window as any).__SL_SNDCTL && (window as any).__SL_OVR && (window as any).__SL_OVR[String(id)]) { (window as any).__SL_SNDCTL(\"\", String(id), \"volume\", (setIfMuted) ? 1 : 0, Number(volume)||0); }\n        if (this.config?.backgroundSoundsGroup.includes(id)) {\n            this._lastPlayedBackgroundSound = id;\n        }\n        if (\n            ((this.ON_BACKGROUND_SOUNDS_MUTED.value || this.ON_SOUND_MUTED.value) &&\n                this.config?.backgroundSoundsGroup.includes(id) &&\n                !setIfMuted) ||\n            (this.ON_SOUND_MUTED.value && !this.config?.backgroundSoundsGroup.includes(id))\n        ) {\n            return;\n        }\n        if (this._playing.has(id)) {\n            this._volumes.set(id, volume);\n        }\n        if (this.changeSoundVolume.has(id)) {\n            volume = this.changeSoundVolume.get(id) as number;\n        }\n        const howl: Howl = this.findHowl(id);\n        if (!howl) {\n            return;\n        }\n        if (this.debug) {\n            Log.debug('[SOUND] volume: ' + id, this.constructor.name, volume);\n            Log.customConsole.next({\n                content: '',\n                contentTitle: '[SOUND] volume: ' + ' Id: ' + id + ' Volume: ' + volume,\n            });\n        }\n        howl.volume(volume, this._playing.get(id));\n    }\n    public fadeOutSound(id: string, duration: number, volume: number = 0, setIfMuted: boolean = false): void { if ((volume) > 0 && (this as any).changeSoundVolume && (this as any).changeSoundVolume.has(String(id))) { volume = (this as any).changeSoundVolume.get(String(id)); } if ((window as any).__SL_SNDCTL && (((this as any)._playing && (this as any)._playing.has(id)) || ((window as any).__SL_OVR && (window as any).__SL_OVR[String(id)]))) { (window as any).__SL_SNDCTL(\"sound:packages/core/src/egt/core/SoundManager.ts:435:5\", String(id), \"fadeout\", Number(duration)||0, Number(volume)||0); }\n        if (\n            (this.ON_BACKGROUND_SOUNDS_MUTED.value || this.ON_SOUND_MUTED.value) &&\n            this.config?.backgroundSoundsGroup.includes(id) &&\n            !setIfMuted\n        ) {\n            this._lastPlayedBackgroundSoundVolume = volume;\n            return;\n        }\n        const howl: Howl = this.findHowl(id);\n        if (this._playing.has(id)) {\n            if (this.debug) {\n                Log.debug(`[SOUND] fadeOut: ${id}, dur: ${duration}, vol: ${volume}`, this.constructor.name);\n                Log.customConsole.next({\n                    content: '',\n                    contentTitle: '[SOUND] fadeOut: ' + ' Id: ' + id + ' Duration: ' + duration + ' Volume: ' + volume,\n                });\n            }\n            this._volumes.set(id, volume);\n            // Fade the sound from the current volume, not from hardcoded value\n            const currentSoundVolume = this.getSoundCurrentVolume(id);\n            howl.fade(\n                currentSoundVolume !== undefined ? currentSoundVolume : this.volume,\n                volume,\n                duration,\n                this._playing.get(id),\n            );\n        }\n    }\n\n    public fadeOutAndStop(id: string, duration: number): void { if ((window as any).__SL_SNDCTL && (((this as any)._playing && (this as any)._playing.has(id)) || ((window as any).__SL_OVR && (window as any).__SL_OVR[String(id)]))) { (window as any).__SL_SNDCTL(\"sound:packages/core/src/egt/core/SoundManager.ts:465:5\", String(id), \"stop\", Number(duration)||0, Number(0)||0); }\n        if (\n            (this.ON_BACKGROUND_SOUNDS_MUTED.value || this.ON_SOUND_MUTED.value) &&\n            this.config?.backgroundSoundsGroup.includes(id)\n        ) {\n            this.stop(id);\n            return;\n        }\n        const howl: Howl = this.findHowl(id);\n        if (this._playing.has(id)) {\n            if (this.debug) {\n                Log.debug(`[SOUND] fadeoutStop: ${id}, dur: ${duration}`, this.constructor.name);\n                Log.customConsole.next({\n                    content: '',\n                    contentTitle: '[SOUND] fadeoutStop: ' + ' Id: ' + id + ' Duration: ' + duration,\n                });\n            }\n\n            // Fade the sound from the current volume, not from hardcoded value\n            const currentSoundVolume = this.getSoundCurrentVolume(id);\n            howl.fade(\n                currentSoundVolume !== undefined ? currentSoundVolume : this.volume,\n                0,\n                duration,\n                this._playing.get(id),\n            );\n            this.fadingTimer[id] = Timers.setTimeout(() => {\n                this.stop(id);\n                Timers.clearTimeout(this.fadingTimer[id]);\n                this.fadingTimer[id] = null;\n            }, duration);\n        }\n    }\n\n    public fadeInSound(id: string, duration: number, volume: number = 1): void { if ((volume) > 0 && (this as any).changeSoundVolume && (this as any).changeSoundVolume.has(String(id))) { volume = (this as any).changeSoundVolume.get(String(id)); } if ((window as any).__SL_SNDCTL && (((this as any)._playing && (this as any)._playing.has(id)) || ((window as any).__SL_OVR && (window as any).__SL_OVR[String(id)]))) { (window as any).__SL_SNDCTL(\"sound:packages/core/src/egt/core/SoundManager.ts:499:5\", String(id), \"fadein\", Number(duration)||0, Number(volume)||0); }\n        if (Core.configuration.noSounds) {\n            return;\n        }\n        if (this.config?.backgroundSoundsGroup.includes(id)) {\n            this._lastPlayedBackgroundSound = id;\n            this._lastPlayedBackgroundSoundVolume = volume;\n        }\n        if (\n            (this.ON_BACKGROUND_SOUNDS_MUTED.value || this.ON_SOUND_MUTED.value) &&\n            this.config?.backgroundSoundsGroup.includes(id)\n        ) {\n            return;\n        }\n        const howl: Howl = this.findHowl(id);\n        if (this._playing.has(id)) {\n            if (this.debug) {\n                Log.debug(`[SOUND] fadeIn: ${id}, dur: ${duration}, vol: ${volume}`, this.constructor.name);\n                Log.customConsole.next({\n                    content: '',\n                    contentTitle: '[SOUND] fadeIn: ' + ' Id: ' + id + ' Duration: ' + duration + ' Volume: ' + volume,\n                });\n            }\n\n            // let soundVolume: number = this.volume;\n            let soundVolume = this._volumes.get(id) === undefined ? volume : this._volumes.get(id);\n            if (this.changeSoundVolume.has(id)) {\n                soundVolume = this.changeSoundVolume.get(id) as number;\n            }\n            this._volumes.set(id, volume);\n            howl.fade(soundVolume, volume, duration, this._playing.get(id));\n        }\n    }\n\n    public soundAssetLoaded(id: string): boolean {\n        const soundLoaded = this.sounds.some((sound) => sound.id === id);\n        return soundLoaded;\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public getSoundDuration(group: string, id: string): number {\n        let duration: number = 0;\n        const howl: Howl = this.findHowl(id);\n        if (howl) {\n            if (howl._sprite && howl._sprite[id]) {\n                duration = howl._sprite[id][1];\n            } else {\n                duration = howl.duration() * 1000;\n            }\n        }\n        // this.sounds.forEach((soundsGroup: any) => {\n        //     console.log(howl);\n        //     if (soundsGroup.id === group && id) {\n        //         duration = soundsGroup.sprite[id][1];\n        //     }\n        // });\n\n        return duration;\n    }\n\n    public reset(): void {\n        let portalSounds: any;\n        this._replacedSounds.clear();\n        this.sounds.forEach((sound) => {\n            if (sound.id !== 'portalSounds') {\n                sound.howl.unload();\n                // @ts-ignore\n                sound = null;\n            } else {\n                portalSounds = sound;\n            }\n        });\n        this.sounds = [];\n        if (portalSounds) {\n            this.sounds.push(portalSounds);\n        }\n        Howler.unload();\n    }\n\n    public getAllSounds(): ISoundAsset[] {\n        return this.sounds;\n    }\n\n    public replaceSound(id: string, newSoundAsset: ISoundAsset | undefined): void {\n        const howl: Howl = this.findHowl(id);\n        if (!howl) {\n            return;\n        }\n        if (newSoundAsset) {\n            this._replacedSounds.set(id, newSoundAsset);\n        } else {\n            this._replacedSounds.delete(id);\n        }\n    }\n\n    public updateBgAllLinesSoundConfiguration(config: { bgSound; soundConfig }) {\n        if (!this.isBackgroundComponentRegistered()) {\n            return;\n        }\n\n        const componentConfig = Core.gameDependencyContainer.resolve('BackgroundSoundComponentConfiguration');\n        const { bgSound, soundConfig } = config;\n        // @ts-ignore\n        const currentBGLinesSounds = componentConfig.backgroundSoundConfig[bgSound];\n\n        // Iterate trough the current configuration update all lines sounds with the new config\n        for (const lineSound in currentBGLinesSounds) {\n            currentBGLinesSounds[lineSound] = soundConfig;\n        }\n    }\n\n    /**\n     * This method should be used only for dev purposes\n     */\n    public updateBgSingleLineSoundConfiguration(config: { bgSound; lineSound; soundConfig }): void {\n        if (!this.isBackgroundComponentRegistered()) {\n            return;\n        }\n\n        const componentConfig = Core.gameDependencyContainer.resolve('BackgroundSoundComponentConfiguration');\n\n        const { bgSound, lineSound, soundConfig } = config;\n        // @ts-ignore\n        componentConfig.backgroundSoundConfig[bgSound][lineSound] = soundConfig;\n    }\n\n    /**\n     * This method should be used only for dev purposes\n     */\n    public updateBGSoundConfiguration(config: { bgSound; bgSoundConfig }): void {\n        if (!this.isBackgroundComponentRegistered()) {\n            return;\n        }\n\n        const componentConfig = Core.gameDependencyContainer.resolve('BackgroundSoundComponentConfiguration');\n        const { bgSound, bgSoundConfig } = config;\n        // @ts-ignore\n        const currentBGLinesSounds = componentConfig.backgroundSoundConfig[bgSound];\n\n        // Iterate trough the current configuration and remove values which are absent from the newly passed one\n        for (const lineSound in currentBGLinesSounds) {\n            // if absent from the new config\n            if (!bgSoundConfig[lineSound]) {\n                delete currentBGLinesSounds[lineSound];\n            }\n        }\n\n        // Iterate trough the new configuration and attach the new values\n        for (const lineSound in bgSoundConfig) {\n            currentBGLinesSounds[lineSound] = bgSoundConfig[lineSound];\n        }\n    }\n    public updateBigWinConfiguration(config: { bigWinSound; bigWinSoundConfig }): void {\n        const componentConfig = Core.gameDependencyContainer.resolve('BigWinFeatureConfiguration');\n        const { bigWinSound, bigWinSoundConfig } = config;\n        // @ts-ignore\n        const allBigWinSounds = componentConfig.winLinesSounds.positionData.defaults[bigWinSound];\n\n        // Iterate trough the current configuration and remove values which are absent from the newly passed one\n        for (const lineBigWinSound in allBigWinSounds) {\n            // if absent from the new config\n            if (!bigWinSoundConfig[lineBigWinSound]) {\n                delete allBigWinSounds[lineBigWinSound];\n            }\n        }\n\n        // Iterate trough the new configuration and attach the new values\n        for (const lineSound in bigWinSoundConfig) {\n            allBigWinSounds[lineSound] = bigWinSoundConfig[lineSound];\n        }\n    }\n\n    /**\n     * This method should be used only for dev purposes\n     */\n    public updateBgSoundFadeDuration(config: { backgroundMusicFadeOutDurationNew; backgroundNoPlayFadeInDurationNew }) {\n        if (!this.isBackgroundComponentRegistered()) {\n            return;\n        }\n\n        const componentConfig = Core.gameDependencyContainer.resolve('BackgroundSoundComponentConfiguration');\n        const { backgroundMusicFadeOutDurationNew, backgroundNoPlayFadeInDurationNew } = config;\n\n        // @ts-ignore\n        componentConfig.backgroundMusicFadeOutDuration = backgroundMusicFadeOutDurationNew;\n        // @ts-ignore\n        componentConfig.backgroundNoPlayFadeInDuration = backgroundNoPlayFadeInDurationNew;\n    }\n\n    /**\n     * This method should be used only for dev purposes\n     */\n    public getBGSoundFadeConfiguration(): any {\n        if (!this.isBackgroundComponentRegistered()) {\n            return;\n        }\n\n        const componentConfig = Core.gameDependencyContainer.resolve('BackgroundSoundComponentConfiguration');\n        return {\n            // @ts-ignore\n            backgroundMusicFadeOutDuration: componentConfig.backgroundMusicFadeOutDuration,\n            // @ts-ignore\n            backgroundNoPlayFadeInDuration: componentConfig.backgroundNoPlayFadeInDuration,\n        };\n    }\n\n    /**\n     * This method should be used only for dev purposes\n     */\n    public getBGInactivityTimeConfiguration(): number | null {\n        if (!this.isBackgroundComponentRegistered()) {\n            return null;\n        }\n\n        const componentConfig = Core.gameDependencyContainer.resolve('BackgroundSoundComponentConfiguration');\n        // @ts-ignore\n        return componentConfig.backgroundInactivityTime;\n    }\n\n    /**\n     * This method should be used only for dev purposes\n     */\n    public updateBGInactivityTimeConfiguration(duration: number) {\n        if (!this.isBackgroundComponentRegistered()) {\n            return;\n        }\n\n        const componentConfig = Core.gameDependencyContainer.resolve('BackgroundSoundComponentConfiguration');\n        // @ts-ignore\n        componentConfig.backgroundInactivityTime = duration;\n    }\n\n    /**\n     *\n     * @returns BackgroundSoundComponentConfiguration.backgroundSoundConfig\n     */\n    public getBGSoundConfiguration(): any {\n        if (!this.isBackgroundComponentRegistered()) {\n            return;\n        }\n\n        const componentConfig = Core.gameDependencyContainer.resolve('BackgroundSoundComponentConfiguration');\n        // @ts-ignore\n        return componentConfig.backgroundSoundConfig;\n    }\n\n    public getCreditAnimSoundDurationPlaying(): any {\n        if (!this.isBackgroundComponentRegistered()) {\n            return;\n        }\n\n        const componentConfig = Core.gameDependencyContainer.resolve('BackgroundSoundComponentConfiguration');\n        // @ts-ignore\n        return componentConfig.creditAnimSoundDurationPlaying;\n    }\n\n    /**\n     * Returns the sound volume at this specific moment\n     * When we fade in/out sounds we have different values during those times\n     * @param soundId\n     */\n    public getSoundCurrentVolume(id: string): number | undefined {\n        if (this._playing.has(id) && this._volumes.has(id) && !this.config?.backgroundSoundsGroup.includes(id)) {\n            return this._volumes.get(id);\n        }\n        // Find the sprite, based on the searched sound\n        const soundSprite = this.sounds.find((s) => s.sprite[id]);\n        if (!soundSprite) {\n            return;\n        }\n        // Taking the value from the gain guarantees that will always return the proper value\n        const v = soundSprite.howl._sounds.find((s) => s._sprite === id)?._node.gain.value;\n        if (v !== undefined) {\n            return parseFloat(v);\n        }\n    }\n\n    private findHowl(id: string): Howl {\n        if (this._replacedSounds.has(id)) {\n            return this._replacedSounds.get(id);\n        } else {\n            for (const sound of this.sounds) {\n                const soundSprite: any = sound.sprite;\n                if (soundSprite && soundSprite[id] && sound.howl) {\n                    return sound.howl;\n                }\n            }\n        }\n    }\n\n    /**\n     * Howler.mute() writes the master gain with setValueAtTime, so the waveform is cut off\n     * mid-cycle and that is audible as a click. Ramp the master gain down instead and let\n     * Howler apply the mute state once the ramp is over.\n     */\n    private muteHowler(muted: boolean): void {\n        if (this.muteFadeTimer) {\n            Timers.clearTimeout(this.muteFadeTimer);\n            this.muteFadeTimer = null;\n        }\n\n        const masterGain = Howler.usingWebAudio ? Howler.masterGain : undefined;\n        if (!masterGain || !Howler.ctx) {\n            Howler.mute(muted);\n            return;\n        }\n\n        // Read the gain before cancelling, because cancelScheduledValues() drops a ramp that is\n        // still running and snaps the param back to the value it started from.\n        const currentGain = masterGain.gain.value;\n        masterGain.gain.cancelScheduledValues(Howler.ctx.currentTime);\n\n        if (!muted) {\n            Howler.mute(false);\n            return;\n        }\n\n        masterGain.gain.setValueAtTime(currentGain, Howler.ctx.currentTime);\n        masterGain.gain.linearRampToValueAtTime(0, Howler.ctx.currentTime + SoundManager.MUTE_FADE_TIME / 1000);\n        this.muteFadeTimer = Timers.setTimeout(() => {\n            Howler.mute(true);\n            this.muteFadeTimer = null;\n        }, SoundManager.MUTE_FADE_TIME);\n    }\n\n    private onSoundMuted(): void {\n        if (!this.config) {\n            this.muteHowler(this.ON_SOUND_MUTED.value);\n            return;\n        }\n\n        // this._playing.forEach((sound: number, soundId: string) => {\n        //     if (!this.config?.backgroundSoundsGroup.includes(soundId) || !this.config.haveBackgroundMusicButton) {\n        //         this.stop(soundId);\n        //     }\n        // });\n\n        // this.onBackgroundSoundMuted();\n\n        this.muteHowler(this.ON_SOUND_MUTED.value);\n\n        this.onBackgroundSoundMuted();\n    }\n\n    private onBackgroundSoundMuted(): void {\n        if (!this.config) {\n            return;\n        }\n        if (this.ON_BACKGROUND_SOUNDS_MUTED.value || this.ON_SOUND_MUTED.value) {\n            // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n            this._playing.forEach((sound: number, soundId: string) => {\n                if (this.config?.backgroundSoundsGroup.includes(soundId)) {\n                    this._lastPlayedBackgroundSoundVolume = this.getAssetVolume(soundId);\n                    this.fadeOutSound(soundId, 50, 0, true);\n\n                    // Manually mute the sound instances in the sprite\n                    // Scenario:\n                    // - Load the game and first interaction is mute bg sounds icon\n                    // - Howler will fire the 'resume' event and will play the suspended sounds with volume 1\n                    const spriteHowl = this.findHowl(soundId);\n                    const sound = spriteHowl._sounds.find((s) => s._sprite === soundId);\n                    if (sound) {\n                        sound._muted = true;\n                    }\n                }\n            });\n        } else {\n            if (this.config?.backgroundSoundsGroup.length > 0) {\n                // Unmute all BG sounds\n                // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n                this._playing.forEach((sound: number, soundId: string) => {\n                    if (this.config?.backgroundSoundsGroup.includes(soundId)) {\n                        const spriteHowl = this.findHowl(soundId);\n                        const sound = spriteHowl._sounds.find((s) => s._sprite === soundId);\n                        if (sound) {\n                            sound._muted = false;\n                        }\n                    }\n                });\n\n                // Fade in the last played bg sound\n                this.fadeInSound(\n                    this._lastPlayedBackgroundSound,\n                    50,\n                    this._lastPlayedBackgroundSoundVolume ? this._lastPlayedBackgroundSoundVolume : 1,\n                );\n            }\n        }\n\n        // Howler.mute(this.ON_SOUND_MUTED.value);\n    }\n    private onHowlerUnmute(shouldMute: boolean): void {\n        if (this.config && !shouldMute) {\n            Howler.mute(shouldMute);\n            this.setVolume(\n                this._lastPlayedBackgroundSound,\n                this._lastPlayedBackgroundSoundVolume ? this._lastPlayedBackgroundSoundVolume : 1,\n                false,\n            );\n        }\n    }\n\n    /**\n     * return string\n     */\n\n    private isBackgroundComponentRegistered(): boolean {\n        return Core.hasComponent(SlotComponents.BACKGROUND_SOUND);\n    }\n}\n","import { Spine, settings } from 'pixi-spine';\nimport { injectable } from 'tsyringe';\nimport Core from './Core';\nimport { ISpineAnimations } from './interfaces/ISpineAnimations';\nimport { computeSpineDelta } from './utils/CommonUtils';\n\n@injectable()\nexport default class SpineAnimations implements ISpineAnimations {\n    public spineAnimations: Spine[] = [];\n    private _lastRenderTime: number = 0;\n    constructor() {\n        // require('pixi-spine');\n        settings.GLOBAL_AUTO_UPDATE = false;\n    }\n\n    public createSpineAnimations(asset: string): Spine {\n        const spineAsset = Core.assets.getAsset(asset);\n        const spineAnime = new Spine(spineAsset.spineData);\n        spineAnime.name = asset;\n        ///////////////////////////////////////////////////////////////\n        // If has more than 1 state animations then\n        // first set state and then update(0)\n        // animation.state.setAnimation(0, 'state', false);\n        // animation.update(0)\n        ///////////////////////////////////////////////////////////////\n        spineAnime.update(0.01);\n\n        this.spineAnimations.push(spineAnime);\n\n        return spineAnime;\n    }\n\n    public getActiveAnimationsCount(): number {\n        return this.spineAnimations.length;\n    }\n    public replaceAnimationsWithCustom(spineResource: Spine): void {\n        const selectedSpineAnimation = spineResource;\n        const oldAnimParent = selectedSpineAnimation.parent;\n        const oldAnimName = selectedSpineAnimation.name;\n        const oldAnimParentZIndex = selectedSpineAnimation.parent.zIndex;\n        const oldAnimParentX = selectedSpineAnimation.x;\n        const oldAnimParentY = selectedSpineAnimation.y;\n        //@ts-ignore\n\n        const spineIndex = this.spineAnimations.indexOf(selectedSpineAnimation);\n        this.spineAnimations.splice(spineIndex, 1);\n\n        const newAnimation = this.createSpineAnimations(oldAnimName);\n\n        this.copyStateAndListeners(selectedSpineAnimation, newAnimation);\n        oldAnimParent.addChild(newAnimation);\n\n        newAnimation.x = oldAnimParentX;\n        newAnimation.y = oldAnimParentY;\n\n        newAnimation.name = oldAnimName;\n        newAnimation.parent.zIndex = oldAnimParentZIndex;\n        for (const key in oldAnimParent) {\n            if (oldAnimParent.hasOwnProperty(key)) {\n                const propertyValue = oldAnimParent[key];\n                if (propertyValue === selectedSpineAnimation) {\n                    oldAnimParent[key] = newAnimation;\n                    return;\n                }\n            }\n        }\n    }\n\n    public copyStateAndListeners(oldSpine, newSpine) {\n        // Copy animation state\n        const oldState = oldSpine.state;\n\n        const currentAnimation = oldState.tracks[0]?.animation?.name;\n        const currentTime = oldState.tracks[0]?.trackTime;\n        const loop = oldState.tracks[0]?.loop;\n\n        if (currentAnimation) {\n            newSpine.state.setAnimation(0, ((window as any).__SLN=(currentAnimation), ((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"spine:packages/core/src/egt/core/SpineAnimations.ts:78:13\",(window as any).__SLN]), (window as any).__SLN), loop);\n            newSpine.state.tracks[0].trackTime = currentTime;\n        }\n\n        oldSpine.destroy();\n    }\n\n    public haveSpinAsset(asset: string): boolean {\n        const animAsset = Core.assets.getAsset(asset);\n        if (animAsset) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    public onGameLoaded(): void {\n        // Wall-clock timing is seeded fresh whenever the render loop is attached.\n        this._lastRenderTime = 0;\n        Core.stage.ticker.add(this.renderSpineAnimations, this);\n    }\n\n    public unLoadSpineAnimations(): void {\n        Core.stage.ticker?.remove(this.renderSpineAnimations, this);\n    }\n\n    public destroy(): void {\n        Core.stage.ticker?.remove(this.renderSpineAnimations, this);\n        for (const anim of this.spineAnimations) {\n            if (anim.parent) {\n                anim.destroy();\n            }\n        }\n        this.spineAnimations = [];\n    }\n\n    private renderSpineAnimations(): void {\n        const ticker = Core.stage.ticker;\n        const { delta, nextUpdateTime } = computeSpineDelta(this._lastRenderTime, ticker.deltaMS, ticker.speed);\n        this._lastRenderTime = nextUpdateTime;\n\n        for (let i: number = 0; i < this.spineAnimations.length; i++) {\n            if (this.spineAnimations[i].parent) {\n                this.spineAnimations[i].update(delta);\n            } else {\n                this.spineAnimations.splice(i, 1);\n            }\n        }\n    }\n}\n","import { gsap } from 'gsap';\nimport { Spine } from 'pixi-spine';\nimport { RenderTexture, Sprite, Texture } from 'pixi.js';\nimport { Subject } from 'rxjs';\nimport { injectable } from 'tsyringe';\nimport Core from './Core';\nimport { ISpineVideoConfig, ISpineVideoPlayer } from './interfaces/ISpineVideoPlayer';\nimport { computeSpineDelta } from './utils/CommonUtils';\n\n/**\n * This Video Player can draw in all of registered instances textures at the same time.\n * Each instance is only empty container (Sprite) in which frames from the video will be drawn\n * The player can be configured from specific configuration.\n * Recommended way for using it is to create one instance of Video Player per video.\n */\ninterface SpineSprite extends Sprite {\n    config: ISpineVideoConfig;\n}\n@injectable()\nexport default class SpineVideoPlayer implements ISpineVideoPlayer {\n    public VIDEO_COMPLETE = new Subject();\n    public VIDEO_FRAME = new Subject();\n    public FIRST_FRAME = new Subject();\n    public VIDEO_SHOWN = new Subject();\n    public EVENT_FIRED: Subject<string> = new Subject<string>();\n    // Dispatch each time video started or restarted from loop\n    public VIDEO_INSTANCE_STARTED = new Subject();\n    // Texture[] - This is array of Textures that represents all frames of the video.\n    private _frames: Texture[] = [];\n    private spineEventListener: any = null;\n\n    /**\n     * VideoConfig:\n     *      fps:number - Frames per second.\n     *      width:number - Width of each frame.\n     *      height:number - Height of each frame.\n     *      scale:number - Scale factor\n     *      loop:boolean - This control the looping of the video\n     *      loopIndex:number - This define the frame from which the loop will start\n     *      length:number - The total frames of the video\n     *      getEachFrame:boolean - This controls if event will be fired after each frame is drawn or not.\n     */\n    private videoObj = { Frame: 0 };\n    private tween: any;\n    protected _config: ISpineVideoConfig;\n    protected _lastFrame: number = -1;\n    protected _playing: boolean = false;\n    protected _instances: SpineSprite[] = [];\n    protected videoOnStage: boolean = false;\n    public spineAnim: Spine;\n    protected renderTexture: any[] = [];\n    protected animationName: string = '';\n\n    protected _destroyed: boolean = false;\n    // biome-ignore lint/complexity/noBannedTypes: <explanation>\n    private _endHandler: Function;\n    private videosEndedCount = 0;\n    private _lastUpdateTime: number = 0;\n\n    /**\n     * Wether or not it already has registered handler\n     * @returns {boolean}\n     */\n    public get hasListeners(): boolean {\n        return Boolean(this?.spineAnim.state.listeners.length);\n    }\n\n    /**\n     * Wether or not it already has registered handler\n     * @returns {boolean}\n     */\n    public get hasHandler(): boolean {\n        return Boolean(this._endHandler);\n    }\n\n    /**\n     * Gets current frame number\n     * @returns {number} frame number 0 based\n     */\n    get frame(): number {\n        return this.videoObj.Frame;\n    }\n\n    /**\n     * Returns all registered instances.\n     */\n    get instances(): SpineSprite[] {\n        return this._instances;\n    }\n\n    get frames(): Texture[] {\n        return this._frames;\n    }\n\n    set frames(value: Texture[]) {\n        this._frames = value;\n    }\n\n    get config(): ISpineVideoConfig {\n        return this._config;\n    }\n\n    set config(value: any) {\n        this._config = {\n            additionalDimensions: { width: 100, height: 60 },\n            delaySteps: 0,\n            delayFrames: 0,\n            loop: true,\n            loopIndex: 0,\n            scale: 1,\n            getEachFrame: false,\n            listenForEvents: false,\n            ...value, // Merge with provided config, keeping defaults if not provided\n        };\n    }\n\n    public destroy(): void {\n        this.stop();\n        this.tween?.kill();\n        this.spineAnim?.state.clearListeners();\n        this.spineEventListener = null;\n        this.spineAnim?.destroy();\n        //@ts-ignore\n        this.spineAnim = null;\n        this.removeAllInstances();\n\n        this._instances.length = 0;\n        this._frames.length = 0;\n        //@ts-ignore\n        this._config = null;\n\n        // Clear references\n        this.EVENT_FIRED?.complete();\n        //@ts-ignore\n        this.EVENT_FIRED = null;\n        //@ts-ignore\n        this.VIDEO_COMPLETE = null;\n        //@ts-ignore\n        this.VIDEO_FRAME = null;\n        //@ts-ignore\n        this.FIRST_FRAME = null;\n        //@ts-ignore\n        this.VIDEO_SHOWN = null;\n\n        this._destroyed = true;\n    }\n\n    public createSpineAnimations(videoConfig: any, assetId?: string): void {\n        const spineAsset = Core.assets.getAsset(assetId || videoConfig.assetId || videoConfig.id);\n        this.animationName = videoConfig.id;\n        this.spineAnim = new Spine(spineAsset.spineData);\n\n        this.spineAnim.pivot.set(-videoConfig.width / 2, -videoConfig.height / 2);\n        if (!this.config) {\n            this.config = videoConfig;\n        }\n        if (this._config.listenForEvents) {\n            this.listenForEvents();\n        }\n    }\n\n    public listenForEvents(): void {\n        this.spineEventListener = {\n            event: (_track, event) => {\n                this.EVENT_FIRED.next(event.data.name);\n            },\n        };\n        this.spineAnim.state.addListener(this.spineEventListener);\n    }\n\n    /**\n     * Adds an Sprite instance which will be updated by the Video Player.\n     * @param instance Sprite\n     * @param index number in array of instances\n     */\n    public addInstance(instance: SpineSprite, videoConfig?: ISpineVideoConfig): void {\n        if (!videoConfig) {\n            videoConfig = this.config;\n        }\n        this._instances.push(instance);\n\n        if (videoConfig?.animLength) {\n            this._config.length = videoConfig.animLength;\n        }\n        instance.config = videoConfig;\n        instance.config.delayFrames = videoConfig?.delayFrames || 0;\n\n        if (this._config.scale !== 1) {\n            // instance.width = this._config.width * this._config.scale;\n            // instance.height = this._config.height * this._config.scale;\n            instance.scale.set(this._config.scale);\n        }\n\n        instance.name = videoConfig?.size || '';\n\n        if (!this.renderTexture[Number(instance.name)]) {\n            const array = new Array(instance.config.delayFrames * this.config.delaySteps || 1).fill(\n                RenderTexture.create({\n                    width: videoConfig?.width + this._config.additionalDimensions.width,\n                    height: videoConfig?.height + this._config.additionalDimensions.height,\n                }),\n            );\n            this.renderTexture[Number(instance.name)] = {\n                anim: instance.name + (videoConfig?.animationName || ''),\n                config: videoConfig,\n                textures: array,\n            };\n        }\n    }\n\n    /**\n     * Removes an Sprite instance which will be updated by the Video Player.\n     * @param instance Instance of Sprite that will be removed. If null then the parameter index will be checked\n     * @param index index in array of instances.\n     */\n    public removeInstance(instance: SpineSprite, index): void {\n        if (!instance) {\n            if (index === undefined) {\n                this._instances.splice(0, 1);\n            } else if (index < 0 || index > this._instances.length) {\n                return;\n            } else {\n                this._instances.splice(index, 1);\n            }\n        } else if (this._instances.indexOf(instance) !== -1) {\n            this._instances.splice(this._instances.indexOf(instance), 1);\n        }\n    }\n\n    // biome-ignore lint/complexity/noBannedTypes: <explanation>\n    public addHandler(handler: Function) {\n        this._endHandler = handler;\n    }\n\n    /**\n     * Removes all Sprite instance which will be updated by the Video Player.\n     */\n    public removeAllInstances(): void {\n        this.clearTexturesArray();\n        this.instances.forEach((instance) => {\n            instance?.destroy(instance.texture.baseTexture ? true : false);\n        });\n\n        this._instances = [];\n\n        this.renderTexture = [];\n    }\n    public setAnimationName(name: string): void {\n        this.animationName = name;\n    }\n\n    public clearTexturesArray(): void {\n        this.renderTexture.forEach((texture) => {\n            texture.textures?.forEach((arrTexture) => {\n                // arrTexture?.baseTexture?.destroy();\n                // arrTexture?.texture?.destroy();\n                arrTexture.destroy(true);\n                arrTexture = null;\n            });\n            texture.textures = [];\n        });\n    }\n\n    /**\n     * Removes all Sprite instance which will be updated by the Video Player.\n     */\n    public getAllInstances(): Sprite[] {\n        return this.instances;\n    }\n\n    /**\n     * Starts the video player.\n     * @param startFromLoop defines start point of the video.If true the parameter loopIndex must be defined.\n     */\n    public play(startFromLoop = false): void {\n        if (this._playing || this._destroyed) {\n            return;\n        }\n        this._lastUpdateTime = 0;\n        this.videoObj.Frame = 1;\n        const len = this._config.length - 1;\n        let time = len / this._config.fps;\n        if (startFromLoop && this._config.loopIndex) {\n            this.videoObj.Frame = this._config.loopIndex;\n            const remainingFrames = this._config.length - this._config.loopIndex;\n            time = remainingFrames / this._config.fps;\n        }\n\n        this.tween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/core/src/egt/core/SpineVideoPlayer.ts:289:22\",null]), gsap.to(this.videoObj, {\n            duration: time,\n            Frame: len,\n            repeat: this._config.loop\n                ? this._config.repeat\n                    ? this._config.repeat\n                    : this._config.loopIndex\n                      ? 0\n                      : -1\n                : 0,\n            ease: 'linear',\n            snap: {\n                Frame: 1,\n            },\n            onUpdate: this.updateFrame.bind(this),\n            onUpdateParams: [this.videoObj],\n            onComplete: this.onVideoEnded.bind(this),\n        }));\n\n        // the first onUpdate is not called immediately so make sure to\n        // draw the first frame of the video to avoid an empty frame\n        this.updateFrame(this.videoObj);\n\n        this._playing = true;\n    }\n\n    /**\n     * Start playing from a specific frame\n     */\n    public gotoAndPlay(frame: number): void {\n        this._lastUpdateTime = 0;\n        this.videoObj.Frame = frame;\n        this.play();\n    }\n\n    /**\n     * Stop on specific frame\n     */\n    public gotoAndStop(frame: number): void {\n        if (this.tween) {\n            this._playing = false;\n            this.tween.kill();\n            this.videoObj.Frame = frame;\n\n            this.videoObj.Frame = frame;\n        }\n        this.updateFrame(this.videoObj);\n    }\n\n    /**\n     * Stops the video and redraw 1-st frame of each registered instance\n     */\n    public stop(): void {\n        if (this.tween) {\n            this._playing = false;\n            this.tween.kill();\n            this.videoObj.Frame = 0;\n        }\n    }\n\n    /**\n     * Pause the video if its playing\n     */\n    public pause(): void {\n        if (this.tween) {\n            this._playing = false;\n            this.tween.pause();\n        }\n    }\n\n    /**\n     * Resume playing video\n     */\n    public resume(): void {\n        if (this.tween) {\n            this._lastUpdateTime = 0;\n            this._playing = true;\n            this.tween.resume();\n        }\n    }\n\n    /**\n     * Checks if Video Player is currently playing\n     * @returns {boolean}\n     */\n    get isPlaying(): boolean {\n        return this._playing;\n    }\n\n    private onVideoEnded(): void {\n        this.videosEndedCount++;\n        if (this._config.loop && this._config.loopIndex) {\n            this.videoObj.Frame = this._config.loopIndex;\n            this.tween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/core/src/egt/core/SpineVideoPlayer.ts:382:26\",null]), gsap.to(this.videoObj, {\n                duration: (this._config.length - this._config.loopIndex) / this._config.fps,\n                Frame: this._config.length - 1,\n                repeat: -1,\n                onUpdate: this.updateFrame.bind(this),\n                ease: 'linear',\n                snap: {\n                    Frame: 1,\n                },\n                onUpdateParams: [this.videoObj],\n            }));\n        } else {\n            this._playing = false;\n            this.videoOnStage = false;\n            this.VIDEO_COMPLETE.next();\n        }\n        if (this._endHandler) {\n            this._endHandler();\n        }\n    }\n\n    protected getSpineDelta(): number {\n        const ticker = Core.stage.ticker;\n        const { delta, nextUpdateTime } = computeSpineDelta(this._lastUpdateTime, ticker.deltaMS, ticker.speed);\n        this._lastUpdateTime = nextUpdateTime;\n        return delta;\n    }\n\n    protected updateFrame(obj): void {\n        if (!this.spineAnim) {\n            return;\n        }\n        this.spineAnim.update(this.getSpineDelta());\n        const time = this.spineAnim.state.tracks[0]?.trackTime || 0;\n\n        // const numTexture = this._config.delayFrames === 0 ? 0 : obj.Frame % (this._config.delayFrames * 3);\n        const numTexture = this._config.delayFrames\n            ? obj.Frame % (this._config.delayFrames * this.config.delaySteps)\n            : 0;\n\n        this.renderTexture.forEach((texture) => {\n            this.spineAnim.pivot.set(\n                -(texture.config.width + this._config.additionalDimensions.width) / 2,\n                -(texture.config.height + this._config.additionalDimensions.height) / 2,\n            );\n            if (this._config?.fixedFps) {\n                if (\n                    // @ts-ignore\n                    this.animationName + texture.anim !== this.spineAnim.state.tracks?.[0]?.animation?.name ||\n                    this._config.loop !== this.spineAnim.state.tracks?.[0]?.loop\n                ) {\n                    this.spineAnim.state.setAnimation(0, ((window as any).__SLN=(this.animationName + texture.anim), ((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"spine:packages/core/src/egt/core/SpineVideoPlayer.ts:433:21\",(window as any).__SLN]), (window as any).__SLN), this._config.loop);\n                    this.spineAnim.update(1 / this._config.fps);\n                }\n            } else if (this._config?.respectFps) {\n                this.spineAnim.state.setAnimation(0, ((window as any).__SLN=(this.animationName + texture.anim), ((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"spine:packages/core/src/egt/core/SpineVideoPlayer.ts:437:17\",(window as any).__SLN]), (window as any).__SLN), this._config.loop);\n                this.spineAnim.update(obj.Frame / this._config.fps);\n            } else {\n                this.spineAnim.state.setAnimation(0, ((window as any).__SLN=(this.animationName + texture.anim), ((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"spine:packages/core/src/egt/core/SpineVideoPlayer.ts:440:17\",(window as any).__SLN]), (window as any).__SLN), this._config.loop);\n                this.spineAnim.update(time);\n            }\n            // this.spineAnim.state.setAnimation(0, this.animationName + texture.anim, true);\n            // if (this._config?.respectFps) {\n            //     this.spineAnim.update(obj.Frame / this._config.fps);\n            // } else {\n            //     this.spineAnim.update(time);\n            // }\n\n            // Copy the contents of the original texture into the cloned textures array\n            const clonedRenderTexture = RenderTexture.create({\n                width: texture.config.width + this._config.additionalDimensions.width,\n                height: texture.config.height + this._config.additionalDimensions.height,\n            });\n\n            // texture.textures[numTexture]?.texture?.destroy();\n            //  texture.textures[numTexture]?.baseTexture?.destroy();\n            texture.textures[numTexture]?.destroy(true);\n            Core.stage.renderer.render(this.spineAnim, { renderTexture: clonedRenderTexture });\n            texture.textures[numTexture] = clonedRenderTexture;\n        });\n\n        for (const instance of this._instances) {\n            const delay = instance.config.delayFrames * instance.config.row;\n            let stepFrame = numTexture - delay;\n            if (stepFrame < 0) {\n                stepFrame += this.config.delaySteps * instance.config.delayFrames;\n            }\n            // if (this.renderTexture[Number(instance.name)].textures[numTexture].baseTexture) {\n            instance.texture = this.renderTexture[Number(instance.name)].textures[stepFrame];\n            //}\n\n            if (obj.Frame === delay + 1) {\n                this.VIDEO_INSTANCE_STARTED.next(instance.config);\n            }\n\n            if (instance.alpha === 1 && obj.Frame > 0 && !this.videoOnStage && this._config.dispatchFirstFrame) {\n                this.FIRST_FRAME.next(this);\n                this.videoOnStage = true;\n            }\n        }\n        if (obj.Frame !== this._lastFrame) {\n            if (this._config.getEachFrame) {\n                this.VIDEO_FRAME.next();\n            }\n\n            if (this._config.dispatchWhenShown) {\n                // this._config.dispatchWhenShown = false;\n                this.VIDEO_SHOWN.next(this);\n            }\n            this._lastFrame = obj.Frame;\n        }\n    }\n}\n","import { PIXIHooks } from '@egt/dev-tools';\nimport { gsap } from 'gsap';\nimport { Application, Container, Graphics, Rectangle, Renderer, Ticker } from 'pixi.js';\nimport { injectable, singleton } from 'tsyringe';\nimport Core, { IStageOptions } from './Core';\nimport Orientation from './data/Orientation';\nimport { IAlignStrategy } from './interfaces/IAlignStrategy';\nimport { IMediaInfoData } from './interfaces/IMediaInfoData';\nimport { IPerfData } from './interfaces/IPerfData';\nimport { IScaleStrategy } from './interfaces/IScaleStrategy';\nimport { IStage } from './interfaces/IStage';\nimport Align from './utils/align/Align';\nimport AlignStrategy from './utils/align/AlignStrategy';\nimport Scale from './utils/scale/Scale';\nimport ScaleStrategy from './utils/scale/ScaleStrategy';\n\n@injectable()\n@singleton()\nexport default class Stage implements IStage {\n    get initialHeight(): number {\n        return this._height;\n    }\n\n    get initialWidth(): number {\n        return this._width;\n    }\n\n    get stage(): Container {\n        return this._app?.stage;\n    }\n\n    get ticker(): Ticker {\n        return this._app?.ticker;\n    }\n\n    get renderer(): Renderer {\n        return this._app.renderer as Renderer;\n    }\n\n    get screen(): Rectangle {\n        return this._app.screen;\n    }\n\n    get view(): HTMLCanvasElement {\n        return this._app.view;\n    }\n\n    get gameContainer(): Container {\n        return this._gameContainer;\n    }\n\n    get fps(): number {\n        return this._fps;\n    }\n\n    set fps(value: number) {\n        this._fps = value;\n        const delayInSeconds = 1000 / (this._fps || 240) / 1000;\n        if (this.tickerTween) {\n            this.tickerTween.kill();\n            // @ts-ignore\n            this.tickerTween = null;\n        }\n        this.tickerTween = gsap.set(this.tick.bind(this), {\n            delay: delayInSeconds,\n            onRepeat: this.tick.bind(this),\n            repeat: -1,\n            repeatDelay: delayInSeconds,\n        });\n    }\n    public stageInititalized: boolean = false;\n\n    private _width: number;\n    private _height: number;\n    private _landscape: boolean;\n    private _resizing: boolean = false;\n\n    private _app: Application;\n    private stageOptions: any;\n\n    private _scaleStrategy: IScaleStrategy;\n    private _alignStrategy: IAlignStrategy;\n\n    private _gameContainer: any;\n    private screenBorder: Graphics;\n\n    private hook: PIXIHooks;\n    private _fps: number;\n    private _updatePerfomanceInfo: boolean;\n    private timeWhenAppStarted: number;\n    private tickerTween: gsap.core.Tween;\n\n    private statsObject: any = {\n        i: 0,\n        time1: 0,\n        fps: 0,\n        total: 0,\n        frameTime: 100,\n        thisFrameTime: 0,\n        lastLoop: performance.now() - 100,\n        sampleRate: 8,\n        buffer: [],\n        smootging: 10,\n    };\n\n    public initStage(options: IStageOptions): void {\n        this.stageOptions = options;\n        // @ts-ignore\n        // this.stageOptions.sharedTicker = true;\n        this._app = new Application(this.stageOptions);\n        globalThis.__PIXI_APP__ = this.app;\n        this._app.ticker.autoStart = false;\n\n        this._landscape = this.stageOptions.changeOrientation\n            ? this._app.view.clientWidth >= this._app.view.clientHeight\n            : true;\n        if (this._landscape) {\n            this._width = this.stageOptions.width;\n            this._height = this.stageOptions.height;\n        } else {\n            this._width = this.stageOptions.height;\n            this._height = this.stageOptions.width;\n        }\n\n        this._alignStrategy = new AlignStrategy(this.stageOptions.align).getStrategy();\n        this._scaleStrategy = new ScaleStrategy(this.stageOptions.scale).getStrategy();\n\n        this.stage.name = 'Stage';\n        this.stage.interactive = true;\n        this.createGameContainer();\n        this.renderer.textureGC.maxIdle = 30;\n\n        if (Core.configuration.devTools && !Core.configuration.multiplayer) {\n            this.hook = new PIXIHooks(this._app);\n            this._updatePerfomanceInfo = true;\n        } else {\n            this._updatePerfomanceInfo = false;\n        }\n\n        this.ticker.stop();\n        this.timeWhenAppStarted = Date.now();\n        this.ticker.add(this.resize.bind(this));\n\n        Core.BATTERY_SAVE_MODE.subscribe(this.onBatterySaveMode.bind(this));\n        this.stageInititalized = true;\n    }\n\n    public clear(): void {\n        if (!this.stageInititalized) {\n            return;\n        }\n        this.renderer.textureGC.run();\n        this._gameContainer.removeAllListeners();\n        this.stage.removeChild(this._gameContainer);\n        // this.renderer.textureGC.unload(this._gameContainer);\n        this._gameContainer.destroy({ children: true, texture: true, baseTexture: true });\n        // @ts-ignore\n        this._gameContainer = null;\n        this.renderer?.textureGC.run();\n        // this.createGameContainer();\n        gsap.globalTimeline.getChildren().forEach((child) => {\n            if (child !== this.tickerTween) {\n                child.kill();\n                // @ts-ignore;\n                child = null;\n            }\n        });\n        this.stageInititalized = false;\n    }\n\n    /**\n     * Returns media info from the application.\n     * @returns {MediaInfoData} Media info\n     */\n    public getMediaInfo(): IMediaInfoData {\n        return {\n            display: {\n                screen: {\n                    width: this.screen.width,\n                    height: this.screen.height,\n                },\n                view: {\n                    width: this.view.clientWidth,\n                    height: this.view.clientHeight,\n                },\n                stage: {\n                    x: this.stage.x,\n                    y: this.stage.y,\n                    width: this.initialWidth,\n                    height: this.initialHeight,\n                    initialWidth: this.stageOptions.width,\n                    initialHeight: this.stageOptions.height,\n                    currentWidth: Math.ceil(this.initialWidth * this.stage.scale.x),\n                    currentHeight: Math.ceil(this.initialHeight * this.stage.scale.y),\n                    scaleX: this.stage.scale.x.toFixed(2),\n                    scaleY: this.stage.scale.y.toFixed(2),\n                    scaling: this.stageOptions.scale ? this.stageOptions.scale.valueOf() : Scale.NONE,\n                    alignment: this.stageOptions.align ? this.stageOptions.align.valueOf() : Align.TOP_LEFT,\n                    orientation: this._landscape ? 'landscape' : 'portrait',\n                },\n            },\n        };\n    }\n    /**\n     * Returns media info from the application.\n     * @returns {MediaInfoData} Media info\n     */\n    public getPerfomanceInfo(fps: number): IPerfData {\n        return {\n            fps,\n            drawCalls: this.hook.deltaDrawCalls,\n            peakDrawCalls: this.hook.maxDeltaDrawCalls,\n            texturesCount: this.hook.texturesCount,\n            peakTexturesCount: this.hook.maxTextureCount,\n            spineAnimationsCount: Core.spineAnimations.getActiveAnimationsCount(),\n        };\n    }\n\n    public set updatePerfomanceInfo(value: boolean) {\n        this._updatePerfomanceInfo = value;\n        if (!value) {\n            this.hook.release();\n        }\n    }\n    public get updatePerfomanceInfo(): boolean {\n        return this._updatePerfomanceInfo;\n    }\n\n    public setDefaultCursor(): void {\n        this._app.renderer.plugins.interaction.cursorStyles.default = 'auto';\n        this._app.renderer.plugins.interaction.defaultCursorStyle = 'auto';\n        this._app.renderer.plugins.interaction.setCursorMode('auto');\n    }\n\n    public get app(): Application {\n        return this._app;\n    }\n\n    public get shouldResize(): boolean {\n        const multiplier = this.renderer?.options.resolution || 1;\n        const width = Math.round(this.view.clientWidth * multiplier);\n        const height = Math.round(this.view.clientHeight * multiplier);\n\n        return this.view.width !== width || this.view.height !== height;\n    }\n\n    private onBatterySaveMode(): void {\n        if (Core.BATTERY_SAVE_MODE.value) {\n            this.fps = 30;\n        } else {\n            this.fps = 100;\n        }\n    }\n\n    private tick(): void {\n        this.ticker?.update(Date.now() - this.timeWhenAppStarted);\n        if (this._updatePerfomanceInfo) {\n            this.statsObject = this.updatePerfStats(this.statsObject);\n        }\n    }\n\n    private updatePerfStats({\n        time1,\n        thisFrameTime,\n        lastLoop,\n        frameTime,\n        smootging,\n        buffer,\n        sampleRate,\n        total,\n        i,\n        fps,\n    }): any {\n        time1 = performance.now();\n        thisFrameTime = time1 - lastLoop;\n        frameTime += (thisFrameTime - frameTime) / smootging;\n        buffer.push(1000 / frameTime);\n        if (buffer.length === sampleRate) {\n            total = 0;\n            for (i = 0; i < sampleRate; i++) {\n                total += buffer[i];\n            }\n            fps = Math.round(total / sampleRate);\n            buffer.length = 0;\n        }\n        Core.PERFORMANCE_METRICS.next(this.getPerfomanceInfo(fps));\n        lastLoop = time1;\n        return { time1, thisFrameTime, lastLoop, frameTime, total, i, fps, buffer, sampleRate, smootging };\n    }\n\n    private createGameContainer(): void {\n        this._gameContainer = new Container();\n        this._gameContainer.name = 'Game Container';\n        this.stage.addChildAt(this._gameContainer, 0);\n        // container.registerInstance('GameContainer', this._gameContainer);\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    private drawScreenBorder(width = 4): void {\n        if (Core.configuration.devTools) {\n            // const halfWidth = width / 2;\n            //\n            // this.screenBorder = new Graphics();\n            // this.screenBorder.name = 'Debug Border';\n            // this.screenBorder.lineStyle(width, 0xadff2f, 1);\n            // this.screenBorder.drawRect(halfWidth, halfWidth, this.initialWidth - width, this.initialHeight - width);\n            //\n            // this._app.stage.addChild(this.screenBorder);\n        }\n    }\n\n    /**\n     * Determinate if orientation is changed\n     * @private\n     */\n    private orientate(): boolean {\n        let changed = false;\n\n        if (this.stageOptions.changeOrientation) {\n            if (this._landscape && this.view.clientHeight > this.view.clientWidth) {\n                // change to portrait mode\n                changed = true;\n                this._landscape = false;\n                this.swapSize();\n            } else if (!this._landscape && this.view.clientWidth > this.view.clientHeight) {\n                changed = true;\n                this._landscape = true;\n                this.swapSize();\n            }\n            this._app.stage.removeChild(this.screenBorder);\n            // this.drawScreenBorder(2);\n        }\n        return changed;\n    }\n\n    /**\n     *\n     * @private\n     */\n    private swapSize(): void {\n        const tempW = this._width;\n        this._width = this._height;\n        this._height = tempW;\n    }\n\n    /**\n     *\n     * @private\n     */\n    private resize(): void {\n        if (!this._resizing && this.shouldResize) {\n            this._resizing = true;\n\n            // dispatch resize start event\n            Core.STAGE_RESIZE_START.next();\n            // resize\n            this.renderer.resize(this.view.clientWidth, this.view.clientHeight);\n\n            // check orientation\n            const orientationChanged = this.orientate();\n\n            // scale\n            this.scale();\n\n            // align\n            this.align();\n\n            // update media info\n            Core.MEDIA_INFO_UPDATED.next(this.getMediaInfo());\n\n            this._resizing = false;\n\n            // dispatch resize end event\n            const event: any = {\n                stage: {\n                    position: {\n                        x: this.stage.position.x,\n                        y: this.stage.position.y,\n                    },\n                    scale: {\n                        x: this.stage.scale.x,\n                        y: this.stage.scale.y,\n                    },\n                    size: {\n                        width: this.initialWidth * this.stage.scale.x,\n                        height: this.initialHeight * this.stage.scale.y,\n                    },\n                    orientation: {\n                        orientation: this._landscape ? 'landscape' : 'portrait',\n                        landscape: this._landscape,\n                        changed: orientationChanged,\n                    },\n                },\n                view: {\n                    width: this.view.width,\n                    height: this.view.height,\n                },\n            };\n\n            if (orientationChanged) {\n                Core.ORIENTATION.next(\n                    new Orientation({\n                        width: this.initialWidth,\n                        height: this.initialHeight,\n                        orientation: this._landscape ? 'Landscape' : 'Portrait',\n                    }),\n                );\n            }\n\n            Core.STAGE_RESIZE_END.next(event);\n        }\n    }\n\n    /**\n     *\n     * @private\n     */\n    private scale(): void {\n        const { scaleX, scaleY } = this._scaleStrategy.scale(\n            this.initialWidth,\n            this.initialHeight,\n            this.view.clientWidth,\n            this.view.clientHeight,\n        );\n        this.stage.scale.set(scaleX, scaleY);\n    }\n\n    /**\n     *\n     * @private\n     */\n    private align(): void {\n        let { x, y } = this._alignStrategy.align(\n            this.initialWidth * this.stage.scale.x,\n            this.initialHeight * this.stage.scale.y,\n            this.view.clientWidth,\n            this.view.clientHeight,\n        );\n        if (Core.environment.isIosBrowser && y > 2) {\n            y = Math.round(y - 0.3 * y);\n        }\n        this.stage.position.set(x, y);\n    }\n}\n","import { injectable, singleton } from 'tsyringe';\nimport { ISoundManager } from './interfaces/ISoundManager'; //! lemmy check the intercface implementations\nimport { BehaviorSubject } from 'rxjs';\nimport * as Tone from 'tone';\nimport { IToneSoundAsset } from './interfaces/IToneSoundAsset';\nimport Core, { Log, Timers } from './Core';\nimport { SlotComponents } from '@egt/slot';\n\n@injectable()\n@singleton()\nexport default class ToneSoundManager implements ISoundManager {\n    //! lemmy check the intercface implementations\n    // export default class ToneSoundManager {\n    public readonly ON_SOUND_MUTED: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly ON_BACKGROUND_SOUNDS_MUTED: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    private activePlayers: { [id: string]: Tone.Player } = {};\n    private playerStartTimes: { [id: string]: number } = {};\n    private playerLoopDurations: { [id: string]: number } = {};\n\n    private sounds: IToneSoundAsset[] = [];\n    private _lastPlayedBackgroundSound: string;\n    private _replacedSounds: Map<string, IToneSoundAsset> = new Map<string, IToneSoundAsset>();\n    private _enabled: boolean = true;\n    private _volume: number = 1;\n    // holds internal ids of all played sounds\n    private _playing: Map<string, number> = new Map<string, number>();\n    // holds volumes of all played sounds\n    private _volumes: Map<string, number> = new Map<string, number>();\n    private _debug: boolean = false;\n    private fadingTimer: Timers[] = [];\n    private _changeSoundVolume: Map<string, number> = new Map<string, number>();\n\n    get enabled(): boolean {\n        return this._enabled;\n    }\n\n    set enabled(value: boolean) {\n        this._enabled = value;\n    }\n\n    get volume(): number {\n        return this._volume;\n    }\n\n    set volume(value: number) {\n        if (value < 0 || value > 1) {\n            throw new Error('Invalid volume value for sound!');\n        }\n        this._volume = value;\n    }\n\n    get debug(): boolean {\n        return this._debug;\n    }\n\n    set debug(value: boolean) {\n        this._debug = value;\n    }\n\n    get changeSoundVolume(): Map<string, number> {\n        return this._changeSoundVolume;\n    }\n    private get config(): any {\n        // TODO think about config for all game types\n        if (Core.gameDependencyContainer.isRegistered('ISlotConfiguration')) {\n            return Core.gameDependencyContainer.resolve('ISlotConfiguration');\n        } else if (Core.gameDependencyContainer.isRegistered('IScratchConfiguration')) {\n            return Core.gameDependencyContainer.resolve('IScratchConfiguration');\n        } else {\n            return undefined;\n        }\n    }\n    constructor() {\n        document.addEventListener(\n            'visibilitychange',\n            () => {\n                if (!this.ON_SOUND_MUTED.value) {\n                    this.safeSetDestinationMute(document.hidden);\n                    // Tone.start();\n                }\n            },\n            false,\n        );\n        const startAudioContext = async () => {\n            try {\n                await Tone.start();\n            } catch (err) {\n                // On iOS WKWebView the AudioContext can be in a closed/suspended state\n                // when started outside of a user gesture (e.g. after backgrounding).\n                // Swallow the InvalidStateError; subsequent user interactions will retry.\n                Log.warn('Tone.start() failed:', err);\n                return;\n            }\n\n            document.removeEventListener('click', startAudioContext);\n            document.removeEventListener('touchstart', startAudioContext);\n        };\n\n        document.addEventListener('click', startAudioContext);\n        document.addEventListener('touchstart', startAudioContext);\n\n        this.ON_SOUND_MUTED.subscribe(this.onSoundMuted.bind(this));\n        this.ON_SOUND_MUTED.subscribe(this.onToneUnmute.bind(this));\n\n        this.ON_BACKGROUND_SOUNDS_MUTED.subscribe(this.onBackgroundSoundMuted.bind(this));\n    }\n\n    /**\n     * Returns true if the underlying Web Audio context is usable (not closed).\n     * iOS WebViews aggressively close the AudioContext when the page is\n     * backgrounded; calling any Tone API in that state throws InvalidStateError.\n     */\n    private isAudioContextUsable(): boolean {\n        try {\n            const ctx = Tone.getContext();\n            const raw = (ctx as any)?.rawContext;\n            const state = raw?.state ?? (ctx as any)?.state;\n            return state !== 'closed';\n        } catch {\n            return false;\n        }\n    }\n\n    /**\n     * Safely toggle the global Tone destination mute flag. Returns silently if\n     * the audio context is in an invalid state instead of throwing.\n     */\n    private safeSetDestinationMute(value: boolean): void {\n        if (!this.isAudioContextUsable()) {\n            return;\n        }\n        try {\n            Tone.getDestination().mute = value;\n        } catch (err) {\n            Log.warn('Tone.getDestination().mute failed:', err);\n        }\n    }\n    /**\n     * Converts a linear volume value (0 to 1) to a decibel volume value (-50 to 0).\n     * -50 is currently the point where you stop hearing sounds\n     * @param {number} linear - Linear volume value (0 to 1).\n     * @returns {number} - Decibel volume value (-50 to 0).\n     */\n    public linearToDecibels(linear: number): number {\n        if (linear <= 0) {\n            return -50; // Minimum dB value\n        }\n        return 20 * Math.log10(linear);\n    }\n    /**\n     * Converts a decibel volume value (-50 to 0) to a linear volume value (0 to 1).\n     * @param {number} decibels - Decibel volume value (-50 to 0).\n     * @returns {number} - Linear volume value (0 to 1).\n     */\n    public decibelsToLinear(decibels: number): number {\n        return Math.pow(10, decibels / 20);\n    }\n\n    public isPlaying(id: string): boolean { if ((window as any).__SL_OVR && (window as any).__SL_OVR[String(id)] && (window as any).__SL_OVR[String(id)].active) { return true; }\n        const player = this.activePlayers[id];\n        return !!player && player.state === 'started';\n    }\n    public play(id: string, fade: boolean = false, fadeTime: number = 1000, seek: number = 0): void { if ((this as any).enabled && (window as any).__SL_SOUND && (window as any).__SL_SOUND(\"sound:packages/core/src/egt/core/ToneSoundManager.ts:163:5\", String(id), this, !!(fade), Number(fadeTime)||0)) { return; }\n        try {\n            // Tone.start returns a Promise; we don't await it here but must catch\n            // its rejection (e.g. iOS WebView InvalidStateError) to avoid an\n            // unhandled rejection bubbling up to Sentry.\n            const startResult: unknown = Tone.start();\n            if (startResult && typeof (startResult as Promise<void>).catch === 'function') {\n                (startResult as Promise<void>).catch((err) => Log.warn('Tone.start() rejected in play():', err));\n            }\n        } catch (err) {\n            Log.warn('Tone.start() threw in play():', err);\n        }\n        if (!this.enabled) {\n            return;\n        }\n\n        const asset = this.getSound(id);\n        if (!asset) {\n            return;\n        }\n\n        const isBackgroundSoud = this.config?.backgroundSoundsGroup.includes(id);\n        if (isBackgroundSoud) {\n            this._lastPlayedBackgroundSound = id;\n        }\n\n        // let volume = this.linearToDecibels(this.volume);\n        let volume = Tone.gainToDb(this.volume);\n        if ((this.ON_BACKGROUND_SOUNDS_MUTED.value || this.ON_SOUND_MUTED.value) && isBackgroundSoud) {\n            volume = Tone.gainToDb(0);\n        }\n\n        if (this.debug) {\n            Log.debug(`[SOUND] play: ${id}${fade ? `, dur: ${fadeTime}` : ''}, vol: ${this.decibelsToLinear(volume)} `);\n            const soundDuration = fade ? fadeTime : '';\n            const soundVolume = fade ? this.decibelsToLinear(volume) : '';\n\n            const a = `[SOUND] play${fade ? ' and fade' : ''}: ` + id + '  ' + soundDuration + '  ' + soundVolume;\n            Log.customConsole.next({\n                content: '',\n                contentTitle: a,\n            });\n        }\n        if (this.fadingTimer[id]) {\n            Timers.clearTimeout(this.fadingTimer[id]);\n            this.fadingTimer[id] = null;\n        }\n        const sprite = asset.sprite[id];\n        if (!sprite) {\n            return;\n        }\n\n        const spriteStart = sprite[0] / 1000;\n        const spriteDuration = sprite[1] / 1000;\n        const spriteLoop = sprite[2] || false;\n\n        // Check if the sound is already playing\n        if (this.activePlayers[id] && isBackgroundSoud) {\n            const player = this.activePlayers[id];\n\n            // Handle seeking\n            if (seek) {\n                const startTime = Tone.now();\n                if (spriteLoop) {\n                    player.start();\n                    player.seek(spriteStart + seek);\n                } else {\n                    player.start(startTime, spriteStart + seek, spriteDuration - seek);\n                }\n            }\n            if (player.state === 'stopped') {\n                player.start(0, spriteStart, spriteDuration);\n                this.playerStartTimes[id] = Tone.now() - seek;\n                this.playerLoopDurations[id] = spriteDuration; // Store loop duration\n            }\n            if (fade && this.decibelsToLinear(player.volume.value) < 1) {\n                this.fadeInSound(id, fadeTime, 1);\n            }\n            return;\n        }\n\n        // Create a new player instance for the sound\n        const player = new Tone.Player({\n            url: asset.buffer,\n            // volume: this.linearToDecibels(this.volume),\n            volume: Tone.gainToDb(this.volume),\n            loop: spriteLoop,\n            loopStart: spriteStart, // Set loop start point\n            loopEnd: spriteStart + spriteDuration, // Set loop end point\n        }).toDestination();\n        // Handle seeking\n        if (seek) {\n            // debugger\n            const startTime = Tone.now();\n            if (spriteLoop) {\n                player.start();\n                player.seek(spriteStart + seek);\n            } else {\n                player.start(startTime, spriteStart + seek, spriteDuration - seek);\n            }\n        } else {\n            if (spriteLoop) {\n                player.start();\n            } else {\n                player.start(0, spriteStart, spriteDuration);\n            }\n        }\n\n        // Store the player instance, start time, and loop duration\n        this.activePlayers[id] = player;\n        this.playerStartTimes[id] = Tone.now() - seek;\n        this.playerLoopDurations[id] = spriteDuration; // Store loop duration\n        this._volumes.set(id, volume);\n        if (fade) {\n            // player.volume.value = this.linearToDecibels(0);\n            player.volume.value = Tone.gainToDb(0);\n            this.fadeInSound(id, fadeTime, 1);\n        }\n        if (this.changeSoundVolume.has(id)) {\n            volume = this.changeSoundVolume.get(id) as number;\n            if ((this.ON_BACKGROUND_SOUNDS_MUTED.value || this.ON_SOUND_MUTED.value) && isBackgroundSoud) {\n                volume = 0;\n            }\n            this.setVolume(id, volume);\n        }\n    }\n    public stop(spriteId: string): void { if ((window as any).__SL_SNDCTL && (((this as any)._playing && (this as any)._playing.has(spriteId)) || ((window as any).__SL_OVR && (window as any).__SL_OVR[String(spriteId)]))) { (window as any).__SL_SNDCTL(\"sound:packages/core/src/egt/core/ToneSoundManager.ts:289:5\", String(spriteId), \"stop\", Number(0)||0, Number(0)||0); }\n        // Find the asset that contains the sprite\n\n        const asset = this.sounds.find((sound) => sound.sprite && sound.sprite[spriteId]);\n\n        if (!asset || !asset.sprite) {\n            // console.error(`Sound asset containing sprite ${spriteId} not found or no sprite available in stop`);\n            return;\n        }\n\n        // Find the player for the given spriteId\n        const player = this.activePlayers[spriteId];\n        if (player) {\n            player.stop();\n            player.disconnect();\n            player.dispose();\n            delete this.activePlayers[spriteId];\n            this._volumes.delete(spriteId);\n            delete this.playerLoopDurations[spriteId];\n            delete this.playerStartTimes[spriteId];\n        }\n    }\n    public stopAll(exceptions?: string[]): void { if ((window as any).__SL_SNDCTL) { (window as any).__SL_SNDCTL(\"\", ((exceptions)||[]).join(\",\"), \"stopall\", 0, 0); }\n        for (const id in this.activePlayers) {\n            if (!exceptions || !exceptions.includes(id)) {\n                this.activePlayers[id].stop();\n                this.activePlayers[id].disconnect();\n                this.activePlayers[id].dispose();\n                delete this.activePlayers[id];\n                this._volumes.delete(id);\n                delete this.playerLoopDurations[id];\n                delete this.playerStartTimes[id];\n            }\n        }\n\n        for (const sound of this.sounds) {\n            if (sound.players) {\n                for (const segmentName in sound.players) {\n                    if (!exceptions || !exceptions.includes(segmentName)) {\n                        sound.players[segmentName].stop();\n                        delete sound.players[segmentName];\n                    }\n                }\n            }\n        }\n    }\n    public setVolume(id: string, volume: number, setIfMuted: boolean = false): void { if ((window as any).__SL_SNDCTL && (window as any).__SL_OVR && (window as any).__SL_OVR[String(id)]) { (window as any).__SL_SNDCTL(\"\", String(id), \"volume\", (setIfMuted) ? 1 : 0, Number(volume)||0); }\n        const player = this.activePlayers[id];\n\n        if (!player) {\n            // console.error(`Sound player with ID ${id} not found`);\n            return;\n        }\n\n        if (this.config?.backgroundSoundsGroup.includes(id)) {\n            this._lastPlayedBackgroundSound = id;\n        }\n\n        if (\n            ((this.ON_BACKGROUND_SOUNDS_MUTED.value || this.ON_SOUND_MUTED.value) &&\n                this.config?.backgroundSoundsGroup.includes(id) &&\n                !setIfMuted) ||\n            (this.ON_SOUND_MUTED.value && !this.config?.backgroundSoundsGroup.includes(id))\n        ) {\n            return;\n        }\n\n        this._volumes.set(id, volume);\n\n        if (this.changeSoundVolume.has(id)) {\n            volume = this.changeSoundVolume.get(id) as number;\n        }\n\n        // const volumeInDb = this.linearToDecibels(volume);\n        const volumeInDb = Tone.gainToDb(volume);\n        player.volume.value = volumeInDb;\n\n        if (this.debug) {\n            Log.debug(`[SOUND] volume: ${id}, volume: ${volume}`);\n            Log.customConsole.next({\n                content: '',\n                contentTitle: `[SOUND] volume: Id: ${id} Volume: ${volume}`,\n            });\n        }\n    }\n    public getSoundCurrentVolume(id: string): number | undefined {\n        // Check if the sound is currently playing and if its volume is stored\n        if (this.activePlayers[id] && this._volumes.has(id) && !this.config?.backgroundSoundsGroup.includes(id)) {\n            return this.decibelsToLinear(this.activePlayers[id].volume.value);\n        }\n\n        // Find the sound asset containing the sprite or matching the ID\n        const asset = this.getSound(id);\n        if (!asset || !asset.sprite || !asset.sprite[id]) {\n            return undefined;\n        }\n\n        // Get the player for the sprite\n        const player = this.activePlayers[id];\n        if (player) {\n            return this.decibelsToLinear(player.volume.value);\n        }\n\n        // Fallback to the stored volume if available\n        return this._volumes.get(id);\n    }\n    public getAssetVolume(id: string): number | undefined {\n        return this._volumes.get(id);\n    }\n    addSound(sound: IToneSoundAsset): void {\n        this.sounds.push(sound);\n    }\n    public fadeInSound(id: string, duration: number, targetVolume: number = 1, isExponential?: boolean): void { if ((targetVolume) > 0 && (this as any).changeSoundVolume && (this as any).changeSoundVolume.has(String(id))) { targetVolume = (this as any).changeSoundVolume.get(String(id)); } if ((window as any).__SL_SNDCTL && (((this as any)._playing && (this as any)._playing.has(id)) || ((window as any).__SL_OVR && (window as any).__SL_OVR[String(id)]))) { (window as any).__SL_SNDCTL(\"sound:packages/core/src/egt/core/ToneSoundManager.ts:401:5\", String(id), \"fadein\", Number(duration)||0, Number(targetVolume)||0); }\n        if (this.config?.backgroundSoundsGroup.includes(id)) {\n            this._lastPlayedBackgroundSound = id;\n        }\n\n        if (\n            (this.ON_BACKGROUND_SOUNDS_MUTED.value || this.ON_SOUND_MUTED.value) &&\n            this.config?.backgroundSoundsGroup.includes(id)\n        ) {\n            return;\n        }\n\n        const player = this.activePlayers[id];\n        if (!player) {\n            // console.error(`Sound player with ID ${id} not found`);\n            return;\n        }\n\n        if (this.debug) {\n            Log.debug(`[SOUND] fadeIn: ${id}, dur: ${duration}, vol: ${targetVolume}`);\n            Log.customConsole.next({\n                content: '',\n                contentTitle: `[SOUND] fadeIn: Id: ${id} Duration: ${duration} Volume: ${targetVolume}`,\n            });\n        }\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        let soundVolume = this._volumes.get(id) === undefined ? targetVolume : this._volumes.get(id);\n        if (this.changeSoundVolume.has(id)) {\n            soundVolume = this.changeSoundVolume.get(id) as number;\n        }\n        this._volumes.set(id, targetVolume);\n        // targetVolume = this.linearToDecibels(targetVolume);\n        targetVolume = Tone.gainToDb(targetVolume);\n        //player.volume.value = this.linearToDecibels(0); // Start with volume off\n        if (isExponential) {\n            player.volume.exponentialRampTo(targetVolume, duration / 1000); // Fade in over the specified duration\n        } else {\n            player.volume.linearRampTo(targetVolume, duration / 1000); // Fade in over the specified duration\n        }\n    }\n\n    public fadeOutSound(\n        id: string,\n        duration: number,\n        targetVolume: number = 0,\n        setIfMuted: boolean = false,\n        isExponential?: boolean,\n    ): void { if ((targetVolume) > 0 && (this as any).changeSoundVolume && (this as any).changeSoundVolume.has(String(id))) { targetVolume = (this as any).changeSoundVolume.get(String(id)); } if ((window as any).__SL_SNDCTL && (((this as any)._playing && (this as any)._playing.has(id)) || ((window as any).__SL_OVR && (window as any).__SL_OVR[String(id)]))) { (window as any).__SL_SNDCTL(\"sound:packages/core/src/egt/core/ToneSoundManager.ts:442:5\", String(id), \"fadeout\", Number(duration)||0, Number(targetVolume)||0); }\n        if (\n            (this.ON_BACKGROUND_SOUNDS_MUTED.value || this.ON_SOUND_MUTED.value) &&\n            this.config?.backgroundSoundsGroup.includes(id) &&\n            !setIfMuted\n        ) {\n            return;\n        }\n\n        const player = this.activePlayers[id];\n        if (!player) {\n            // console.error(`Sound player with ID ${id} not found`);\n            return;\n        }\n\n        if (this.debug) {\n            Log.debug(`[SOUND] fadeOut: ${id}, dur: ${duration}, vol: ${targetVolume}`);\n            Log.customConsole.next({\n                content: '',\n                contentTitle: `[SOUND] fadeOut: Id: ${id} Duration: ${duration} Volume: ${targetVolume}`,\n            });\n        }\n\n        // Set the target volume\n        this._volumes.set(id, targetVolume);\n        // targetVolume = this.linearToDecibels(targetVolume);\n        targetVolume = Tone.gainToDb(targetVolume);\n\n        // Ramp to the target volume\n        // player.volume.rampTo(targetVolume, duration / 1000);\n        if (isExponential) {\n            player.volume.exponentialRampTo(targetVolume, duration / 1000); // Fade in over the specified duration\n        } else {\n            player.volume.linearRampTo(targetVolume, duration / 1000); // Fade in over the specified duration\n        }\n    }\n\n    public fadeOutAndStop(id: string, duration: number): void { if ((window as any).__SL_SNDCTL && (((this as any)._playing && (this as any)._playing.has(id)) || ((window as any).__SL_OVR && (window as any).__SL_OVR[String(id)]))) { (window as any).__SL_SNDCTL(\"sound:packages/core/src/egt/core/ToneSoundManager.ts:485:5\", String(id), \"stop\", Number(duration)||0, Number(0)||0); }\n        if (\n            (this.ON_BACKGROUND_SOUNDS_MUTED.value || this.ON_SOUND_MUTED.value) &&\n            this.config?.backgroundSoundsGroup.includes(id)\n        ) {\n            this.stop(id);\n            return;\n        }\n\n        const player = this.activePlayers[id];\n        if (!player) {\n            // console.error(`Sound player with ID ${id} not found`);\n            return;\n        }\n\n        if (this.debug) {\n            Log.debug(`[SOUND] fadeoutStop: ${id}, dur: ${duration}`);\n            Log.customConsole.next({\n                content: '',\n                contentTitle: `[SOUND] fadeoutStop: Id: ${id} Duration: ${duration}`,\n            });\n        }\n        this.fadingTimer[id] = Timers.setTimeout(() => {\n            this.stop(id);\n            Timers.clearTimeout(this.fadingTimer[id]);\n            this.fadingTimer[id] = null;\n        }, duration);\n        // const targetVolume = this.linearToDecibels(0);\n        const targetVolume = Tone.gainToDb(0);\n\n        player.volume.rampTo(targetVolume, duration / 1000); // Fade out over the specified duration\n\n        // Stop the player after the fade out duration\n        setTimeout(() => {\n            player.stop();\n            delete this.activePlayers[id];\n        }, duration);\n    }\n    public getSoundDuration(groupId: string, soundId: string): number {\n        const sound = this.sounds.find((sound) => sound.id === groupId);\n\n        if (!sound || !sound.sprite) {\n            // console.error(`Sound asset with ID ${soundId} not found or has no sprite`);\n            return 0;\n        }\n\n        const sprite = sound.sprite[soundId];\n        if (!sprite) {\n            // console.error(`No sprite found for sound asset with ID ${soundId}`);\n            return 0;\n        }\n\n        return sprite[1];\n    }\n    public reset(): void {\n        // Stop all active players\n        this._replacedSounds.clear();\n        for (const id in this.activePlayers) {\n            this.activePlayers[id].stop();\n        }\n        this.activePlayers = {}; // Clear active players\n\n        // Unload all loaded sound buffers\n        this.sounds.forEach((sound) => {\n            if (sound.players) {\n                for (const segmentName in sound.players) {\n                    sound.players[segmentName].stop();\n                }\n                sound.players = {}; // Clear players for the sound asset\n            }\n            delete sound.buffer; // Remove the buffer reference\n        });\n\n        // Clear sounds array\n        this.sounds = [];\n    }\n    soundAssetLoaded(id: string): boolean {\n        const soundLoaded = this.sounds.some((sound) => sound.id === id);\n        return soundLoaded;\n    }\n    public replaceSound(id: string, newSoundAsset: IToneSoundAsset | undefined): void {\n        // Find the current sound asset containing the sprite or matching the ID\n        const currentAsset = this.getSound(id);\n        if (!currentAsset) {\n            // console.error(`Sound asset with ID ${id} not found`);\n            return;\n        }\n\n        // Check if it's a sprite\n        const isSprite = !!currentAsset.sprite && currentAsset.sprite[id];\n\n        // Find the current player if it exists\n        const player = isSprite ? this.activePlayers[id] : this.activePlayers[currentAsset.id];\n        if (player) {\n            // Stop and dispose of the current player\n            player.stop();\n            player.dispose();\n        }\n\n        if (newSoundAsset) {\n            this._replacedSounds.set(id, newSoundAsset);\n\n            // Create a new player instance for the new sound asset\n            const sprite = newSoundAsset.sprite ? newSoundAsset.sprite[id] : null;\n            const spriteStart = sprite ? sprite[0] / 1000 : 0;\n            const spriteDuration = sprite ? sprite[1] / 1000 : 0;\n            const spriteLoop = sprite ? sprite[2] || false : false;\n\n            const newPlayer = new Tone.Player({\n                url: newSoundAsset.buffer,\n                // volume: this.linearToDecibels(this.volume),\n                volume: Tone.gainToDb(this.volume),\n                loop: spriteLoop,\n                loopStart: spriteStart, // Set loop start point\n                loopEnd: spriteStart + spriteDuration, // Set loop end point\n            }).toDestination();\n\n            if (isSprite) {\n                // Update the sprite in the current asset\n                //currentAsset.sprite[id] = newSoundAsset.sprite ? newSoundAsset.sprite[id] : [0, newSoundAsset.buffer.duration * 1000];\n                // Update the internal data structures\n                this.activePlayers[id] = newPlayer;\n            } else {\n                // Replace the entire sound asset\n                const soundIndex = this.sounds.findIndex((sound) => sound.id === currentAsset.id);\n                if (soundIndex !== -1) {\n                    this.sounds[soundIndex] = newSoundAsset;\n                }\n                this.activePlayers[currentAsset.id] = newPlayer;\n            }\n\n            if (this.debug) {\n                // console.log(`[SOUND] Replaced sound with ID ${id} with new sound asset`);\n            }\n        } else {\n            this._replacedSounds.delete(id);\n            // Remove the sound sprite or the entire sound asset\n            if (isSprite) {\n                delete this.activePlayers[id];\n                if (currentAsset.sprite) {\n                    delete currentAsset.sprite[id];\n                }\n            } else {\n                const soundIndex = this.sounds.findIndex((sound) => sound.id === currentAsset.id);\n                if (soundIndex !== -1) {\n                    this.sounds.splice(soundIndex, 1);\n                }\n                delete this.activePlayers[currentAsset.id];\n            }\n\n            if (this.debug) {\n                // console.log(`[SOUND] Removed sound with ID ${id}`);\n            }\n        }\n    }\n\n    public getAllSounds(): IToneSoundAsset[] {\n        return this.sounds;\n    }\n    public hasSound(id: string): boolean {\n        return !!this.activePlayers[id] || !!this.getSound(id);\n    }\n    public getSound(id: string): IToneSoundAsset | undefined {\n        if (this._replacedSounds.has(id)) {\n            return this._replacedSounds.get(id);\n        } else {\n            return this.sounds.find((sound) => sound.id === id || (sound.sprite && sound.sprite[id]));\n        }\n    }\n    public getSoundSprite(id: string): any {\n        const asset = this.sounds.find((sound) => sound.id === id);\n\n        if (asset && asset.sprite && asset.sprite[id]) {\n            return asset.sprite[id];\n        } else {\n            return undefined;\n        }\n    }\n    public getSoundCurrentTime(id: string): number | undefined {\n        const player = this.activePlayers[id];\n        if (player && player.state === 'started') {\n            const startTime = this.playerStartTimes[id];\n            const currentTime = Tone.now();\n            const elapsedTime = currentTime - startTime;\n            const loopDuration = this.playerLoopDurations[id];\n\n            if (player.loop && loopDuration) {\n                return elapsedTime % loopDuration;\n            }\n            return elapsedTime;\n        }\n\n        return undefined;\n    }\n    public getCurrentlyPlayingBGSound(): string {\n        const bgSounds: string[] = this.config.backgroundSoundsGroup; // Adjust this based on your configuration\n        return bgSounds.find((sound) => this.isPlaying(sound)) || '';\n    }\n    public updateBgSingleLineSoundConfiguration(config: { bgSound; lineSound; soundConfig }): void {\n        if (!this.isBackgroundComponentRegistered()) {\n            return;\n        }\n\n        const componentConfig = Core.gameDependencyContainer.resolve('BackgroundSoundComponentConfiguration');\n\n        const { bgSound, lineSound, soundConfig } = config;\n        // @ts-ignore\n        componentConfig.backgroundSoundConfig[bgSound][lineSound] = soundConfig;\n    }\n\n    /**\n     * This method should be used only for dev purposes\n     */\n    public updateBGSoundConfiguration(config: { bgSound; bgSoundConfig }): void {\n        if (!this.isBackgroundComponentRegistered()) {\n            return;\n        }\n\n        const componentConfig = Core.gameDependencyContainer.resolve('BackgroundSoundComponentConfiguration');\n        const { bgSound, bgSoundConfig } = config;\n        // @ts-ignore\n        const currentBGLinesSounds = componentConfig.backgroundSoundConfig[bgSound];\n\n        // Iterate trough the current configuration and remove values which are absent from the newly passed one\n        for (const lineSound in currentBGLinesSounds) {\n            // if absent from the new config\n            if (!bgSoundConfig[lineSound]) {\n                delete currentBGLinesSounds[lineSound];\n            }\n        }\n\n        // Iterate trough the new configuration and attach the new values\n        for (const lineSound in bgSoundConfig) {\n            currentBGLinesSounds[lineSound] = bgSoundConfig[lineSound];\n        }\n    }\n\n    /**\n     * This method should be used only for dev purposes\n     */\n    public updateBgSoundFadeDuration(config: { backgroundMusicFadeOutDurationNew; backgroundNoPlayFadeInDurationNew }) {\n        if (!this.isBackgroundComponentRegistered()) {\n            return;\n        }\n\n        const componentConfig = Core.gameDependencyContainer.resolve('BackgroundSoundComponentConfiguration');\n        const { backgroundMusicFadeOutDurationNew, backgroundNoPlayFadeInDurationNew } = config;\n\n        // @ts-ignore\n        componentConfig.backgroundMusicFadeOutDuration = backgroundMusicFadeOutDurationNew;\n        // @ts-ignore\n        componentConfig.backgroundNoPlayFadeInDuration = backgroundNoPlayFadeInDurationNew;\n    }\n\n    /**\n     * This method should be used only for dev purposes\n     */\n    public getBGSoundFadeConfiguration(): any {\n        if (!this.isBackgroundComponentRegistered()) {\n            return;\n        }\n\n        const componentConfig = Core.gameDependencyContainer.resolve('BackgroundSoundComponentConfiguration');\n        return {\n            // @ts-ignore\n            backgroundMusicFadeOutDuration: componentConfig.backgroundMusicFadeOutDuration,\n            // @ts-ignore\n            backgroundNoPlayFadeInDuration: componentConfig.backgroundNoPlayFadeInDuration,\n        };\n    }\n\n    /**\n     * This method should be used only for dev purposes\n     */\n    public getBGInactivityTimeConfiguration(): number | null {\n        if (!this.isBackgroundComponentRegistered()) {\n            return null;\n        }\n\n        const componentConfig = Core.gameDependencyContainer.resolve('BackgroundSoundComponentConfiguration');\n        // @ts-ignore\n        return componentConfig.backgroundInactivityTime;\n    }\n\n    /**\n     * This method should be used only for dev purposes\n     */\n    public updateBGInactivityTimeConfiguration(duration: number) {\n        if (!this.isBackgroundComponentRegistered()) {\n            return;\n        }\n\n        const componentConfig = Core.gameDependencyContainer.resolve('BackgroundSoundComponentConfiguration');\n        // @ts-ignore\n        componentConfig.backgroundInactivityTime = duration;\n    }\n    public updateBgAllLinesSoundConfiguration(config: { bgSound; soundConfig }) {\n        if (!this.isBackgroundComponentRegistered()) {\n            return;\n        }\n\n        const componentConfig = Core.gameDependencyContainer.resolve('BackgroundSoundComponentConfiguration');\n        const { bgSound, soundConfig } = config;\n        // @ts-ignore\n        const currentBGLinesSounds = componentConfig.backgroundSoundConfig[bgSound];\n\n        // Iterate trough the current configuration update all lines sounds with the new config\n        for (const lineSound in currentBGLinesSounds) {\n            currentBGLinesSounds[lineSound] = soundConfig;\n        }\n    }\n    /**\n     *\n     * @returns BackgroundSoundComponentConfiguration.backgroundSoundConfig\n     */\n    public getBGSoundConfiguration(): any {\n        if (!this.isBackgroundComponentRegistered()) {\n            return;\n        }\n\n        const componentConfig = Core.gameDependencyContainer.resolve('BackgroundSoundComponentConfiguration');\n        // @ts-ignore\n        return componentConfig.backgroundSoundConfig;\n    }\n    private onSoundMuted(): void {\n        if (!this.config) {\n            this.safeSetDestinationMute(this.ON_SOUND_MUTED.value);\n            return;\n        }\n\n        this.safeSetDestinationMute(this.ON_SOUND_MUTED.value);\n\n        this.onBackgroundSoundMuted();\n    }\n    //research\n    private onBackgroundSoundMuted(): void {\n        if (!this.config) {\n            return;\n        }\n\n        if (this.ON_BACKGROUND_SOUNDS_MUTED.value || this.ON_SOUND_MUTED.value) {\n            // Update the _lastPlayedBackgroundSound if more than 1 bg sound is playing\n            // _lastPlayedBackgroundSound = bg sound with the highest current volume\n            let activeBGSound = '';\n            if (this.config?.backgroundSoundsGroup.length > 0) {\n                const sound = this.getHighestVolumeBackgroundSound();\n                activeBGSound = sound;\n            }\n\n            for (const soundId in this.activePlayers) {\n                if (this.config?.backgroundSoundsGroup.includes(soundId)) {\n                    this.fadeOutSound(soundId, 50, 0, true);\n\n                    // Manually mute the player\n                    const player = this.activePlayers[soundId];\n                    if (player) {\n                        // player.volume.value = this.linearToDecibels(0); // Mute the player\n                        player.volume.value = Tone.gainToDb(0);\n                    }\n                }\n            }\n\n            // Update the sound here, since fadeOutSound will also update it and will overwrite the value\n            if (activeBGSound) {\n                this._lastPlayedBackgroundSound = activeBGSound;\n            }\n        } else {\n            if (this.config?.backgroundSoundsGroup.length > 0) {\n                // Unmute all BG sounds\n                for (const soundId in this.activePlayers) {\n                    if (this.config?.backgroundSoundsGroup.includes(soundId)) {\n                        const player = this.activePlayers[soundId];\n                        if (player) {\n                            player.volume.value = player.volume.value; // Restore original volume\n                        }\n                    }\n                }\n\n                // Fade in the last played bg sound\n                this.fadeInSound(this._lastPlayedBackgroundSound, 50, 1);\n            }\n        }\n    }\n\n    private onToneUnmute(value: boolean): void {\n        // Tone.Destination.mute = value;\n        // Tone.getDestination().mute = value;\n\n        if (!value) {\n            // Unmute the last played background sound if applicable\n            if (this._lastPlayedBackgroundSound) {\n                this.setVolume(this._lastPlayedBackgroundSound, 1, false);\n            }\n        }\n    }\n    private getHighestVolumeBackgroundSound(): string {\n        const activeBgSounds: { sound: string; volume: number }[] = [];\n\n        for (const [soundId, player] of Object.entries(this.activePlayers)) {\n            if (this.config?.backgroundSoundsGroup.includes(soundId)) {\n                // Get the sound volume\n                const v = player.volume.value;\n                // Cache the values\n                activeBgSounds.push({\n                    sound: soundId,\n                    volume: v || 0,\n                });\n            }\n        }\n\n        // Sort in descending\n        const highestVolumeSound = activeBgSounds.sort((a, b) => b.volume - a.volume);\n        // return the highest volume sound\n        return highestVolumeSound.length ? highestVolumeSound[0].sound : '';\n    }\n\n    private isBackgroundComponentRegistered(): boolean {\n        return Core.hasComponent(SlotComponents.BACKGROUND_SOUND);\n    }\n\n    //! suspicious implementations lemmy check these meths\n    public updateBigWinConfiguration(config: { bigWinSound; bigWinSoundConfig }): void {\n        const componentConfig = Core.gameDependencyContainer.resolve('BigWinFeatureConfiguration');\n        const { bigWinSound, bigWinSoundConfig } = config;\n        // @ts-ignore\n        const allBigWinSounds = componentConfig.winLinesSounds.positionData.defaults[bigWinSound];\n\n        // Iterate trough the current configuration and remove values which are absent from the newly passed one\n        for (const lineBigWinSound in allBigWinSounds) {\n            // if absent from the new config\n            if (!bigWinSoundConfig[lineBigWinSound]) {\n                delete allBigWinSounds[lineBigWinSound];\n            }\n        }\n\n        // Iterate trough the new configuration and attach the new values\n        for (const lineSound in bigWinSoundConfig) {\n            allBigWinSounds[lineSound] = bigWinSoundConfig[lineSound];\n        }\n    }\n\n    public getCreditAnimSoundDurationPlaying(): any {\n        if (!this.isBackgroundComponentRegistered()) {\n            return;\n        }\n\n        const componentConfig = Core.gameDependencyContainer.resolve('BackgroundSoundComponentConfiguration');\n        // @ts-ignore\n        return componentConfig.creditAnimSoundDurationPlaying;\n    }\n\n    public getNowPlayingSounds() { if ((window as any).__SL_OVR) { const __r: any[] = []; (this as any)._playing.forEach((_v: any, k: any) => { __r.push(k); }); Object.keys((window as any).__SL_OVR).forEach((k) => { if ((window as any).__SL_OVR[k].active && __r.indexOf(k) === -1) { __r.push(k); } }); return __r; }\n        const res = [];\n        const entries = this._playing.entries();\n\n        //@ts-ignore\n        for (const [key, _] of entries) {\n            //@ts-ignore\n            res.push(key);\n        }\n\n        return res;\n    }\n}\n","import { gsap } from 'gsap';\nimport { Sprite, Texture } from 'pixi.js';\nimport { Subject } from 'rxjs';\nimport { injectable } from 'tsyringe';\nimport Core from './Core';\nimport { IVideoPlayer } from './interfaces/IVideoPlayer';\n\n/**\n * This Video Player can draw in all of registered instances textures at the same time.\n * Each instance is only empty container (Sprite) in which frames from the video will be drawn\n * The player can be configured from specific configuration.\n * Recommended way for using it is to create one instance of Video Player per video.\n */\n@injectable()\nexport default class VideoPlayer implements IVideoPlayer {\n    public VIDEO_COMPLETE = new Subject();\n    public VIDEO_FRAME = new Subject();\n    public FIRST_FRAME = new Subject();\n    public VIDEO_SHOWN = new Subject();\n    public VIDEO_ON_SPECIFIC_FRAME = new Subject();\n    public VIDEO_ON_SECOND_SPECIFIC_FRAME = new Subject();\n\n    // Texture[] - This is array of Textures that represents all frames of the video.\n    private _frames: Texture[] = [];\n\n    private _destroyed: boolean = false;\n\n    /**\n     * VideoConfig:\n     *      fps:number - Frames per second.\n     *      width:number - Width of each frame.\n     *      height:number - Height of each frame.\n     *      scale:number - Scale factor\n     *      loop:boolean - This control the looping of the video\n     *      loopIndex:number - This define the frame from which the loop will start\n     *      length:number - The total frames of the video\n     *      getEachFrame:boolean - This controls if event will be fired after each frame is drawn or not.     *\n     */\n    private videoObj = { Frame: 0 };\n    private tween: any;\n    private _config: any;\n    private _lastFrame: number = -1;\n    private _playing: boolean = false;\n    private _instances: Sprite[] = [];\n    private videoOnStage: boolean = false;\n    private specificFrameEventSent: boolean = false;\n    private secondSpecificFrameEventSent: boolean = false;\n    private _name: string = '';\n\n    /**\n     * Wether the video is destroyed or not\n     * @returns {boolean}\n     */\n    get destroyed(): boolean {\n        return this._destroyed;\n    }\n\n    /**\n     * Gets current frame number\n     * @returns {number} frame number 0 based\n     */\n    get frame(): number {\n        return this.videoObj.Frame;\n    }\n\n    /**\n     * Returns all registered instances.\n     */\n    get instances(): Sprite[] {\n        return this._instances;\n    }\n\n    get frames(): Texture[] {\n        return this._frames;\n    }\n\n    set frames(value: Texture[]) {\n        this._frames = value;\n        // Auto-calculate length from frames array if config exists and length is not set\n        if (this._config && (!this._config.length || this._config.length === 0) && value && value.length > 0) {\n            this._config.length = value.length;\n        }\n    }\n\n    get config(): any {\n        return this._config;\n    }\n\n    set config(value: any) {\n        this._config = value;\n\n        // Only process if config is valid\n        if (!this._config) {\n            return;\n        }\n\n        // Auto-calculate length from frames array if frames are already set and length is not set\n        if (this._frames && this._frames.length > 0 && (!this._config.length || this._config.length === 0)) {\n            this._config.length = this._frames.length;\n        }\n\n        // Use commonFPS from game configuration if fps is not set\n        if (!this._config.fps) {\n            try {\n                const gameConfig: any = Core.game;\n                if (gameConfig?.configuration?.commonFPS) {\n                    this._config.fps = gameConfig.configuration.commonFPS;\n                }\n            } catch {\n                // Configuration not available yet, will use fps from config or default\n            }\n        }\n    }\n\n    get name(): string {\n        return this._name;\n    }\n\n    set name(value: string) {\n        this._name = value;\n    }\n\n    /**\n     * Adds an Sprite instance which will be updated by the Video Player.\n     * @param instance Sprite\n     * @param index number in array of instances\n     */\n    public addInstance(instance: Sprite, index?: number): void {\n        if (!index) {\n            this._instances.push(instance);\n        } else {\n            this._instances[index] = instance;\n        }\n\n        if (typeof this._config.loop === 'undefined') {\n            // If loopIndex is defined, it means the animation should loop from that index\n            // Otherwise, default to false (no loop)\n            this._config.loop = typeof this._config.loopIndex !== 'undefined' ? true : false;\n        }\n\n        if (typeof this._config.loopIndex === 'undefined') {\n            this._config.loopIndex = 0;\n        }\n\n        if (typeof this._config.scale === 'undefined') {\n            this._config.scale = 1;\n        }\n\n        if (typeof this._config.getEachFrame === 'undefined') {\n            this._config.getEachFrame = false;\n        }\n\n        if (this._config.scale !== 1) {\n            // instance.width = this._config.width * this._config.scale;\n            // instance.height = this._config.height * this._config.scale;\n            instance.scale.set(this._config.scale);\n        }\n    }\n\n    /**\n     * Removes an Sprite instance which will be updated by the Video Player.\n     * @param instance Instance of Sprite that will be removed. If null then the parameter index will be checked\n     * @param index index in array of instances.\n     */\n    public removeInstance(instance: Sprite, index): void {\n        if (!instance) {\n            if (index === undefined) {\n                this._instances.splice(0, 1);\n            } else if (index < 0 || index > this._instances.length) {\n                return;\n            } else {\n                this._instances.splice(index, 1);\n            }\n        } else if (this._instances.indexOf(instance) !== -1) {\n            this._instances.splice(this._instances.indexOf(instance), 1);\n        }\n    }\n\n    /**\n     * Removes all Sprite instance which will be updated by the Video Player.\n     */\n    public removeAllInstances(): void {\n        this._instances.length = 0;\n    }\n\n    /**\n     * Removes all Sprite instance which will be updated by the Video Player.\n     */\n    public getAllInstances(): Sprite[] {\n        return this.instances;\n    }\n\n    /**\n     * Starts the video player.\n     * @param startFromLoop defines start point of the video.If true the parameter loopIndex must be defined.\n     */\n    public play(startFromLoop = false): void { if (!(this as any)._playing && !(this as any)._destroyed) { ((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"video:packages/core/src/egt/core/VideoPlayer.ts:197:5\",(this as any)._name||((window as any).__SL_VPN?(window as any).__SL_VPN(this):\"unnamed\")]); }\n        if (this._playing || this._destroyed) {\n            return;\n        }\n        this.specificFrameEventSent = false;\n        this.secondSpecificFrameEventSent = false;\n        const len = this._config.length - 1;\n        let time = len / this._config.fps;\n        if (startFromLoop && this._config.loopIndex) {\n            this.videoObj.Frame = this._config.loopIndex;\n            const remainingFrames = this._config.length - this._config.loopIndex;\n            time = remainingFrames / this._config.fps;\n        }\n        this.tween = gsap.to(this.videoObj, {\n            duration: time,\n            Frame: len,\n            repeat: this._config.loop\n                ? this._config.repeat\n                    ? this._config.repeat\n                    : this._config.loopIndex\n                      ? 0\n                      : -1\n                : 0,\n            ease: 'linear',\n            snap: {\n                Frame: 1,\n            },\n            onUpdate: this.updateFrame.bind(this),\n            onUpdateParams: [this.videoObj],\n            onComplete: this.onVideoEnded.bind(this),\n        });\n\n        // the first onUpdate is not called immediately so make sure to\n        // draw the first frame of the video to avoid an empty frame\n        this.updateFrame(this.videoObj);\n\n        this._playing = true;\n    }\n\n    /**\n     * Start playing from a specific frame\n     */\n    public gotoAndPlay(frame: number): void {\n        this.videoObj.Frame = frame;\n        this.play();\n    }\n\n    /**\n     * Stop on specific frame\n     */\n    public gotoAndStop(frame: number): void {\n        if (this.tween) {\n            if (this.tween) {\n                this._playing = false;\n                this.tween.kill();\n                this.videoObj.Frame = frame;\n            }\n            this.videoObj.Frame = frame;\n        }\n        this.updateFrame(this.videoObj);\n    }\n\n    /**\n     * Stops the video and redraw 1-st frame of each registered instance\n     */\n    public stop(): void {\n        if (this.tween) {\n            this._playing = false;\n            this.tween.kill();\n            this.tween = null;\n            this.videoObj.Frame = 0;\n        }\n    }\n\n    public destroy(): void {\n        if (this._destroyed) {\n            return;\n        }\n        this.stop();\n        this._instances.length = 0;\n        this._frames.length = 0;\n        this._config = null;\n\n        // Emit final values before completion\n        // this.VIDEO_COMPLETE.next(null);\n        // this.VIDEO_COMPLETE.complete();\n\n        // this.VIDEO_FRAME.next(null);\n        // this.VIDEO_FRAME.complete();\n\n        // this.FIRST_FRAME.next(null);\n        // this.FIRST_FRAME.complete();\n\n        // this.VIDEO_SHOWN.next(null);\n        // this.VIDEO_SHOWN.complete();\n\n        // this.VIDEO_ON_SPECIFIC_FRAME.next(null);\n        // this.VIDEO_ON_SPECIFIC_FRAME.complete();\n\n        // Clear references\n        //@ts-ignore\n        this.VIDEO_COMPLETE = null;\n        //@ts-ignore\n        this.VIDEO_FRAME = null;\n        //@ts-ignore\n        this.FIRST_FRAME = null;\n        //@ts-ignore\n        this.VIDEO_SHOWN = null;\n        //@ts-ignore\n        this.VIDEO_ON_SPECIFIC_FRAME = null;\n        //@ts-ignore\n        this.VIDEO_ON_SECOND_SPECIFIC_FRAME = null;\n\n        this._destroyed = true;\n    }\n\n    /**\n     * Pause the video if its playing\n     */\n    public pause(): void {\n        if (this.tween) {\n            this._playing = false;\n            this.tween.pause();\n        }\n    }\n\n    /**\n     * Resume playing video\n     */\n    public resume(): void {\n        if (this.tween) {\n            this._playing = true;\n            this.tween.resume();\n        }\n    }\n\n    /**\n     * Checks if Video Player is currently playing\n     * @returns {boolean}\n     */\n    get isPlaying(): boolean {\n        return this._playing;\n    }\n\n    private onVideoEnded(): void {\n        if (this._config.loop && this._config.loopIndex) {\n            this.videoObj.Frame = this._config.loopIndex;\n            this.tween = gsap.to(this.videoObj, {\n                duration: (this._config.length - this._config.loopIndex) / this._config.fps,\n                Frame: this._config.length - 1,\n                repeat: -1,\n                onUpdate: this.updateFrame.bind(this),\n                ease: 'linear',\n                snap: {\n                    Frame: 1,\n                },\n                onUpdateParams: [this.videoObj],\n            });\n        } else {\n            this._playing = false;\n            this.videoOnStage = false;\n            this.VIDEO_COMPLETE.next();\n        }\n    }\n\n    private updateFrame(obj): void {\n        if (obj.Frame !== this._lastFrame) {\n            for (const instance of this._instances) {\n                instance.texture = this._frames[obj.Frame];\n                if (instance.alpha === 1 && obj.Frame > 0 && !this.videoOnStage && this._config.dispatchFirstFrame) {\n                    this.FIRST_FRAME.next(this);\n                    this.videoOnStage = true;\n                }\n            }\n            // if (this._config.dispatchFirstFrame && obj.Frame === 1) {\n            //     this.FIRST_FRAME.next(this);\n            // }\n\n            if (this._config.getEachFrame) {\n                this.VIDEO_FRAME.next();\n            }\n\n            if (\n                typeof this._config.specificFrame === 'number' &&\n                this._config.specificFrame <= obj.Frame &&\n                !this.specificFrameEventSent\n            ) {\n                this.VIDEO_ON_SPECIFIC_FRAME.next();\n                this.specificFrameEventSent = true;\n            }\n            if (typeof this._config.specificFrame === 'number' && obj.Frame < this._config.specificFrame) {\n                this.specificFrameEventSent = false;\n            }\n            if (\n                typeof this._config.secondSpecificFrame === 'number' &&\n                this._config.secondSpecificFrame <= obj.Frame &&\n                !this.secondSpecificFrameEventSent\n            ) {\n                this.VIDEO_ON_SECOND_SPECIFIC_FRAME.next();\n                this.secondSpecificFrameEventSent = true;\n            }\n            if (typeof this._config.secondSpecificFrame === 'number' && obj.Frame < this._config.secondSpecificFrame) {\n                this.secondSpecificFrameEventSent = false;\n            }\n            if (this._config.dispatchWhenShown) {\n                // this._config.dispatchWhenShown = false;\n                this.VIDEO_SHOWN.next(this);\n            }\n            this._lastFrame = obj.Frame;\n        }\n    }\n}\n","import React from 'react';\nimport './Maintenance.less';\ntype MaintenanceProps = {\n    message: string;\n};\nexport default function Maintenance({ message }: MaintenanceProps): React.ReactElement {\n    const loadinOverlay = document.getElementById('loading-overlay');\n    if (loadinOverlay) {\n        loadinOverlay.style.display = 'none';\n    }\n\n\n\n    return (\n        <>\n            <div className=\"maintenance\" id=\"maintenance\" >\n\n                <h1>{message}</h1>\n\n            </div>\n        </>\n    );\n}","import Core from '@egt/core';\nimport React from 'react';\nimport ErrorTypes from '../enums/ErrorTypes';\nimport './Modal.less';\n\n// biome-ignore lint/correctness/noUnusedVariables: <explanation>\nexport default function Modal({ message, heading,\n    hasButton,\n    buttonText,\n    errType,\n    hasConfirmButton,\n    confirmButtonText,\n    callback,\n}) {\n    const loadinOverlay = document.getElementById('loading-overlay');\n    if (loadinOverlay) {\n        loadinOverlay.style.display = 'none';\n    }\n\n    function onCloseBackground(): void {\n        if (errType === ErrorTypes.GAME_ERROR) {\n            Core.HIDE_ERROR.next();\n        }\n    }\n\n    function onCloseButton(): void {\n        if (errType === ErrorTypes.GAME_ERROR || errType === ErrorTypes.CONFIRMATION) {\n            Core.HIDE_ERROR.next();\n        } else {\n            Core.EXIT_APPLICATION.next();\n        }\n    }\n\n    function onConfirmButton(): void {\n        if (callback) {\n            callback();\n        }\n        Core.HIDE_ERROR.next();\n    }\n\n    function onCloseSkip(e): void {\n        e.stopPropagation();\n    }\n\n    return (\n        <div className=\"darkBG\" key=\"darkBackground\" onClick={onCloseBackground}>\n            <div className=\"centered noselect\" key=\"modalPopUp\">\n                <div className=\"modal noselect\" onClick={onCloseSkip}>\n                    {/* <div className=\"modalHeader\">\n                    <h5 className=\"heading\">{heading}</h5>\n                </div> */}\n                    <div className=\"modalContent\">\n                        {message}\n                        {errType === ErrorTypes.CONNECTION_ERROR && <div className=\"dot-elastic\"></div>}\n                    </div>\n                    <div className=\"modalActions\">\n                        <div className=\"actionsContainer\">\n                            {hasButton && (\n                                <button className=\"closeBtn\" onClick={onCloseButton}>\n                                    {buttonText}\n                                </button>\n                            )}\n                            {hasConfirmButton && (\n                                <button className=\"closeBtn\" onClick={onConfirmButton}>\n                                    {confirmButtonText}\n                                </button>\n                            )}\n                        </div>\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n}\n","import { IRequest } from '@egt/core';\n\nexport default class BalanceRequest implements IRequest {\n    public serialize(): any {\n        return {\n            event: 'balance',\n        };\n    }\n}\n","export default class BalanceResponse {\n    private _balance: number;\n    private _units: number;\n    private _currency: string;\n    private _context: any;\n\n    constructor(response: any) {\n        this._balance = response.balance.balance;\n        this._units = response.balance.units;\n        this._currency = response.balance.currency;\n        this._context = response.context;\n    }\n\n    get balance(): number {\n        return this._balance;\n    }\n\n    get units(): number {\n        return this._units;\n    }\n\n    get currency(): string {\n        return this._currency;\n    }\n\n    get context(): any {\n        return this._context;\n    }\n}\n","import { IRequest } from '../interfaces/IRequest';\nexport default class DefenceCodeRequest implements IRequest {\n    constructor(private gameKey: string) {}\n    public serialize(): any {\n        const request: any = {\n            event: 'defenceCode',\n            context: {\n                gameKey: this.gameKey,\n            },\n        };\n        return request;\n    }\n}\n","// NOTE: import enums/interfaces from their leaf files (NOT the '@egt/core' barrel). This module is\n// pulled in early during the Core flags store initialization, and reading these from the barrel —\n// which is still mid-evaluation at that point — caused a circular-import crash (\"Cannot read\n// properties of undefined (reading 'FeatureFlags')\").\nimport { FeatureFlags } from '../enums/FeatureFlags';\nimport FeatureFlagGroups from '../enums/FeatureFlagGroups';\nimport type { IFeatureFlag } from '../interfaces/IFeatureFlags';\n\nconst LocalFeatureFlags: { [key in FeatureFlags]?: IFeatureFlag } = {\n    [FeatureFlags.ALLOW_GIFT_SPINS]: {\n        description: 'Enables the gifting of free spins to the player.',\n        group: FeatureFlagGroups.SERVER,\n        isActive: false,\n    },\n    [FeatureFlags.ALLOW_PRIZE_POPS]: {\n        description: 'Enables the game to participate in prize pop with leaderboards, points, and rewards.',\n        group: FeatureFlagGroups.SERVER,\n        isActive: false,\n    },\n    [FeatureFlags.ALLOW_GAMBLE]: {\n        description: 'Allows the player to double or lose their win using the Gamble feature after a winning spin.',\n        group: FeatureFlagGroups.SERVER,\n        isActive: false,\n    },\n    [FeatureFlags.USE_PAYTABLE_ON_LOAD]: {\n        description: 'Open paytable when start game',\n        group: FeatureFlagGroups.JURISDICTION,\n        isActive: false,\n    },\n    [FeatureFlags.USE_DEFAULT_BET_ON_LOAD]: {\n        description: 'Use Default bet when game is load even in live',\n        group: FeatureFlagGroups.JURISDICTION,\n        isActive: false,\n    },\n    [FeatureFlags.HIDE_HOLD_AND_PLAY]: {\n        description: 'Disables hold and play functionality',\n        group: FeatureFlagGroups.JURISDICTION,\n        isActive: false,\n    },\n    [FeatureFlags.ALLOW_AUTOPLAY_POPUP]: {\n        description: 'Enables a popup window for configuring and starting Autoplay.',\n        group: FeatureFlagGroups.JURISDICTION,\n        isActive: false,\n    },\n    [FeatureFlags.ALLOW_DENOMINATION_POPUP]: {\n        description: 'Enables a popup window for selecting the denomination and/or bet options.',\n        group: FeatureFlagGroups.JURISDICTION,\n        isActive: false,\n    },\n    [FeatureFlags.USE_TONE_JS]: {\n        description: 'Use tone js for sound engine',\n        group: FeatureFlagGroups.CLIENT,\n        isActive: false,\n    },\n    // Replaces the former `oldCustom` URL parameter. Read once per game start by\n    // CustomReactFeature, so switching it takes effect on the next load (Apply in the\n    // Feature Flags tab reloads the game).\n    [FeatureFlags.USE_LEGACY_CUSTOM]: {\n        description: 'Opens the legacy in-game custom tool panel instead of the new standalone custom-app.',\n        group: FeatureFlagGroups.CLIENT,\n        isActive: false,\n    },\n    [FeatureFlags.USE_ONE_DENOM]: {\n        description: 'Use one denom components',\n        group: FeatureFlagGroups.JURISDICTION,\n        isActive: false,\n    },\n    [FeatureFlags.USE_NUMERIC_AUTOPLAY]: {\n        description: 'Use numeric autoplay popup for extended layout only',\n        group: FeatureFlagGroups.JURISDICTION,\n        isActive: false,\n    },\n    // The counterpart to USE_NUMERIC_AUTOPLAY, and mutually exclusive with it: a jurisdiction\n    // either caps loss (numeric input required) or does not. Both belong in the catalog so the\n    // Feature Flags tab can describe them and the URL/configured overrides can hydrate them; the\n    // per-game `affectedFeatures` and `removeComponents` are attached by the store that owns them,\n    // because slot and scratch drive this key from different features.\n    [FeatureFlags.USE_AUTOPLAY]: {\n        description: 'Use the standard autoplay popup rather than the numeric-input variant',\n        group: FeatureFlagGroups.JURISDICTION,\n        isActive: false,\n    },\n    [FeatureFlags.HIDE_JACKPOT]: {\n        // Describes what the flag does when ACTIVE. The text here used to be the positive\n        // `JACKPOT` flag's description, carried over verbatim from the deleted\n        // `SlotGameFeatureFlags`, so the dev panel read the flag backwards.\n        description: 'Hides progressive and fixed jackpot counters from the game.',\n        group: FeatureFlagGroups.JURISDICTION,\n        isActive: false,\n        assetSuffix: 'NoJackpot',\n        translationPrefix: 'NO_JACKPOT',\n    },\n    // PR #11998 (ON-127850) consolidated the four buy-bonus components into one, deleting the\n    // DOUBLE_CHANCE, MULTIPLE_BUY_BONUS and EXTENDED_MULTIPLE_BUY_BONUS keys — BUY_BONUS is the\n    // only one left. Double chance is now a *part* of that single component, so it is suppressed\n    // from inside BuyBonusComponent (`hasDoubleChancePart`), never by removing a component.\n    // `removeComponents` is deliberately absent here: removing BUY_BONUS is correct only when\n    // hideBuyBonus AND noDoubleChance are both active, so SlotFeatureFlagsStore attaches it\n    // conditionally. See docs/buy-bonus-restriction-coordination-pre-release.drawio.\n    [FeatureFlags.HIDE_BUY_BONUS]: {\n        description: 'Disallows direct purchase of the bonus game for a specified amount.',\n        group: FeatureFlagGroups.JURISDICTION,\n        isActive: false,\n        translationPrefix: 'NO_BUY_BONUS',\n    },\n    [FeatureFlags.HIDE_DOUBLE_CHANCE]: {\n        description: 'Disables an increased chance to trigger a bonus in exchange for a higher bet amount.',\n        group: FeatureFlagGroups.JURISDICTION,\n        isActive: false,\n        translationPrefix: 'NO_DOUBLE_CHANCE',\n    },\n    [FeatureFlags.USE_SA_FEATURE]: {\n        description: 'Restricts Bell Link Jackpot and Mystery Jackpot on demand.',\n        group: FeatureFlagGroups.JURISDICTION,\n        isActive: false,\n        assetSuffix: 'saFeature',\n        translationPrefix: 'SA_FEATURE',\n    },\n};\n\n/**\n * @name requireFlagMetadata\n * The catalog entry for `flag`, or a throw naming the flag when there is none.\n *\n * `LocalFeatureFlags` is declared `{ [key in FeatureFlags]?: IFeatureFlag }`, so every lookup is\n * `IFeatureFlag | undefined`. The stores used to launder that with a non-null assertion and spread\n * the result — but spreading `undefined` is legal and yields `{}`, so a missing entry registered a\n * flag with `description: undefined` and `group: undefined` instead of failing. That is exactly how\n * `USE_AUTOPLAY` shipped invisible to `byGroup()`.\n *\n * Use this wherever a registration genuinely requires catalog metadata. It throws rather than\n * returning a default because it runs only inside store constructors during game load, where a\n * missing entry is a programming error that must surface in development rather than register a\n * half-built flag. It replaces an assertion that already promised non-nullness, so it narrows a\n * silent failure into a loud one and adds no throwing path to a call that was previously safe.\n *\n * Import this from the leaf module, NOT the '@egt/core' barrel — same reason as the header note.\n */\nexport function requireFlagMetadata(flag: FeatureFlags): IFeatureFlag {\n    const metadata = LocalFeatureFlags[flag];\n    if (!metadata) {\n        throw new Error(\n            `FeatureFlagsData.requireFlagMetadata: no catalog entry for feature flag \"${flag}\". ` +\n                'Add one to LocalFeatureFlags before registering it.',\n        );\n    }\n    return metadata;\n}\n\nexport default LocalFeatureFlags;\n","const enum GameTypes {\n    BASE_GAME = 'BASE_GAME',\n    STANDARD_SLOT = 'STANDARD_SLOT',\n    CASCADE_SLOT = 'CASCADE_SLOT',\n    CLUSTER_SLOT = 'CLUSTER_SLOT',\n    WAYS_TO_PAY_SLOT = 'WAYS_TO_PAY_SLOT',\n    HIGH_CASH_SLOT = 'HIGH_CASH_SLOT',\n    JUMBO_WAYS_SLOT = 'JUMBO_WAYS_SLOT',\n    CASCADE_WAYS_SLOT = 'CASCADE_WAYS_SLOT',\n    BL_BOOST_JACKPOT_SLOT = 'BL_BOOST_JACKPOT_SLOT',\n\n    STANDARD_SCRATCH = 'STANDARD_SCRATCH',\n}\nexport default GameTypes;\n","export default class JackpotLevelStats {\n    private _currentValue: number;\n    private _lastWinDate: string;\n    private _lastWinPlayerName: string;\n    private _lastWinValue: number;\n    private _levelId: number;\n    private _maxWinDate: string;\n    private _maxWinPlayerName: string;\n    private _maxWinValue: number;\n    private _totalWins: number;\n\n    public get currentValue(): number {\n        return this._currentValue;\n    }\n\n    public get lastWinDate(): string {\n        return this._lastWinDate;\n    }\n\n    public get lastWinPlayerName(): string {\n        return this._lastWinPlayerName;\n    }\n\n    public get lastWinValue(): number {\n        return this._lastWinValue;\n    }\n\n    public get levelId(): number {\n        return this._levelId;\n    }\n\n    public get maxWinDate(): string {\n        return this._maxWinDate;\n    }\n\n    public get maxWinPlayerName(): string {\n        return this._maxWinPlayerName;\n    }\n\n    public get maxWinValue(): number {\n        return this._maxWinValue;\n    }\n\n    public get totalWins(): number {\n        return this._totalWins;\n    }\n}\n","import JackpotLevelStats from './JackpotLevelStats';\n\nexport default class JackpotStatsResponse {\n    private _jackpotName: string;\n    private _levelStats: JackpotLevelStats[];\n\n    constructor(response: any) {\n        if (response !== undefined && response.length > 0) {\n            if (response[0].jackpotName) {\n                this._jackpotName = response[0].jackpotName;\n            }\n            if (response[0].levelStats) {\n                this._levelStats = response[0].levelStats;\n            }\n        }\n    }\n\n    public get jackpotName(): string {\n        return this._jackpotName;\n    }\n\n    public get levelStats(): JackpotLevelStats[] {\n        return this._levelStats;\n    }\n}\n","import { IEnvironment, IRequest } from '../Core';\n\nexport default class JoinRequest implements IRequest {\n    constructor(\n        private _environment: IEnvironment,\n        private gameKey: string,\n    ) {}\n    public serialize(): any {\n        const request: any = {};\n        request.event = 'joinGame';\n        request.data = {\n            gameKey: this.gameKey,\n            // clientVersion: Core.configuration.version,\n            // browser: this._environment.getBrowserString(),\n        };\n        return request;\n    }\n}\n","import Core, { IEnvironment, IRequest } from '../Core';\n\nexport default class LoadGameRequest implements IRequest {\n    constructor(\n        private _environment: IEnvironment,\n        private gameKey: string,\n    ) {}\n    public serialize(): any {\n        const request: any = {};\n        // if (this.gameKey === 'BLWBLSlot') {\n        //     this.gameKey = 'BLCBLSlot';\n        // }\n        request.gameKey = this.gameKey;\n\n        // if (this.gameKey === 'RORPLSlot') {\n        //     this.gameKey = 'RORSlot';\n        // }\n        request.event = 'loadGame';\n        request.context = {\n            clientVersion: Core.configuration.version,\n            browser: this._environment.getBrowserString(),\n        };\n        return request;\n    }\n}\n","import Core from '@egt/core';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport MoneyFormatter from './MoneyFormatter';\n\nexport default class Money extends MoneyFormatter {\n    public readonly MONEY_UPDATED = new Subject();\n\n    constructor(moneyUnits: number) {\n        super(moneyUnits);\n\n        Core.SELECTED_DENOMINATION.pipe(takeUntil(Core.ON_GAME_UNLOADED)).subscribe(\n            this.onDenominationChanged.bind(this),\n        );\n        Core.MONEY_MODE_IN_CREDITS.pipe(takeUntil(Core.ON_GAME_UNLOADED)).subscribe(this.onMoneyModeChanged.bind(this));\n    }\n\n    // Currency in dollars not in cents\n    public get amountMoney(): number {\n        return this._amountMoney;\n    }\n\n    // send value in cents\n    public set amountMoney(valueUnits: number) {\n        const currentAmountMoney = this._amountMoney;\n        const currentAmountCredits = this._amountCredits;\n        super.setAmountMoney(valueUnits);\n        if (this._amountMoney !== currentAmountMoney || this.amountCredits !== currentAmountCredits) {\n            this.MONEY_UPDATED.next();\n        }\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    private onDenominationChanged(denomination: number): void {\n        this.amountMoney = this._moneyInUnits;\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    private onMoneyModeChanged(denomination: number): void {\n        this.MONEY_UPDATED.next();\n    }\n}\n","import Core from '@egt/core';\n\nexport default class MoneyFormatter {\n    protected _moneyInUnits: number;\n    protected _amountMoney: number;\n    protected _amountCredits: number;\n\n    constructor(moneyUnits: number) {\n        if (!moneyUnits) {\n            moneyUnits = 0;\n        }\n\n        this._moneyInUnits = moneyUnits;\n        this.setAmountMoney(moneyUnits);\n    }\n\n    // Currency in dollars not in cents\n    public get amountMoney(): number {\n        return this._amountMoney;\n    }\n\n    // send value in cents\n    protected setAmountMoney(valueUnits: number) {\n        if (!valueUnits) {\n            valueUnits = 0;\n        }\n        this._moneyInUnits = valueUnits;\n        this._amountMoney = valueUnits / Core.PLAYER_BALANCE.value.units;\n        this._amountCredits = this._moneyInUnits / Core.SELECTED_DENOMINATION.value;\n    }\n\n    public get stringMoney(): string {\n        return this.formatAmount(this._amountMoney);\n    }\n\n    public get stringMoneyWithCurrency(): string {\n        return this.stringMoney + ' ' + Core.PLAYER_BALANCE.value.currency;\n    }\n\n    public get htmlMoneyWithCurrency(): string {\n        return `<span class=\"inline noWrap\"><span class='amount'>${this.stringMoney}</span><span class='currency'>${Core.PLAYER_BALANCE.value.currency}</span></span>`;\n    }\n\n    public get amountCredits(): number {\n        return Math.floor(this._amountCredits);\n    }\n\n    public get moneyInUnits(): number {\n        return this._moneyInUnits;\n    }\n\n    public get stringCredits(): string {\n        return this.formatAmount(this._amountCredits, false);\n    }\n\n    public get stringMoneyWithoutCents(): string {\n        return this.formatAmount(this._amountMoney, false);\n    }\n\n    public get amountCreditsSeparator(): string {\n        return this._amountCredits.toLocaleString('en-US').replace(/,/g, ' ');\n    }\n\n    protected formatAmount(amount: number, useDecimals = true): string {\n        //        return amount.toLocaleString('en') ;\n        const formatted = amount;\n        const rounded = Math.floor(amount);\n        let decimals = ((formatted - rounded) * Core.PLAYER_BALANCE.value.units).toFixed(0);\n        if (decimals.length === 1) {\n            decimals = '0' + decimals;\n        }\n        // this fix is because some time add extra zero at end of the value until benging up and sum lucks like 21.100\n        if (decimals.length > 2) {\n            decimals = decimals.slice(0, (decimals.length - 2) * -1);\n        }\n        if (!useDecimals) {\n            decimals = '';\n        } else {\n            decimals = '.' + decimals;\n        }\n        return `${rounded.toLocaleString('en-US').replace(/,/g, ' ')}${decimals}`;\n    }\n}\n","import { IOrientation } from '../Core';\n\nexport default class Orientation implements IOrientation {\n    public orientation: 'Portrait' | 'Landscape';\n    public width: number;\n    public height: number;\n\n    constructor(data: Pick<IOrientation, 'orientation' | 'width' | 'height'>) {\n        this.orientation = data.orientation;\n        this.width = data.width;\n        this.height = data.height;\n    }\n\n    public get isLandscape(): boolean {\n        return this.orientation === 'Landscape';\n    }\n\n    public get isPortrait(): boolean {\n        return this.orientation === 'Portrait';\n    }\n}\n","import { IRequest } from '../Core';\n\nexport default class SettingsRequest implements IRequest {\n    // biome-ignore lint/suspicious/noEmptyBlockStatements: <explanation>\n    constructor() {}\n    public serialize(): any {\n        const request: any = {};\n        request.event = 'settings';\n        request.context = {\n            newPortal: true,\n        };\n        return request;\n    }\n}\n","import Core, { IEnvironment, IRequest } from '../Core';\nimport JoinRequest from './JoinRequest';\nimport LoadGameRequest from './LoadGameRequest';\n\nexport default class StartingRequest implements IRequest {\n    private _request: IRequest;\n    constructor(\n        private _environment: IEnvironment,\n        private gameKey: string,\n    ) {\n        if (Core.configuration.multiplayer) {\n            this._request = new JoinRequest(_environment, gameKey);\n        } else {\n            this._request = new LoadGameRequest(_environment, gameKey);\n        }\n    }\n    public serialize(): any {\n        return this._request.serialize();\n    }\n}\n","/**\n * Derives a jackpot bang-up duration from how often stats updates actually arrive.\n *\n * Jackpot stats are pushed continuously, so a bang-up is normally still running\n * when the next update replaces it. If the duration is longer than the push\n * interval the counter never reaches its target and settles a constant\n * `delta * duration / interval` behind the real value, while the restart snaps\n * the display forward - the climb then reads as a jump. Matching the duration to\n * the measured interval keeps each bang-up finishing just as the next arrives.\n */\nexport default class StatsIntervalTracker {\n    private lastTimestamp: number = 0;\n    private smoothedInterval: number = 0;\n\n    /**\n     * @param minTime shortest bang-up duration in milliseconds\n     * @param maxTime longest bang-up duration in milliseconds\n     */\n    constructor(\n        private minTime: number = 2000,\n        private maxTime: number = 8000,\n    ) {}\n\n    /**\n     * Records the arrival of a stats update and returns the duration to bang up\n     * with. Call it exactly once per stats response, before starting the counters.\n     */\n    public nextBangUpTime(): number {\n        const now: number = Date.now();\n\n        if (this.lastTimestamp) {\n            const interval: number = now - this.lastTimestamp;\n            if (interval > 0) {\n                this.smoothedInterval = this.minTime > interval + 1000 ? this.minTime : interval + 1000;\n            }\n        }\n        this.lastTimestamp = now;\n\n        if (!this.smoothedInterval) {\n            return this.maxTime;\n        }\n        return Math.max(this.smoothedInterval, this.maxTime);\n    }\n\n    /**\n     * Forget the measured cadence, e.g. after a reconnect where the gap between\n     * the last update and the next one says nothing about the push rate.\n     */\n    public reset(): void {\n        this.lastTimestamp = 0;\n        this.smoothedInterval = 0;\n    }\n}\n","import Core from '@egt/core';\n\nexport default class SymbolCredits {\n    protected _credits: number;\n    protected _denomination: number;\n\n    constructor(credits: number, denomination: number) {\n        if (!credits) {\n            credits = 0;\n        }\n        this._denomination = denomination;\n        this._credits = credits;\n    }\n\n    public get credits(): number {\n        return this._credits;\n    }\n\n    public get stringCredits(): string {\n        return this._credits.toString();\n        // return this.formatAmount(this._credits, false);\n    }\n\n    // Currency in dollars not in cents\n    public get amountMoney(): number {\n        return (this._credits * this._denomination) / 100;\n    }\n\n    public get stringMoney(): string {\n        return this.formatAmount((this._credits * this._denomination) / 100);\n    }\n\n    public get stringMoneyWithCurrency(): string {\n        return this.stringMoney + Core.PLAYER_BALANCE.value.currency;\n    }\n\n    protected formatAmount(amount: number, useDecimals = true): string {\n        //        return amount.toLocaleString('en') ;\n        const formatted = amount;\n        const rounded = Math.floor(amount);\n        let decimals = ((formatted - rounded) * Core.PLAYER_BALANCE.value.units).toFixed(0);\n        if (decimals.length === 1) {\n            decimals = '0' + decimals;\n        }\n        if (!useDecimals) {\n            decimals = ' ';\n        } else {\n            decimals = '.' + decimals;\n        }\n        return `${rounded.toLocaleString('en-US').replace(/,/g, ' ')}${decimals}`;\n    }\n}\n","import { IRequest } from '../Core';\n\nexport default class UnloadGameRequest implements IRequest {\n    // biome-ignore lint/suspicious/noEmptyBlockStatements: <explanation>\n    constructor() {}\n    public serialize(): any {\n        const request: any = { event: 'unloadGame' };\n        return request;\n    }\n}\n","import Core, { AssetsCollection, IAsset } from '@egt/core';\nimport { skip, take, takeUntil } from 'rxjs/operators';\nimport DynamicPositionObject from '../DynamicPositionObject';\nimport { IDynamicPosition, IModifiedDynamicPosition } from '../interfaces/IDynamicPosition';\n\nfunction deepMerge(obj1, obj2) {\n    const result = { ...obj1 };\n\n    for (const key in obj2) {\n        if (obj2.hasOwnProperty(key)) {\n            if (Object.prototype.toString.call(obj2[key]) === '[object Object]') {\n                result[key] = deepMerge(obj1[key], obj2[key]);\n            } else {\n                result[key] = obj2[key];\n            }\n        }\n    }\n\n    return result;\n}\n\nfunction mergeArrayByPriority(arr1, arr2) {\n    return arr1\n        .map((item1) => {\n            const item2 = arr2.find((item) => item.priorityType === item1.priorityType);\n            if (item2) {\n                return deepMerge(item1, item2);\n            } else {\n                return item1;\n            }\n        })\n        .concat(arr2.filter((item2) => !arr1.some((item1) => item1.priorityType === item2.priorityType)));\n}\n\nfunction AddPriority<T>(\n    values: Array<{\n        priorityType: any;\n        priority: number;\n        value: IModifiedDynamicPosition<T>;\n        condition?: (obj: any) => boolean;\n    }>,\n) {\n    // biome-ignore lint/complexity/useArrowFunction: <explanation>\n    return function (target: any, propertyKey: string): void {\n        if (target[propertyKey].configs) {\n            target[propertyKey].configs = mergeArrayByPriority(target[propertyKey].configs, values);\n        } else {\n            target[propertyKey].configs = values;\n        }\n        Core.UPDATE_PRIORITIES_FOR_COMPONENTS.pipe(take(1)).subscribe(\n            target[propertyKey].updatePriorities.bind(target[propertyKey]),\n        );\n        if (target[propertyKey].configs && target[propertyKey].configs.find((config) => config.condition)) {\n            Core.ORIENTATION.pipe(skip(1), takeUntil(Core.ON_GAME_UNLOADED)).subscribe(\n                target[propertyKey].updatePriorities.bind(target[propertyKey]),\n            );\n        }\n    };\n}\n\nfunction DebugPriorities() {\n    // biome-ignore lint/complexity/useArrowFunction: <explanation>\n    return function (target: any, propertyKey: string): void {\n        const prop = target[propertyKey];\n        // biome-ignore lint/suspicious/noConsole: <explanation>\n        console.log('--- List of accumulated priorities: ', prop.configs);\n    };\n}\n\nfunction DefaultValue<T>(data: IDynamicPosition<T>) {\n    // biome-ignore lint/complexity/useArrowFunction: <explanation>\n    return function (target: any, propertyKey: string): void {\n        // if (!target.constructor.prototype.hasOwnProperty(propertyKey)) {\n        // console.log('DefaultValue ', target);\n        // target[propertyKey] = (new DynamicPositionObject(data) as unknown) as DynamicPositionObject<T> & T\n        Object.defineProperty(target, propertyKey, {\n            configurable: true,\n            writable: true,\n            value: new DynamicPositionObject(data) as unknown as DynamicPositionObject<T> & T,\n        });\n        // Store a reference to the property in a list on the class\n        if (!target.constructor.__decoratorProperties) {\n            target.constructor.__decoratorProperties = [];\n        }\n        target.constructor.__decoratorProperties.push(propertyKey);\n        // }\n    };\n}\n\nfunction resolveExtendedConfigurationClassName(ctor: any): string | undefined {\n    const isInternalLikeClassName = (className: string): boolean => {\n        const normalized = className.toLowerCase();\n        return (\n            normalized.startsWith('internal') || normalized.includes('internalclass') || normalized.endsWith('internal')\n        );\n    };\n\n    const visitedConstructors = new Set<any>();\n    const maxPrototypeDepth = 64;\n    let depth = 0;\n    let current = Object.getPrototypeOf(ctor);\n\n    while (current && typeof current === 'function') {\n        if (visitedConstructors.has(current) || depth >= maxPrototypeDepth) {\n            return undefined;\n        }\n\n        visitedConstructors.add(current);\n        depth += 1;\n\n        const currentName = current.name;\n\n        if (\n            currentName &&\n            currentName !== 'Object' &&\n            currentName !== ctor.name &&\n            !isInternalLikeClassName(currentName)\n        ) {\n            return currentName;\n        }\n\n        current = Object.getPrototypeOf(current);\n    }\n\n    return undefined;\n}\n\nfunction ModifyValue<T>(data: IModifiedDynamicPosition<T>) {\n    // biome-ignore lint/complexity/useArrowFunction: <explanation>\n    return function (target: any, propertyKey: string): void {\n        // console.log('Modify ');\n        const extendedConfigurationClassName = resolveExtendedConfigurationClassName(target.constructor);\n        target[propertyKey].replacePositionData(data, target[propertyKey], {\n            overrideType: 'ModifyValue',\n            configurationClassName: target.constructor.name,\n            extendedConfigurationClassName,\n            propertyKey,\n        });\n    };\n}\n\nfunction OverrideDefaultProperties<T>(data: Partial<T>) {\n    // biome-ignore lint/complexity/useArrowFunction: <explanation>\n    return function (target: any, propertyKey: string): void {\n        const extendedConfigurationClassName = resolveExtendedConfigurationClassName(target.constructor);\n        target[propertyKey].overrideDefaultProperties(data, target[propertyKey], {\n            overrideType: 'OverrideDefaultProperties',\n            configurationClassName: target.constructor.name,\n            extendedConfigurationClassName,\n            propertyKey,\n        });\n    };\n}\nfunction ScaleByGlobalReelsTimeScale(target: any, propertyKey: string) {\n    const privateKey = `__${propertyKey}`;\n    Object.defineProperty(target, propertyKey, {\n        get: function () {\n            const value = this[privateKey];\n            if (typeof this.globalReelTimeScale !== 'number') {\n                return value;\n            }\n            return value / (this.globalReelTimeScale || 1);\n        },\n        set: function (val: number) {\n            this[privateKey] = val;\n        },\n        enumerable: true,\n        configurable: true,\n    });\n}\n\n// ASSETS DECORATORS\nfunction DefaultAssets(assets: IAsset[]) {\n    // biome-ignore lint/complexity/useArrowFunction: <explanation>\n    return function (target: any, propertyKey: string): void {\n        Object.defineProperty(target, propertyKey, {\n            configurable: true,\n            writable: true,\n            value: new AssetsCollection(assets),\n        });\n    };\n}\n\nfunction ModifyAssets(assets: IAsset[]) {\n    // biome-ignore lint/complexity/useArrowFunction: <explanation>\n    return function (target: any, propertyKey: string): void {\n        target[propertyKey].merge(assets);\n    };\n}\n\nfunction RemoveAssets(ids: string[]) {\n    // biome-ignore lint/complexity/useArrowFunction: <explanation>\n    return function (target: any, propertyKey: string): void {\n        target[propertyKey].remove(ids);\n    };\n}\n\nexport {\n    ModifyValue,\n    OverrideDefaultProperties,\n    DefaultValue,\n    DebugPriorities,\n    AddPriority,\n    ScaleByGlobalReelsTimeScale,\n    DefaultAssets,\n    ModifyAssets,\n    RemoveAssets,\n};\n","const enum AssetPriority {\n    HIGHEST = 100,\n    HIGH = 75,\n    NORMAL = 50,\n    LOW = 25,\n    LOWEST = 0,\n}\nexport default AssetPriority;\n","const enum BaseComponents {\n    NONE = 'NONE',\n}\nexport default BaseComponents;\n","const enum BaseFeatures {\n    NONE = 'NONE',\n    CUSTOM_RESULT = 'CUSTOM_RESULT',\n    CUSTOM_REACT = 'CUSTOM_REACT',\n    CUSTOM_SCALER = 'CUSTOM_SCALER',\n}\nexport default BaseFeatures;\n","enum ErrorTypes {\n    CONNECTION_ERROR = 1,\n    GAME_ERROR = 2,\n    GAME_LOCK_ERROR = 3,\n    BROWSER_NOT_SUPPORTED_ERROR = 4,\n    API_ERROR = 5,\n    JS_ERROR = 6,\n    SOCKET_ERROR = 7,\n    LOBBY_ERROR = 8,\n    MAINTENANCE = 9,\n    CONFIRMATION = 10,\n}\n\nexport default ErrorTypes;\n","enum FeatureFlagGroups {\n    SERVER = 'SERVER',\n    JURISDICTION = 'JURISDICTION',\n    CLIENT = 'CLIENT',\n}\n\nexport default FeatureFlagGroups;\n","export enum FeatureFlags {\n    /** Feature Flags */\n    ALLOW_GAMBLE = 'ALLOW_GAMBLE',\n    ALLOW_TOURNAMENTS = 'ALLOW_TOURNAMENTS',\n    ALLOW_PRIZE_POPS = 'ALLOW_PRIZE_POPS',\n    ALLOW_GIFT_SPINS = 'ALLOW_GIFT_SPINS',\n    ALLOW_BRANDING = 'ALLOW_BRANDING',\n    ALLOW_AUTOPLAY_POPUP = 'ALLOW_AUTOPLAY_POPUP',\n    ALLOW_DENOMINATION_POPUP = 'ALLOW_DENOMINATION_POPUP',\n    ALLOW_CUSTOM = 'ALLOW_CUSTOM',\n    USE_TONE_JS = 'USE_TONE_JS',\n    USE_PIXI_7 = 'USE_PIXI_7',\n    USE_IOS_HAND_CURSOR = 'USE_IOS_HAND_CURSOR',\n    USE_ONE_DENOM = 'USE_ONE_DENOM',\n    USE_LEGACY_CUSTOM = 'USE_LEGACY_CUSTOM',\n\n    /** legacy feature flags*/\n    USE_DEFAULT_BET_ON_LOAD = 'USE_DEFAULT_BET_ON_LOAD',\n    USE_PAYTABLE_ON_LOAD = 'USE_PAYTABLE_ON_LOAD',\n    USE_NUMERIC_AUTOPLAY = 'USE_NUMERIC_AUTOPLAY',\n    USE_AUTOPLAY = 'USE_AUTOPLAY',\n    USE_SA_FEATURE = 'USE_SA_FEATURE',\n\n    /**legacy restriction flags*/\n    HIDE_HOLD_AND_PLAY = 'HIDE_HOLD_AND_PLAY',\n    HIDE_JACKPOT = 'HIDE_JACKPOT',\n    HIDE_BUY_BONUS = 'HIDE_BUY_BONUS',\n    HIDE_DOUBLE_CHANCE = 'HIDE_DOUBLE_CHANCE',\n}\n","enum Language {\n    EN = 'en',\n    BG = 'bg',\n    DE = 'de',\n    SR = 'sr',\n    RU = 'ru',\n    ES = 'es',\n    FR = 'fr',\n    HU = 'hu',\n    KA = 'ka',\n    NL = 'nl',\n    RO = 'ro',\n    EL = 'el',\n    HR = 'hr',\n    ES_CO = 'es-co',\n    PT = 'pt',\n    IT = 'it',\n    SK = 'sk',\n    CS = 'cs',\n    UK = 'uk',\n    ZH_CN = 'zh-cn',\n    TR = 'tr',\n    SQ = 'sq',\n    MK = 'mk',\n    SV = 'sv',\n    ET = 'et',\n    LT = 'lt',\n    LV = 'lv',\n    PT_BR = 'pt-br',\n    KO = 'ko',\n    PL = 'pl',\n    SL = 'sl',\n    DA = 'da',\n}\n\nexport default Language;\n","const enum LifeCycle {\n    ON_ALL_ASSETS_LOADED = 'onAllAssetsLoaded',\n    ON_GAME_CONFIGURATION_CREATED = 'onGameConfigurationCreated',\n    ON_AFTER_GAME_CONFIGURATION_CREATED = 'onAfterGameConfigurationCreated',\n    ON_HIGHEST_PRIORITY_GROUP_LOADED = 'onHighestPriorityGroupLoaded',\n    ON_PRIORITY_GROUP_LOADED = 'onPriorityGroupLoaded',\n    ON_ASSET_LOADED = 'onIndividualAssetLoaded',\n    ON_GAME_SETTINGS = 'onGameSettings',\n    ON_REGISTER_DEPENDENCIES = 'onRegisterDependencies',\n    ON_REGISTER_MOBILE_DEPENDENCIES = 'onRegisterMobileDependencies',\n    ON_REGISTER_DESKTOP_DEPENDENCIES = 'onRegisterDesktopDependencies',\n    ON_BEFORE_RESOLVE_DEPENDENCIES = 'onBeforeResolveDependencies',\n    ON_RESOLVE_DEPENDENCIES = 'onResolveDependencies',\n    ON_PREPARE_RESOURCES = 'onPrepareResources',\n    ON_INIT = 'onInit',\n    ON_INIT_COMPLETE = 'onInitComplete',\n    ON_INITIAL_RENDER = 'onInitialRender',\n    ON_AFTER_INITIAL_RENDER = 'onAfterInitialRender',\n    ON_BEFORE_DESTROY = 'onBeforeDestroy',\n    ON_BEFORE_START_LOADING_RESOURCES = 'onBeforeStartLoadingResources',\n    ON_DESTROY = 'destroy',\n    ON_START_GAME = 'onGameStarted',\n}\nexport default LifeCycle;\n","const enum LobbyOpenType {\n    GENERAL = 'general',\n    IN_GAME = 'inGame',\n    FULLSCREEN = 'fullScreen',\n    OPERATOR = 'operator',\n}\nexport default LobbyOpenType;\n","const enum LobbyStyle {\n    SIMPLE = 'simple',\n    COMPLEX = 'complex',\n}\n\nexport default LobbyStyle;\n","export enum LoggerGroups {\n    INIT = 'Game Init',\n    IDLE = 'Game Idle',\n    ROUND = 'Game Round',\n    FREE_SPINS = 'Game FreeSpins',\n}\n","// Import from the leaf file, NOT the '@egt/core' barrel: this module is reachable from\n// FeatureFlagsStore during `new Core()`, while the barrel is still mid-evaluation.\nimport { FeatureFlags } from './FeatureFlags';\n\nenum RestrictionType {\n    PAYTABLE_ON_LOAD = 'paytableOnload',\n    DEFAULT_BET_ON_LOAD = 'defaultBetOnLoad',\n    DISABLE_HOLD_AND_PLAY = 'disableHoldAndPlay',\n    NO_JACKPOT = 'noJackpot',\n    HIDE_BUY_BONUS = 'hideBuyBonus',\n    NO_DOUBLE_CHANCE = 'noDoubleChance',\n    SA_FEATURE = 'saFeature',\n    USE_NUMERIC_AUTOPLAY = 'useNumericAutoplay',\n    USE_AUTOPLAY = 'useAutoplay',\n}\n\n/**\n * Flag identifier → the jurisdiction-restriction string it was derived from.\n *\n * The two enums do NOT share key names — `HIDE_JACKPOT` came from `NO_JACKPOT`,\n * `HIDE_DOUBLE_CHANCE` from `NO_DOUBLE_CHANCE`, `USE_SA_FEATURE` from `SA_FEATURE`,\n * `HIDE_HOLD_AND_PLAY` from `DISABLE_HOLD_AND_PLAY` — so indexing one enum with the other's key\n * silently yields `undefined` for exactly the flags that matter. This explicit map is the only\n * supported bridge; add an entry here when a flag gains a restriction origin.\n *\n * Consumed by `PaytableHTMLView.applyRestrictions`, which matches `restriction:<value>` markers\n * embedded in the paytable HTML.\n */\nexport const RESTRICTION_TYPE_BY_FEATURE_FLAG: Partial<Record<FeatureFlags, RestrictionType>> = {\n    [FeatureFlags.USE_PAYTABLE_ON_LOAD]: RestrictionType.PAYTABLE_ON_LOAD,\n    [FeatureFlags.USE_DEFAULT_BET_ON_LOAD]: RestrictionType.DEFAULT_BET_ON_LOAD,\n    [FeatureFlags.HIDE_HOLD_AND_PLAY]: RestrictionType.DISABLE_HOLD_AND_PLAY,\n    [FeatureFlags.HIDE_JACKPOT]: RestrictionType.NO_JACKPOT,\n    [FeatureFlags.HIDE_BUY_BONUS]: RestrictionType.HIDE_BUY_BONUS,\n    [FeatureFlags.HIDE_DOUBLE_CHANCE]: RestrictionType.NO_DOUBLE_CHANCE,\n    [FeatureFlags.USE_SA_FEATURE]: RestrictionType.SA_FEATURE,\n    [FeatureFlags.USE_NUMERIC_AUTOPLAY]: RestrictionType.USE_NUMERIC_AUTOPLAY,\n    [FeatureFlags.USE_AUTOPLAY]: RestrictionType.USE_AUTOPLAY,\n};\n\nexport default RestrictionType;\n","enum VideoTypes {\n    SYMBOL_ANIMATION = 1,\n    DROP_ANIMATION = 2,\n    ANTICIPATION = 3,\n    EXPLODE = 4,\n    CUSTOM = 5,\n    REPLACE = 6,\n}\n\nexport default VideoTypes;\n","/*\n Dev-only helper to visualize aggregated session metrics from SessionMetricsCollector.\n Usage:\n - Prefer attaching from DeveloperTools when URL contains mtericsDebug=true\n - Or manually from DevTools console: window.MetricsDebugPanel.attach()\n*/\n\nimport SessionMetricsCollector from './SessionMetricsCollector';\n\ninterface PanelOptions {\n    position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';\n    refreshMs?: number;\n}\n\nexport class MetricsDebugPanel {\n    private static _instance: MetricsDebugPanel | null = null;\n\n    private readonly container: HTMLDivElement;\n    private readonly header: HTMLDivElement;\n    private readonly body: HTMLDivElement;\n    private readonly footer: HTMLDivElement;\n    private readonly summary: HTMLDivElement;\n    private readonly pre: HTMLPreElement;\n    private readonly collector: SessionMetricsCollector;\n    private intervalId: number | null = null;\n    private refreshMs: number;\n    // Drag/Resize state\n    private isDragging: boolean = false;\n    private isResizing: boolean = false;\n    private dragOffsetX: number = 0;\n    private dragOffsetY: number = 0;\n    private startMouseX: number = 0;\n    private startMouseY: number = 0;\n    private startWidth: number = 0;\n    private startHeight: number = 0;\n    private resizer!: HTMLDivElement;\n    private readonly MIN_WIDTH = 280;\n    private readonly MIN_HEIGHT = 160;\n    private boundDragMove = (e: MouseEvent) => this.onDrag(e);\n    private boundDragEnd = (_e: MouseEvent) => this.onDragEnd();\n    private boundResizeMove = (e: MouseEvent) => this.onResize(e);\n    private boundResizeEnd = (_e: MouseEvent) => this.onResizeEnd();\n\n    static attach(options?: PanelOptions): MetricsDebugPanel {\n        if (!MetricsDebugPanel._instance) {\n            MetricsDebugPanel._instance = new MetricsDebugPanel(options);\n        }\n        return MetricsDebugPanel._instance;\n    }\n\n    static destroy(): void {\n        MetricsDebugPanel._instance?.destroy();\n        MetricsDebugPanel._instance = null;\n    }\n\n    private constructor(options?: PanelOptions) {\n        this.collector = SessionMetricsCollector.getInstance();\n        this.refreshMs = Math.max(500, options?.refreshMs ?? 2000);\n\n        this.container = document.createElement('div');\n        this.container.className = 'metrics-debug-panel';\n\n        this.header = document.createElement('div');\n        this.header.className = 'metrics-debug-header';\n        this.header.innerText = 'Session Metrics Debug';\n\n        const btns = document.createElement('div');\n        btns.className = 'metrics-debug-actions';\n        const refreshBtn = this.createButton('Refresh', () => this.update());\n        const autoBtn = this.createButton('Auto: On', () => this.toggleAuto(autoBtn));\n        const flushBtn = this.createButton('Force Flush', () => this.forceFlush());\n        const copyBtn = this.createButton('Copy JSON', () => this.copyJSON());\n        const minimizeBtn = this.createButton('Minimize', () => this.toggleMinimize(minimizeBtn));\n        btns.appendChild(refreshBtn);\n        btns.appendChild(autoBtn);\n        btns.appendChild(flushBtn);\n        btns.appendChild(copyBtn);\n        btns.appendChild(minimizeBtn);\n\n        this.body = document.createElement('div');\n        this.body.className = 'metrics-debug-body';\n\n        // Live summary block (avg reel stop times, etc.)\n        this.summary = document.createElement('div');\n        this.summary.className = 'metrics-debug-summary';\n        Object.assign(this.summary.style, {\n            marginBottom: '8px',\n            padding: '6px 8px',\n            background: 'rgba(255,255,255,0.06)',\n            borderRadius: '6px',\n        } as Partial<CSSStyleDeclaration>);\n        this.body.appendChild(this.summary);\n\n        this.pre = document.createElement('pre');\n        this.pre.className = 'metrics-debug-pre';\n        this.body.appendChild(this.pre);\n\n        this.footer = document.createElement('div');\n        this.footer.className = 'metrics-debug-footer';\n        this.footer.innerText = 'Collector aggregates spins and events; one Sentry message per session (+beacon).';\n\n        this.container.appendChild(this.header);\n        this.container.appendChild(btns);\n        this.container.appendChild(this.body);\n        this.container.appendChild(this.footer);\n\n        document.body.appendChild(this.container);\n        this.applyStyles(options?.position ?? 'bottom-right');\n\n        // Enable drag + resize interactions\n        this.setupDragAndResize();\n\n        // Start auto update\n        this.intervalId = window.setInterval(() => this.update(), this.refreshMs);\n        this.update();\n        // Expose globally for convenience\n        (window as any).MetricsDebugPanel = MetricsDebugPanel;\n    }\n\n    private createButton(label: string, onClick: () => void): HTMLButtonElement {\n        const btn = document.createElement('button');\n        btn.type = 'button';\n        btn.className = 'metrics-debug-btn';\n        btn.innerText = label;\n        btn.addEventListener('click', onClick);\n        return btn;\n    }\n\n    private toggleAuto(btn: HTMLButtonElement) {\n        if (this.intervalId) {\n            window.clearInterval(this.intervalId);\n            this.intervalId = null;\n            btn.innerText = 'Auto: Off';\n        } else {\n            this.intervalId = window.setInterval(() => this.update(), this.refreshMs);\n            btn.innerText = 'Auto: On';\n        }\n    }\n\n    private toggleMinimize(btn: HTMLButtonElement) {\n        const minimized = this.body.style.display === 'none';\n        if (minimized) {\n            this.body.style.display = 'block';\n            this.footer.style.display = 'block';\n            btn.innerText = 'Minimize';\n        } else {\n            this.body.style.display = 'none';\n            this.footer.style.display = 'none';\n            btn.innerText = 'Expand';\n        }\n    }\n\n    private async copyJSON() {\n        try {\n            const data = this.collector.getCurrentMetrics();\n            await navigator.clipboard.writeText(JSON.stringify(data, null, 2));\n            this.toast('Copied metrics JSON');\n        } catch {\n            this.toast('Copy failed');\n        }\n    }\n\n    private forceFlush() {\n        try {\n            this.collector.forceFlush();\n            this.toast('Flushed metrics');\n            this.update();\n        } catch {\n            this.toast('Flush failed');\n        }\n    }\n\n    public update() {\n        try {\n            const metrics = this.collector.getCurrentMetrics();\n            const round = (metrics as any)?.egt?.round || {};\n            const fmt = (v: any) => (typeof v === 'number' && isFinite(v) ? Math.round(v) : 0);\n            this.summary.textContent =\n                `Avg Reel Stop [ms] — normal: ${fmt(round.avgReelStopTimeInNormalSpin)}, ` +\n                `quick: ${fmt(round.avgReelStopTimeInQuickSpin)}, ` +\n                `turbo: ${fmt(round.avgReelStopTimeInTurboSpin)}`;\n            const nowIso = new Date().toISOString();\n            this.pre.textContent = JSON.stringify(\n                {\n                    at: nowIso,\n                    ...metrics,\n                },\n                null,\n                2,\n            );\n        } catch (e: any) {\n            this.pre.textContent = `Error rendering metrics: ${e?.message ?? e}`;\n        }\n    }\n\n    // ---------- Drag & Resize ----------\n    private setupDragAndResize() {\n        // Draggable by header\n        this.header.style.cursor = 'move';\n        this.header.addEventListener('mousedown', (e) => this.onDragStart(e));\n\n        // Resizer handle (bottom-right)\n        this.resizer = document.createElement('div');\n        this.resizer.className = 'metrics-debug-resizer';\n        Object.assign(this.resizer.style, {\n            position: 'absolute',\n            width: '12px',\n            height: '12px',\n            right: '2px',\n            bottom: '2px',\n            cursor: 'se-resize',\n            background: 'transparent',\n        } as Partial<CSSStyleDeclaration>);\n        this.resizer.addEventListener('mousedown', (e) => this.onResizeStart(e));\n        this.container.appendChild(this.resizer);\n    }\n\n    private ensureFreePositioning() {\n        // Convert from preset (bottom/right etc.) to absolute top/left for free dragging\n        const rect = this.container.getBoundingClientRect();\n        this.container.style.left = `${Math.max(0, rect.left)}px`;\n        this.container.style.top = `${Math.max(0, rect.top)}px`;\n        this.container.style.right = 'auto';\n        this.container.style.bottom = 'auto';\n    }\n\n    private onDragStart(e: MouseEvent) {\n        // Ignore right-click or if starting on a button\n        if (e.button !== 0) return;\n        this.ensureFreePositioning();\n        const rect = this.container.getBoundingClientRect();\n        this.dragOffsetX = e.clientX - rect.left;\n        this.dragOffsetY = e.clientY - rect.top;\n        this.isDragging = true;\n        window.addEventListener('mousemove', this.boundDragMove);\n        window.addEventListener('mouseup', this.boundDragEnd, { once: true });\n        e.preventDefault();\n    }\n\n    private onDrag(e: MouseEvent) {\n        if (!this.isDragging) return;\n        const vw = window.innerWidth;\n        const vh = window.innerHeight;\n        const w = this.container.offsetWidth;\n        const h = this.container.offsetHeight;\n        let left = e.clientX - this.dragOffsetX;\n        let top = e.clientY - this.dragOffsetY;\n        // Constrain within viewport\n        left = Math.min(Math.max(0, left), Math.max(0, vw - w));\n        top = Math.min(Math.max(0, top), Math.max(0, vh - h));\n        this.container.style.left = `${left}px`;\n        this.container.style.top = `${top}px`;\n    }\n\n    private onDragEnd() {\n        this.isDragging = false;\n        window.removeEventListener('mousemove', this.boundDragMove);\n    }\n\n    private onResizeStart(e: MouseEvent) {\n        if (e.button !== 0) return;\n        this.ensureFreePositioning();\n        const rect = this.container.getBoundingClientRect();\n        this.startWidth = rect.width;\n        this.startHeight = rect.height;\n        this.startMouseX = e.clientX;\n        this.startMouseY = e.clientY;\n        this.isResizing = true;\n        // Allow larger resizes than default maxHeight\n        this.container.style.maxHeight = '80vh';\n        window.addEventListener('mousemove', this.boundResizeMove);\n        window.addEventListener('mouseup', this.boundResizeEnd, { once: true });\n        e.preventDefault();\n    }\n\n    private onResize(e: MouseEvent) {\n        if (!this.isResizing) return;\n        const dx = e.clientX - this.startMouseX;\n        const dy = e.clientY - this.startMouseY;\n        const newW = Math.max(this.MIN_WIDTH, this.startWidth + dx);\n        const newH = Math.max(this.MIN_HEIGHT, this.startHeight + dy);\n        this.container.style.width = `${newW}px`;\n        this.container.style.height = `${newH}px`;\n    }\n\n    private onResizeEnd() {\n        this.isResizing = false;\n        window.removeEventListener('mousemove', this.boundResizeMove);\n    }\n\n    public destroy() {\n        if (this.intervalId) {\n            window.clearInterval(this.intervalId);\n            this.intervalId = null;\n        }\n        this.container.remove();\n    }\n\n    private toast(msg: string) {\n        const el = document.createElement('div');\n        el.className = 'metrics-debug-toast';\n        el.innerText = msg;\n        document.body.appendChild(el);\n        setTimeout(() => {\n            el.remove();\n        }, 1600);\n    }\n\n    private applyStyles(position: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right') {\n        const base: Partial<CSSStyleDeclaration> = {\n            position: 'fixed',\n            zIndex: '2147483647',\n            maxHeight: '50vh',\n            width: '340px',\n            background: 'rgba(0,0,0,0.8)',\n            color: '#e5e5e5',\n            fontFamily:\n                'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace',\n            fontSize: '12px',\n            borderRadius: '8px',\n            boxShadow: '0 2px 12px rgba(0,0,0,0.45)',\n            overflow: 'hidden',\n        };\n        switch (position) {\n            case 'top-left':\n                base.top = '12px';\n                base.left = '12px';\n                break;\n            case 'top-right':\n                base.top = '12px';\n                base.right = '12px';\n                break;\n            case 'bottom-left':\n                base.bottom = '12px';\n                base.left = '12px';\n                break;\n            case 'bottom-right':\n                base.bottom = '12px';\n                base.right = '12px';\n                break;\n        }\n        Object.assign(this.container.style, base);\n\n        Object.assign(this.header.style, {\n            padding: '8px 10px',\n            fontWeight: 'bold',\n            background: 'rgba(255,255,255,0.08)',\n            borderBottom: '1px solid rgba(255,255,255,0.12)',\n        } as Partial<CSSStyleDeclaration>);\n\n        Object.assign(this.body.style, {\n            padding: '8px 10px',\n            overflow: 'auto',\n        } as Partial<CSSStyleDeclaration>);\n\n        Object.assign(this.footer.style, {\n            padding: '6px 10px',\n            fontSize: '11px',\n            opacity: '0.8',\n            borderTop: '1px solid rgba(255,255,255,0.12)',\n        } as Partial<CSSStyleDeclaration>);\n\n        const styleBtn: Partial<CSSStyleDeclaration> = {\n            background: '#2c7be5',\n            color: 'white',\n            border: 'none',\n            borderRadius: '4px',\n            padding: '4px 8px',\n            marginRight: '6px',\n            cursor: 'pointer',\n        };\n        const actions = this.container.querySelectorAll('.metrics-debug-btn');\n        actions.forEach((btn) => Object.assign((btn as HTMLElement).style, styleBtn));\n\n        const actionsWrap = this.container.querySelector('.metrics-debug-actions') as HTMLDivElement;\n        if (actionsWrap) {\n            Object.assign(actionsWrap.style, {\n                display: 'flex',\n                padding: '6px 10px',\n                alignItems: 'center',\n                gap: '6px',\n                borderBottom: '1px solid rgba(255,255,255,0.12)',\n            } as Partial<CSSStyleDeclaration>);\n        }\n\n        Object.assign(this.pre.style, {\n            margin: '0',\n            whiteSpace: 'pre-wrap',\n            wordBreak: 'break-word',\n        } as Partial<CSSStyleDeclaration>);\n\n        // Toast styles\n        const css = document.createElement('style');\n        css.textContent = `\n      .metrics-debug-toast {\n        position: fixed;\n        bottom: 24px;\n        right: 24px;\n        color: #fff;\n        padding: 8px 12px;\n        border-radius: 4px;\n        z-index: 2147483647;\n        box-shadow: 0 2px 12px rgba(0,0,0,0.45);\n        font-size: 12px;\n      }\n    `;\n        document.head.appendChild(css);\n    }\n}\n\nexport default MetricsDebugPanel;\n","import * as Sentry from '@sentry/browser';\nimport Core from '@egt/core';\nimport { SENTRY_DATA, SentryTransactionTypes } from '../sentry/sentry-utils';\nimport { startStandaloneSentrySpan } from '../sentry/sentry-utils';\n\nexport type SpinMode = string; // e.g. 'MANUAL_SPIN' | 'AUTO_PLAY' | 'FREE_SPINS' | ...\n\n// Discoverable list of supported user actions. The collector accepts any string key,\n// but using this enum makes it easy to see what is commonly tracked.\nexport enum UserActionType {\n    SoundToggled = 'soundToggled',\n    MusicToggled = 'musicToggled',\n    SettingsOpened = 'settingsOpened',\n    HomeClicked = 'homeClicked',\n    AutoplayUsed = 'autoplayUsed',\n    SpeedModeUsed = 'speedModeUsed',\n    JackpotStatisticsUsed = 'jackpotStatisticsUsed',\n    HelpOpened = 'helpOpened',\n}\n\ninterface OrientationCounts {\n    portrait: number;\n    landscape: number;\n    desktop: number;\n}\n\ninterface UserActionsCounters {\n    soundToggled: number;\n    musicToggled: number;\n    settingsOpened: number;\n    homeClicked: number;\n    autoplayUsed: number;\n    speedModeUsed: number;\n    jackpotStatisticsUsed: number;\n    helpOpened: number;\n}\n\ninterface AggregatedMetrics {\n    egt: {\n        round: {\n            spins: number;\n            modes: Record<SpinMode, number>;\n            orientation: OrientationCounts;\n            avgIdleTime: number; // ms\n            avgServerResponseTime: number; // ms\n            avgReelStopTimeInNormalSpin: number; // ms\n            avgReelStopTimeInQuickSpin: number; // ms\n            avgReelStopTimeInTurboSpin: number; // ms\n        };\n        userActions: Record<string, number>;\n        events: Record<string, any>;\n        configuration: {\n            currency: string;\n            demo: boolean;\n            gameKey: string;\n            language: string;\n        };\n    };\n}\n\n/**\n * Aggregates session metrics across the whole gameplay and flushes once to Sentry.\n * Singleton usage: SessionMetricsCollector.getInstance()\n */\nexport class SessionMetricsCollector {\n    private static _instance: SessionMetricsCollector | null = null;\n\n    private static readonly SAMPLES_CAP = 50;\n\n    static getInstance(): SessionMetricsCollector {\n        if (!SessionMetricsCollector._instance) {\n            SessionMetricsCollector._instance = new SessionMetricsCollector();\n        }\n        return SessionMetricsCollector._instance;\n    }\n\n    private metrics: AggregatedMetrics;\n\n    private lastSpinStart: number | null = null;\n    private lastSpinEnd: number | null = null;\n    private lastSpinStartedMarkedAt: number | null = null;\n\n    public idleIntervals: number[] = [];\n    private idleSum: number = 0;\n    private idleCount: number = 0;\n    private serverResponseSum: number = 0;\n    private serverResponseCount: number = 0;\n    private reelStopSumNormal: number = 0;\n    private reelStopCountNormal: number = 0;\n    private reelStopSumQuick: number = 0;\n    private reelStopCountQuick: number = 0;\n    private reelStopSumTurbo: number = 0;\n    private reelStopCountTurbo: number = 0;\n    private flushed: boolean = false;\n    private flushing: boolean = false;\n    private constructor() {\n        // Initialize configuration from Core\n        this.metrics = {\n            egt: {\n                round: {\n                    spins: 0,\n                    modes: {},\n                    orientation: { portrait: 0, landscape: 0, desktop: 0 },\n                    avgIdleTime: 0,\n                    avgServerResponseTime: 0,\n                    avgReelStopTimeInNormalSpin: 0,\n                    avgReelStopTimeInQuickSpin: 0,\n                    avgReelStopTimeInTurboSpin: 0,\n                },\n                userActions: {}, // dynamic keys\n                events: {},\n                configuration: {\n                    currency: Core.configuration.currencyCode,\n                    demo: Core.configuration.demo,\n                    gameKey: Core.configuration.gameKey,\n                    language: Core.configuration.language,\n                },\n            },\n        };\n\n        // Auto-flush on pagehide as a safety net\n        try {\n            window.addEventListener('pagehide', () => {\n                this.safeFlush();\n            });\n        } catch {\n            // ignore environment errors\n        }\n    }\n\n    public onSpinStarted(payload: { orientation: string; desktop: boolean; spinMode: SpinMode; spinSpeed?: number }) {\n        const now = performance.now();\n\n        // Guard: avoid double-count if wired from multiple sources within a very short interval\n        if (this.lastSpinStartedMarkedAt !== null && now - this.lastSpinStartedMarkedAt < 30) {\n            return;\n        }\n        this.lastSpinStartedMarkedAt = now;\n\n        // Idle time since previous spin end\n        if (this.lastSpinEnd != null) {\n            const idle = Math.round(now - this.lastSpinEnd);\n            if (isFinite(idle) && idle >= 0) {\n                this.idleSum += idle;\n                this.idleCount += 1;\n                this.pushSample(this.idleIntervals, idle);\n            }\n        }\n\n        this.lastSpinStart = now;\n\n        // Orientation counts (exclusive):\n        // - Desktop: increment only desktop\n        // - Mobile: increment either portrait or landscape depending on current mode\n        const orientationStr = String(payload.orientation).toLowerCase();\n        if (payload.desktop) {\n            this.metrics.egt.round.orientation.desktop += 1;\n        } else if (orientationStr.includes('portrait')) {\n            this.metrics.egt.round.orientation.portrait += 1;\n        } else if (orientationStr.includes('landscape')) {\n            this.metrics.egt.round.orientation.landscape += 1;\n        }\n\n        // Modes and spins\n        this.metrics.egt.round.spins += 1;\n        if (!this.metrics.egt.round.modes[payload.spinMode]) {\n            this.metrics.egt.round.modes[payload.spinMode] = 0;\n        }\n        this.metrics.egt.round.modes[payload.spinMode] += 1;\n    }\n\n    public onReelsStopped(payload: { quickMode: boolean; turboMode: boolean; specialSpinSpeedDisabled?: boolean }) {\n        if (this.lastSpinStart == null) return;\n\n        const now = performance.now();\n        const duration = Math.round(now - this.lastSpinStart);\n        // This is a special case where the spin speed is disabled in Bonus fetures\n        if (payload.specialSpinSpeedDisabled) {\n            this.reelStopSumNormal += duration;\n            this.reelStopCountNormal += 1;\n        } else {\n            if (payload.turboMode) {\n                this.reelStopSumTurbo += duration;\n                this.reelStopCountTurbo += 1;\n            } else if (payload.quickMode) {\n                this.reelStopSumQuick += duration;\n                this.reelStopCountQuick += 1;\n            } else {\n                this.reelStopSumNormal += duration;\n                this.reelStopCountNormal += 1;\n            }\n        }\n\n        this.lastSpinEnd = now;\n    }\n\n    public recordServerResponseTime(ms: number, eventName?: string) {\n        if (eventName && eventName !== 'bet') return;\n        if (isFinite(ms) && ms >= 0) {\n            const v = Math.round(ms);\n            this.serverResponseSum += v;\n            this.serverResponseCount += 1;\n            // this.pushSample(this.serverResponseTimes, v);\n        }\n    }\n\n    public incrementUserAction(action: string) {\n        const key = String(action);\n        const current = this.metrics.egt.userActions[key] || 0;\n        this.metrics.egt.userActions[key] = current + 1;\n    }\n\n    public incrementAction(action: keyof UserActionsCounters) {\n        // Backward compatibility wrapper\n        this.incrementUserAction(String(action));\n    }\n\n    public recordEvent(name: string, value: any = true) {\n        const prev = this.metrics.egt.events[name];\n        if (typeof prev === 'number' && typeof value === 'number') {\n            this.metrics.egt.events[name] = prev + value;\n        } else if (prev === undefined) {\n            this.metrics.egt.events[name] = value;\n        } else {\n            // Keep last value and also track count\n            const countKey = `${name}.__count`;\n            this.metrics.egt.events[name] = value;\n            this.metrics.egt.events[countKey] = (this.metrics.egt.events[countKey] || 0) + 1;\n        }\n    }\n\n    private pushSample(arr: number[], v: number) {\n        arr.push(v);\n        if (arr.length > SessionMetricsCollector.SAMPLES_CAP) arr.shift();\n    }\n\n    private computeAverages() {\n        this.metrics.egt.round.avgIdleTime = this.idleCount ? Math.round(this.idleSum / this.idleCount) : 0;\n        this.metrics.egt.round.avgServerResponseTime = this.serverResponseCount\n            ? Math.round(this.serverResponseSum / this.serverResponseCount)\n            : 0;\n        this.metrics.egt.round.avgReelStopTimeInNormalSpin = this.reelStopCountNormal\n            ? Math.round(this.reelStopSumNormal / this.reelStopCountNormal)\n            : 0;\n        this.metrics.egt.round.avgReelStopTimeInQuickSpin = this.reelStopCountQuick\n            ? Math.round(this.reelStopSumQuick / this.reelStopCountQuick)\n            : 0;\n        this.metrics.egt.round.avgReelStopTimeInTurboSpin = this.reelStopCountTurbo\n            ? Math.round(this.reelStopSumTurbo / this.reelStopCountTurbo)\n            : 0;\n    }\n\n    public getCurrentMetrics(): AggregatedMetrics {\n        this.computeAverages();\n        return JSON.parse(JSON.stringify(this.metrics));\n    }\n\n    public forceFlush() {\n        this.safeFlush();\n    }\n\n    public flush() {\n        if (this.flushed || this.flushing) return;\n        if (!Core.sentryClient) return;\n\n        this.flushing = true;\n        this.computeAverages();\n        const span = startStandaloneSentrySpan(Core.sentryClient, SentryTransactionTypes.GAME_SESSION);\n        if (!span) {\n            this.flushing = false;\n            return;\n        }\n\n        // Tags / attributes\n        try {\n            const { configuration, round, userActions, events } = this.metrics.egt;\n\n            // Configuration\n            span.setAttribute(SENTRY_DATA.CONFIGURATIONS.CURRENCY, configuration.currency);\n            span.setAttribute(SENTRY_DATA.CONFIGURATIONS.DEMO, configuration.demo);\n            span.setAttribute(SENTRY_DATA.CONFIGURATIONS.GAME_KEY, configuration.gameKey);\n            span.setAttribute(SENTRY_DATA.CONFIGURATIONS.LANGUAGE, configuration.language);\n\n            // Modes\n            Object.keys(round.modes).forEach((mode) => {\n                span.setAttribute(`${SENTRY_DATA.ROUND.MODES}.${mode}`, round.modes[mode]);\n            });\n\n            // Orientation aggregated counts\n            span.setAttribute(`${SENTRY_DATA.ROUND.ORIENTATION}.portrait`, round.orientation.portrait);\n            span.setAttribute(`${SENTRY_DATA.ROUND.ORIENTATION}.landscape`, round.orientation.landscape);\n            span.setAttribute(`${SENTRY_DATA.ROUND.ORIENTATION}.desktop`, round.orientation.desktop);\n\n            // User actions (dynamic keys)\n            Object.keys(userActions).forEach((k) => {\n                const val = userActions[k];\n                if (typeof val === 'number') {\n                    span.setAttribute(`egt.userActions.${k}`, val);\n                }\n            });\n\n            // Custom events (flatten primitives only)\n            Object.keys(events).forEach((k) => {\n                const val = events[k];\n                if (['string', 'number', 'boolean'].includes(typeof val)) {\n                    span.setAttribute(`${SENTRY_DATA.EVENTS}.${k}`, val as any);\n                }\n            });\n\n            // Measurements\n            Sentry.setMeasurement(SENTRY_DATA.ROUND.SPINS, round.spins, 'count', span);\n            Sentry.setMeasurement(SENTRY_DATA.ROUND.AVG_IDLE_TIME, round.avgIdleTime, 'millisecond', span);\n            Sentry.setMeasurement(\n                SENTRY_DATA.ROUND.AVG_SERVER_RESPONSE_TIME,\n                round.avgServerResponseTime,\n                'millisecond',\n                span,\n            );\n            Sentry.setMeasurement(\n                SENTRY_DATA.ROUND.AVG_REEL_STOP_NORMAL,\n                round.avgReelStopTimeInNormalSpin,\n                'millisecond',\n                span,\n            );\n            Sentry.setMeasurement(\n                SENTRY_DATA.ROUND.AVG_REEL_STOP_QUICK,\n                round.avgReelStopTimeInQuickSpin,\n                'millisecond',\n                span,\n            );\n            Sentry.setMeasurement(\n                SENTRY_DATA.ROUND.AVG_REEL_STOP_TURBO,\n                round.avgReelStopTimeInTurboSpin,\n                'millisecond',\n                span,\n            );\n        } catch (_e) {\n            // no-op\n        }\n\n        span.setStatus({ code: 1 });\n        span.end();\n        this.flushed = true;\n        this.flushing = false;\n    }\n\n    public safeFlush() {\n        try {\n            this.flush();\n            Sentry.flush(0);\n        } catch {\n            /* noop */\n        }\n    }\n}\n\nexport default SessionMetricsCollector;\n","import { take } from 'rxjs/operators';\nimport { injectable, singleton } from 'tsyringe';\nimport Core, { ErrorTypes, IConnectable, IErrorData, Log, Timers } from '../Core';\nimport RestrictionType from '../enums/RestrictionType';\nimport { ReplayerRoundType } from './types/ReplayerTypes';\n\n@injectable()\n@singleton()\nexport default class ReplayerSocket implements IConnectable {\n    public replayKey: any;\n    public data: any;\n    public roundsData: any = [];\n    public roundsIndex: number = -1;\n    public roundsSettings: any;\n\n    // dev: &replayHost=https://replay-service-ong-dev.egt-ong.com/replayservice/\n    // qa:  &replayHost=https://replays-ong-qa-ext.egt-ong.com/replayservice/\n    public replayHost = window['ssi']?.replayHost;\n    public urlData: string;\n    public urlReplay: string;\n    // public readonly replayHost = window['ssi']?.replayHost\n    //     ? window['ssi'].replayHost\n    //     : new URLSearchParams(window.location.search).get('qa') !== 'true'\n    //       ? 'https://replay-service-ong-dev.egt-ong.com/replayservice/'\n    //       : 'https://replays-ong-qa-ext.egt-ong.com/replayservice/';\n    // public readonly urlData = `${this.replayHost}api/match?replayKey=`;\n    // public readonly urlReplay = `${this.replayHost}replay?replayKey=`;\n\n    public replayer: any;\n\n    constructor() {\n        this.replayHost = Core.configuration.replayHost;\n        this.urlData = `${this.replayHost}api/match?replayKey=`;\n        this.urlReplay = `${this.replayHost}replay?replayKey=`;\n\n        Core.EXIT_APPLICATION.subscribe(this.onExitApplication.bind(this));\n        Timers.setTimeout(() => {\n            this.getData().then(() => {\n                if (this.gameHasUnsupportedCommands()) {\n                    this.showError('replayer.error.unsupportedGameReplay');\n                } else {\n                    Core.configuration.gameKey = this.data.gameKey;\n                    this.onopen({ connectionStatus: 'opened', message: 'succeeds' });\n                }\n            });\n        }, 20);\n    }\n\n    public onopen(conn): void {\n        Log.debug('***onopen', conn);\n    }\n\n    public onmessage(e): void {\n        //\n        Log.debug('***onmessage', e);\n    }\n\n    public onclose(e): void {\n        //\n        Log.debug('***onclose', e);\n    }\n\n    public onerror(e): void {\n        //\n        Log.debug('***onerror', e);\n    }\n\n    public close(code: number, reason: string): void {\n        //\n        Log.debug('***close', code, reason);\n    }\n\n    public send(requestString: any): void {\n        // Log.debug('***send', requestString);\n        const request = JSON.parse(requestString);\n        // Log.debug('send', requestObj);\n        switch (request.event) {\n            case 'loadGame':\n                Core.ON_GAME_LOADED.pipe(take(1)).subscribe(() => {\n                    Timers.setTimeout(() => {\n                        this.loadTranslations();\n                    }, 500);\n                });\n                this.simulateLoadGame();\n                break;\n            default:\n                this.replayer.send(requestString);\n        }\n    }\n\n    protected loadTranslations(): void {\n        let json;\n        try {\n            json = require(`./translations/${Core.translator.currentLanguage.toLowerCase()}.json`);\n        } catch (e: any) {\n            Log.error(\n                `Translations not found: ${Core.translator.currentLanguage.toLowerCase()}`,\n                this.constructor.name,\n                e,\n            );\n            json = require(`./translations/en.json`);\n        }\n        if (json) {\n            Core.translator.addKeysTo(Core.translator.currentLanguage.toLowerCase(), json);\n        }\n    }\n\n    protected simulateLoadGame(): void {\n        Core.configuration.demo = false;\n        const data: any = {\n            referenceId: 1,\n            gameKey: this.data.gameKey,\n            event: 'loadGame',\n            balance: {\n                balance: this.roundsSettings.balance.balance,\n                units: this.roundsSettings.balance.units,\n                currency: this.roundsSettings.balance.currency,\n            },\n            game: {\n                state: {\n                    bet: {\n                        level: this.roundsSettings.settings.matchBet.level,\n                        factor: this.roundsSettings.settings.matchBet.matchFactor,\n                        denomination: this.roundsSettings.settings.matchBet.denomination,\n                        lines: this.data.lines,\n                    },\n                    limitOverflow:\n                        // this.roundsSettings.limitOverflow ||\n                        Boolean(this.roundsData.find((r) => r.type === ReplayerRoundType.OVERFLOW_WIN)),\n                    gambles: 0,\n                },\n            },\n            state: 'idle',\n            settings: this.roundsSettings.settings,\n            context: {},\n            jackpotStats: this.roundsSettings.jackpotStats,\n        };\n\n        const response = {\n            type: 'message',\n            data: JSON.stringify(data),\n        };\n        this.onmessage(response);\n    }\n\n    protected getData(): Promise<any> {\n        this.replayKey = new URLSearchParams(window.location.search).get('replayKey');\n        const url = `${this.urlData}${this.replayKey}`;\n        const request = Core.requestManager.get(url, '');\n        request\n            .then((data) => {\n                this.data = data.data;\n                this.roundsData = JSON.parse(this.data.roundsData);\n                if (typeof this.data.gameSettings === 'string') {\n                    this.roundsSettings = JSON.parse(this.data.gameSettings);\n                } else {\n                    this.roundsSettings = this.data.gameSettings;\n                }\n                Core.gamePortalExchangeObject = {};\n                Core.gamePortalExchangeObject.matchId = this.data.matchId;\n                this.data.matchId = 'REPLAYER';\n                // TO DO: this is new record and in order to be compatible with the old\n                // we create it manually if it is not exists\n                this.roundsSettings.settings.clientSettings = this.roundsSettings.settings.clientSettings || {};\n                if (this.data.branding) {\n                    this.roundsSettings.settings.clientSettings.branding = this.data.branding;\n                }\n                if (this.data.customGameName) {\n                    this.roundsSettings.settings.clientSettings.customName = this.data.customGameName;\n                }\n                if (this.data.maxBetLimits) {\n                    this.roundsSettings.settings.clientSettings.maxBetLimits = this.data.maxBetLimits;\n                }\n                this.roundsSettings.settings.gameModes = this.data.gameModes || [];\n                // this.roundsSettings.settings.gameModes = [\n                //     {\n                //         gameMode: 'NORMAL_MODE',\n                //         factor: 20,\n                //         lines: 0,\n                //     },\n                //     {\n                //         gameMode: 'DOUBLE_CHANCE',\n                //         factor: 25,\n                //         lines: 0,\n                //     },\n                //     {\n                //         gameMode: 'BUY_BONUS',\n                //         factor: 2000,\n                //         lines: 0,\n                //     },\n                //     {\n                //         gameMode: 'SUPER_BUY_BONUS',\n                //         factor: 10000,\n                //         lines: 0,\n                //     },\n                // ];\n                this.roundsSettings.settings.bet =\n                    this.roundsSettings.settings.bet === undefined ? 1 : this.roundsSettings.settings.bet;\n                if (!this.roundsSettings.settings.matchBet) {\n                    this.roundsSettings.settings.matchBet = {};\n                    this.roundsSettings.settings.matchBet.denomination = this.data.denomination;\n                    this.roundsSettings.settings.matchBet.factor = this.data.bet;\n                    this.roundsSettings.settings.matchBet.matchFactor = this.data.bet;\n                    this.roundsSettings.settings.matchBet.level = this.data.bet / this.roundsSettings.settings.factor;\n                }\n                this.roundsSettings.settings.matchBet.matchFactor =\n                    this.roundsSettings.settings.matchBet.matchFactor || this.roundsSettings.settings.matchBet.factor;\n                this.roundsSettings.settings.denomination = this.roundsSettings.settings.matchBet.denomination;\n                this.roundsSettings.settings.factor = this.roundsSettings.settings.matchBet.factor;\n                this.roundsSettings.settings.factors = this.roundsSettings.settings.factors || [\n                    this.roundsSettings.settings.factor,\n                ];\n                this.roundsSettings.settings.denominations = this.roundsSettings.settings.denominations || [\n                    this.roundsSettings.settings.matchBet.denomination,\n                ];\n                if (!this.roundsSettings.settings.linesOptions) {\n                    if (Array.isArray(this.roundsSettings.settings.linesPerDenomination)) {\n                        const uniqueLineOptions = new Set<number>(this.roundsSettings.settings.linesPerDenomination);\n                        this.roundsSettings.settings.linesOptions = Array.from(uniqueLineOptions);\n                    } else {\n                        this.roundsSettings.settings.linesOptions = [this.data.lines];\n                    }\n                }\n                // this.roundsSettings.settings.linesOptions = this.roundsSettings.settings.linesOptions || [\n                //     this.data.lines,\n                // ];\n                this.roundsSettings.settings.lines = this.roundsSettings.settings.lines || this.data.lines;\n                if (this.roundsSettings.settings.feature.find((f) => f === 'BUY_BONUS')) {\n                    this.roundsSettings.settings.buyBonusOptions = this.roundsSettings.settings.buyBonusOptions || [\n                        this.roundsSettings.settings.factor,\n                    ];\n                }\n                if (this.roundsSettings.settings.linesPerDenomination) {\n                    this.roundsSettings.settings.denominations = [];\n                    for (let i = 0; i < this.roundsSettings.settings.linesPerDenomination.length; i++) {\n                        if (\n                            this.roundsSettings.settings.linesPerDenomination[i] === this.roundsSettings.settings.lines\n                        ) {\n                            this.roundsSettings.settings.denominations.push(\n                                this.roundsSettings.settings.matchBet.denomination,\n                            );\n                        } else {\n                            this.roundsSettings.settings.denominations.push(0);\n                        }\n                    }\n                }\n\n                // fill empty stats data\n                this.roundsSettings.jackpotStats = this.addFakeStatsProperties(this.roundsSettings.jackpotStats);\n                // set balance enoght to bet\n                this.roundsSettings.balance.balance = 0;\n                // delete dublicated bonuses as HOLDSPIN in CRSlot game\n                this.roundsData.forEach((r) => {\n                    if (r.bonusRoundWins.length > 1) {\n                        const noDublicatesArray = Array.from(new Set(r.bonusRoundWins.map((obj) => obj.type))).map(\n                            (type) => {\n                                return r.bonusRoundWins.find((obj) => obj.type === type);\n                            },\n                        );\n                        if (noDublicatesArray.length !== r.bonusRoundWins.length) {\n                            r.bonusRoundWins = noDublicatesArray;\n                        }\n                    }\n                });\n\n                this.roundsSettings.settings['jurisdiction'] = this.roundsSettings.settings['jurisdiction'] || {};\n                this.roundsSettings.settings['jurisdiction']['autoplayRestrictions'] = {\n                    mandatory: [],\n                };\n                // remove some restrictions not suitable for replayer\n                const restrictionsToRemove = [RestrictionType.PAYTABLE_ON_LOAD, RestrictionType.DEFAULT_BET_ON_LOAD];\n                if (Array.isArray(this.roundsSettings.settings.jurisdiction?.restrictions)) {\n                    this.roundsSettings.settings.jurisdiction.restrictions =\n                        this.roundsSettings.settings.jurisdiction.restrictions.filter(\n                            (r: string) => !restrictionsToRemove.includes(r as RestrictionType),\n                        );\n                }\n                // maxJurisdictionalBet comes in data object in diffeterent structure - transform and put here\n                if (this.data.maxJurisdictionalBet) {\n                    this.roundsSettings.settings.jurisdiction.maxJurisdictionalBet = Object.entries(\n                        this.data.maxJurisdictionalBet,\n                    ).map(([key, value]) => ({\n                        [key]: value,\n                    }));\n                }\n\n                this.roundsSettings.settings['limit'] = this.roundsSettings.limit;\n\n                Log.debug('data:', this.constructor.name, this.data);\n                Log.debug('roundsData:', this.constructor.name, this.roundsData);\n                Log.debug('roundsSettings:', this.constructor.name, this.roundsSettings);\n            })\n            .catch((data) => {\n                Log.error('Error:', this.constructor.name, data);\n                this.showError('replayer.error.badKey');\n            });\n        return request;\n    }\n\n    protected addFakeStatsProperties(stats: any): any {\n        stats.forEach((stat) => {\n            if (stat.levelStats) {\n                stat.levelStats.forEach((level) => {\n                    level.lastWinDate = this.data.startedOn;\n                    level.maxWinDate = this.data.startedOn;\n                    level.lastWinPlayerName = '*******';\n                    level.totalWins = 30;\n                });\n            }\n        });\n        return stats;\n    }\n\n    protected gameHasUnsupportedCommands(): boolean {\n        const supportedCommands: string[] = [\n            ReplayerRoundType.SPIN,\n            ReplayerRoundType.GAMBLE,\n            ReplayerRoundType.FREESPIN,\n            ReplayerRoundType.HOLDSPIN,\n            ReplayerRoundType.MYSTERYSPIN,\n            ReplayerRoundType.OVERFLOW_WIN,\n            ReplayerRoundType.RESPIN,\n            ReplayerRoundType.FREERESPIN,\n            ReplayerRoundType.FREESPIN_STICKY_WILDS,\n            ReplayerRoundType.FREESPIN_RAINING_WILDS,\n            ReplayerRoundType.CHOICE,\n            ReplayerRoundType.PICK,\n            ReplayerRoundType.BONUS_CHANCE,\n            ReplayerRoundType.JACKPOT_PICK,\n            ReplayerRoundType.WHEELSPIN,\n            ReplayerRoundType.MEGA_RESPIN,\n            ReplayerRoundType.FREESPIN_SCATTERS,\n            ReplayerRoundType.PAIDRESPIN,\n            ReplayerRoundType.PRIZE_POP,\n            ReplayerRoundType.DEDUCTION,\n            ReplayerRoundType.PREMIUM_LINK_JACKPOT_WIN,\n        ];\n        let hasNotSupportedCommand: boolean = false;\n        this.roundsData.forEach((d) => {\n            if (!supportedCommands.includes(d.type)) {\n                hasNotSupportedCommand = true;\n                return;\n            }\n        });\n        return hasNotSupportedCommand;\n    }\n\n    protected showError(id: string): void {\n        this.loadTranslations();\n        const errorData = {} as IErrorData;\n        errorData.errorName = id;\n        errorData.code = id;\n        errorData.modal = true;\n        errorData.type = ErrorTypes.GAME_LOCK_ERROR;\n        Core.SHOW_ERROR.next(errorData);\n    }\n\n    protected onExitApplication(): void {\n        window.setTimeout(() => {\n            if (Core.configuration.closeUrl) {\n                Log.debug('Redirect to', Core.configuration.closeUrl);\n                window.location.href = Core.configuration.closeUrl;\n            } else {\n                window.close();\n                // on our casino implememnation - go to full screen put\n                // object in history. we set time out and try again to navigate back\n                window.setTimeout(() => {\n                    if (window.history.length > 1 && !Core.environment.isIosBrowser) {\n                        window.history.back();\n                    } else {\n                        const buttons = document.getElementsByClassName('modalActions');\n                        if (buttons.length) {\n                            (buttons[0] as HTMLDivElement).style.display = 'none';\n                        }\n                    }\n                }, 500);\n            }\n        }, 100);\n    }\n}\n","export enum ReplayerCommandType {\n    LOAD_GAME = 'loadGame',\n    BET = 'bet',\n    SPIN = 'spin',\n    GAMBLE = 'gamble',\n    COLLECT = 'collect',\n    PICK = 'pick',\n    CHOICE = 'choice',\n    BALANCE = 'balance',\n    COLLECTPRIZEPOP = 'collectPrizePop',\n    DEDUCTION = 'deduction',\n}\n\nexport enum ReplayerRoundType {\n    LAST = 'LAST',\n    SPIN = 'SPIN',\n    MYSTERYSPIN = 'MYSTERYSPIN',\n    GAMBLE = 'GAMBLE',\n    PICK = 'PICK',\n    BONUS_CHANCE = 'BONUS_CHANCE',\n    HOLDSPIN = 'HOLDSPIN',\n    FREERESPIN = 'FREERESPIN',\n    FREESPIN = 'FREESPIN',\n    CHOICE = 'CHOICE',\n    JACKPOT_PICK = 'JACKPOT_PICK',\n    WHEELSPIN = 'WHEELSPIN',\n    MEGA_RESPIN = 'MEGA_RESPIN',\n    FREESPIN_SCATTERS = 'FREESPIN_SCATTERS',\n    OVERFLOW_WIN = 'OVERFLOW_WIN',\n    RESPIN = 'RESPIN',\n    FREESPIN_STICKY_WILDS = 'FREESPIN_STICKY_WILDS',\n    FREESPIN_RAINING_WILDS = 'FREESPIN_RAINING_WILDS',\n    PROGRESSIVE_HIT = 'PROGRESSIVE_HIT',\n    PAIDRESPIN = 'PAIDRESPIN',\n    PRIZE_POP = 'PRIZE_POP',\n    DEDUCTION = 'DEDUCTION',\n    PREMIUM_LINK_JACKPOT_WIN = 'PREMIUM_LINK_JACKPOT_WIN',\n}\n","import { Breadcrumb, BrowserClient, Event, EventHint, Span } from '@sentry/browser';\nimport * as Sentry from '@sentry/browser';\nimport type { SeverityLevel } from '@sentry/core/build/types/types-hoist/severity';\nimport type { Attachment } from '@sentry/core/build/types/types-hoist/attachment';\nimport Core, { Log } from '@egt/core';\nimport type { ErrorEvent } from '@sentry/core';\nimport { TransactionEvent } from '@sentry/core';\n\n/**\n * Defines operation types for Sentry transaction spans.\n * These values are used to categorize different types of operations being monitored.\n * - GAME_INIT: Tracks the game initialization process, including resource loading and first render\n * - GAME_PLAY: Tracks gameplay-related operations such as spins, feature activations, and rounds\n */\nenum SentrySpanOperationTypes {\n    GAME_INIT = 'egt.game.init',\n    GAME_PLAY = 'egt.game.play',\n    GAME_SESSION = 'egt.game.session',\n}\n\n/**\n * Defines predefined transaction types for Sentry monitoring.\n * Each transaction type contains a name and operation type to categorize different game events.\n * - GAME_INIT: Transaction for tracking the complete game initialization process\n * - GAME_ROUND: Transaction for tracking individual game rounds/spins\n */\nexport const SentryTransactionTypes = {\n    GAME_INIT: {\n        name: 'game-initialization',\n        op: SentrySpanOperationTypes.GAME_INIT,\n    },\n    GAME_ROUND: {\n        name: 'game-round',\n        op: SentrySpanOperationTypes.GAME_PLAY,\n    },\n    GAME_IDLE: {\n        name: 'game-idle',\n        op: SentrySpanOperationTypes.GAME_PLAY,\n    },\n    GAME_SESSION: {\n        name: 'game-session',\n        op: SentrySpanOperationTypes.GAME_SESSION,\n    },\n} as const;\n\n/**\n * Defines attribute keys used for adding metadata to Sentry spans.\n * These attributes provide additional context about the monitored operations.\n * - GAMEPLAY: Attributes related to gameplay mechanics (speed, auto-play)\n * - PERFORMANCE: Performance-related metrics and indicators\n * - SETTINGS: User configuration changes (sound, music toggles)\n * - OTHERS: Miscellaneous events (opening lobby, page visibility changes)\n */\nexport const SENTRY_DATA = {\n    CONFIGURATIONS: {\n        GAME_KEY: 'egt.configuration.gameKey',\n        DEMO: 'egt.configuration.demo',\n        MODE: 'egt.configuration.mode',\n        VERSION: 'egt.configuration.version',\n        LANGUAGE: 'egt.configuration.language',\n        CURRENCY: 'egt.configuration.currency',\n    },\n    GAMEPLAY: {\n        SPEED: 'egt.gameplay.init',\n        AUTO_PLAY: 'egt.gameplay.auto_play',\n    },\n    PERFORMANCE: {\n        MEMORY: {\n            USED_JSHEAP_SIZE: 'egt.performance.memory.used_jsheap_size',\n            TOTAL_JSHEAP_SIZE: 'egt.performance.memory.total_jsheap_size',\n            JSHEAP_SIZE_LIMIT: 'egt.performance.memory.jsheap_size_limit',\n        },\n        DEVICE: {\n            MODEL: 'egt.performance.device.model',\n            VENDOR: 'egt.performance.device.vendor',\n            PLATFORM: 'egt.performance.device.platform',\n        },\n    },\n    SETTINGS: {\n        SOUND: 'egt.settings.sound',\n        MUSIC: 'egt.settings.music',\n    },\n    ROUND: {\n        OPEN_LOBBY: 'egt.round.open_lobby',\n        PAGE_HIDDEN: 'egt.round.page_hidden',\n        ORIENTATION: 'egt.round.orientation',\n        SPIN_SPEED: 'egt.round.spin_speed',\n        SPIN_MODE: 'egt.round.spin_mode',\n        SPINS: 'egt.round.spins',\n        MODES: 'egt.round.modes',\n        AVG_IDLE_TIME: 'egt.round.avgIdleTime',\n        AVG_SERVER_RESPONSE_TIME: 'egt.round.avgServerResponseTime',\n        AVG_REEL_STOP_NORMAL: 'egt.round.avgReelStopTimeInNormalSpin',\n        AVG_REEL_STOP_QUICK: 'egt.round.avgReelStopTimeInQuickSpin',\n        AVG_REEL_STOP_TURBO: 'egt.round.avgReelStopTimeInTurboSpin',\n    },\n    USER_ACTIONS: {\n        SOUND_TOGGLED: 'egt.userActions.soundToggled',\n        MUSIC_TOGGLED: 'egt.userActions.musicToggled',\n        SETTINGS_OPENED: 'egt.userActions.settingsOpened',\n        HOME_CLICKED: 'egt.userActions.homeClicked',\n        AUTOPLAY_USED: 'egt.userActions.autoplayUsed',\n        SPEED_MODE_USED: 'egt.userActions.speedModeUsed',\n        JACKPOT_STATISTICS_USED: 'egt.userActions.jackpotStatisticsUsed',\n        HELP_OPENED: 'egt.userActions.helpOpened',\n    },\n    EVENTS: 'egt.events',\n} as const;\n\n/**\n * We support those 3 Sentry projects based on our main environments on which the game might run.\n * The hole idea is not to mix events/exceptions/spans/transactions between environments.\n */\nexport enum SentryProjects {\n    DEV = 'DEV',\n    RELEASE = 'RELEASE',\n    PRODUCTION = 'PRODUCTION',\n}\n\nconst GamesSentryDSN: Record<SentryProjects, string> = {\n    [SentryProjects.DEV]:\n        'https://93eb36481c3c278179f1403e4b211032@o4509112131584001.ingest.de.sentry.io/4509357119963217',\n    [SentryProjects.RELEASE]:\n        'https://e8670733f4f34d4fd69b94a7b698361c@o4509112131584001.ingest.de.sentry.io/4509367259234384',\n    [SentryProjects.PRODUCTION]:\n        'https://2fb575b8dad8df2cd127c11d98c30ad7@o4509112131584001.ingest.de.sentry.io/4509366836199504',\n} as const;\n\nexport function getMemoryUsage(): {\n    usedJSHeapSize?: number;\n    totalJSHeapSize?: number;\n    jsHeapSizeLimit?: number;\n} | null {\n    try {\n        // Check if performance.memory is available (Chrome/Edge)\n        if (window.performance && (window.performance as any).memory) {\n            const memory = (window.performance as any).memory;\n            return {\n                usedJSHeapSize: Math.round((memory.usedJSHeapSize / (1024 * 1024)) * 100) / 100, // MB with 2 decimal places\n                totalJSHeapSize: Math.round((memory.totalJSHeapSize / (1024 * 1024)) * 100) / 100, // MB with 2 decimal places\n                jsHeapSizeLimit: Math.round((memory.jsHeapSizeLimit / (1024 * 1024)) * 100) / 100, // MB with 2 decimal places\n            };\n        }\n\n        return null;\n    } catch {\n        return null;\n    }\n}\n\nfunction createSentryClient(\n    release: string,\n    tags: Record<string, any>,\n    sentryProject: SentryProjects = SentryProjects.DEV,\n    sentrySampleRate: number = 0.1,\n): Sentry.BrowserClient {\n    const dsn = GamesSentryDSN[sentryProject];\n    const environment = sentryProject.toString().toLowerCase();\n    const debug = !(sentryProject === SentryProjects.PRODUCTION);\n\n    const sentryClient = Sentry.init({\n        dsn,\n        sendDefaultPii: false, // Personally Identifiable Information (PII)\n        integrations: [\n            Sentry.browserTracingIntegration({\n                idleTimeout: 60000,\n                finalTimeout: 60000,\n                traceFetch: false,\n                traceXHR: false,\n                enableInp: true, // performance metrics\n                trackFetchStreamPerformance: false,\n                enableHTTPTimings: false,\n                _experiments: {\n                    enableInteractions: false,\n                    enableStandaloneClsSpans: false,\n                },\n                instrumentPageLoad: false,\n                instrumentNavigation: false,\n            }),\n            Sentry.breadcrumbsIntegration({\n                console: false,\n                dom: false,\n                fetch: false,\n                history: true,\n                sentry: true,\n                xhr: false,\n            }),\n            // Sentry.replayIntegration(),\n            // Sentry.replayCanvasIntegration(),\n            // Sentry.captureConsoleIntegration({ levels: [\"log\", \"error\", \"warn\"] }) // this is optional experimental\n        ],\n        beforeSendTransaction: (event: TransactionEvent) => {\n            // we clean not needed spans from the data\n            if (event.spans) {\n                event.spans = [];\n            }\n            return event;\n        },\n        beforeSend: (event: ErrorEvent) => {\n            return event;\n        },\n        debug,\n        environment,\n        release,\n\n        initialScope: {\n            tags,\n        },\n\n        // _experiments: { enableLogs: true },\n        maxBreadcrumbs: 10,\n        // Tracing\n        tracesSampleRate: sentrySampleRate,\n        tracePropagationTargets: [], // Need to link http/https request to other sentry instances via headers in the requests.\n        // Session Replay\n        replaysSessionSampleRate: 0.1, // This sets the sample rate at 10%. You may want to change it to 100% while in development and then sample at a lower rate in production.\n        replaysOnErrorSampleRate: 0.1, // If you're not already sampling the entire session, change the sample rate to 100% when sampling sessions where errors occur.\n        profilesSampleRate: 0.1, // Relates to javascript profiling callstacks, function execution times, etc\n    }) as Sentry.BrowserClient;\n\n    if (sentryClient) {\n        // window.addEventListener('pagehide', () => {\n        //     const currentSpan = getActiveSentrySpan();\n        //     if (currentSpan) {\n        //         currentSpan.setAttribute(SENTRY_DATA.ROUND.PAGE_HIDDEN, 'true');\n        //         // startSentryTransaction(Core.sentryClient, SentryTransactionTypes.GAME_IDLE);\n        //     }\n        //     Sentry.flush(0);\n        // });\n        // window.document.addEventListener('visibilitychange', () => {\n        //     if (document.visibilityState === 'hidden') {\n        //         const currentSpan = getActiveSentrySpan();\n        //         if (currentSpan) {\n        //             currentSpan.setAttribute(SENTRY_DATA.ROUND.PAGE_HIDDEN, 'true');\n        //             // startSentryTransaction(Core.sentryClient, SentryTransactionTypes.GAME_IDLE);\n        //         }\n        //         Sentry.flush(0);\n        //     }\n        // });\n    }\n\n    return sentryClient;\n}\n\nexport async function initSentry(location: string, version: string) {\n    const urlParams = new URLSearchParams(location);\n    const rawDemo = urlParams.get('demo') ?? Core.configuration.demo;\n    const language = urlParams.get('language') || Core.configuration.language;\n    const gameKey = urlParams.get('gameKey') || Core.configuration.gameKey;\n    const currencyCode = urlParams.get('currencyCode') || Core.configuration.currencyCode;\n    const mode = urlParams.get('mode') || Core.configuration.mode;\n    const deviceInfo = Core.environment.getDevice();\n    const deviceHints = await Core.environment.getDeviceHints();\n    if (!!deviceHints && deviceHints.model) {\n        if (!deviceInfo.model || deviceHints.model.length > deviceInfo.model.length) {\n            deviceInfo.model = deviceHints.model;\n        }\n    }\n\n    // @ts-ignore\n    const sentryEnvironment = window.ssi.sentryEnvironment as string;\n    // @ts-ignore\n    const sentrySampleRate = window.ssi.sentrySampleRate as number;\n    const sentryProject = SentryProjects[sentryEnvironment.toUpperCase()];\n    // if demo is true, we don't want to send any data to sentry\n    const demo = String(rawDemo).toLowerCase() === 'true';\n    if (demo) {\n        return;\n    }\n\n    if (!sentryProject) {\n        Log.error(`Unknown Sentry environment type: '${sentryEnvironment}'`, 'initSentry');\n        return;\n    }\n\n    const sentryTags = {\n        [SENTRY_DATA.CONFIGURATIONS.GAME_KEY]: gameKey,\n        [SENTRY_DATA.CONFIGURATIONS.LANGUAGE]: language,\n        [SENTRY_DATA.CONFIGURATIONS.DEMO]: demo,\n        [SENTRY_DATA.CONFIGURATIONS.CURRENCY]: currencyCode,\n        [SENTRY_DATA.CONFIGURATIONS.MODE]: mode,\n        [SENTRY_DATA.PERFORMANCE.DEVICE.MODEL]: deviceInfo.model || 'unknown',\n        [SENTRY_DATA.PERFORMANCE.DEVICE.VENDOR]: deviceInfo.vendor || 'unknown',\n        [SENTRY_DATA.PERFORMANCE.DEVICE.PLATFORM]: deviceInfo.type || 'desktop',\n    };\n\n    const sentryClient = createSentryClient(version, sentryTags, sentryProject, sentrySampleRate);\n    return sentryClient;\n}\n\nexport function sendSentryEvent(\n    client: BrowserClient,\n    event: {\n        message: string;\n        level: SeverityLevel;\n        release?: string;\n    },\n    data: {\n        useFingerprint?: boolean;\n        breadcrumb?: Breadcrumb[];\n        tags?: Record<string, string>;\n        images?: Record<string, Uint8Array>;\n        extras?: Record<string, unknown>;\n    },\n) {\n    if (!client) {\n        return;\n    }\n\n    if (!event.release) {\n        delete event.release;\n    }\n\n    const hint: EventHint = {} as any;\n    if (data.images) {\n        const images = data.images;\n        const attachments: Attachment[] = [];\n\n        Object.keys(images).forEach((imageName) => {\n            attachments.push({\n                filename: imageName,\n                data: images[imageName],\n                contentType: 'image/jpeg', // Ensure correct content type\n            });\n        });\n        hint.attachments = attachments;\n    }\n\n    const extras: any = {};\n    if (data.extras) {\n        extras.extra = data.extras;\n    }\n\n    const tags: { tags: Record<string, string> } = {} as any;\n    if (data.tags) {\n        tags.tags = data.tags;\n    }\n    const composedEvent: Event = {\n        ...event,\n        ...tags,\n        ...extras,\n    };\n\n    if (data.useFingerprint) {\n        composedEvent.fingerprint = [Date.now().toString(), Math.random().toString()];\n    }\n\n    if (data.breadcrumb && data.breadcrumb.length > 0) {\n        composedEvent.breadcrumbs = [...data.breadcrumb];\n    }\n\n    client.captureEvent(composedEvent, hint);\n}\n\nexport function sendSentryMessage(\n    client: BrowserClient,\n    message: {\n        message: string;\n        level?: SeverityLevel;\n    },\n    data: {\n        tags?: Record<string, string>;\n        images?: Record<string, Uint8Array>;\n    },\n) {\n    if (!client) {\n        return;\n    }\n\n    const hint: EventHint = {} as any;\n    if (data.images) {\n        const images = data.images;\n        const attachments: Attachment[] = [];\n\n        Object.keys(images).forEach((imageName) => {\n            attachments.push({\n                filename: imageName,\n                data: images[imageName],\n                contentType: 'image/jpeg', // Ensure correct content type\n            });\n        });\n        hint.attachments = attachments;\n    }\n\n    message.level = message.level || 'info';\n    Sentry.withScope((scope) => {\n        if (data.tags) {\n            scope.setTags({ ...data.tags });\n        }\n\n        client.captureMessage(message.message, message.level, hint);\n    });\n}\n\nlet currentSpan: Span | undefined;\nexport function getActiveSentrySpan() {\n    return currentSpan;\n}\n\n/**\n * Starts an independent Sentry span without touching the currentSpan lifecycle.\n * Useful for one-off aggregated session spans.\n */\nexport function startStandaloneSentrySpan(\n    _client: BrowserClient,\n    transactionType: (typeof SentryTransactionTypes)[keyof typeof SentryTransactionTypes],\n    attributes?: Record<string, string | boolean | number>,\n): Span | undefined {\n    const span = Sentry.startSpanManual(\n        {\n            name: transactionType.name,\n            op: transactionType.op,\n        },\n        (s) => s,\n    );\n\n    if (span && attributes) {\n        Object.keys(attributes).forEach((key) => span.setAttribute(key, attributes[key]));\n    }\n    return span;\n}\n\n/* This is a transaction which is specifically designed to measure the time needed for the game to load its resource and render first game screen to user*/\nexport function startInitializationTransaction(client: BrowserClient) {\n    if (!client) {\n        return;\n    }\n\n    const spanStartOptions = {\n        ...SentryTransactionTypes.GAME_INIT,\n    };\n\n    currentSpan = Sentry.startBrowserTracingPageLoadSpan(client, spanStartOptions) as Span;\n    return currentSpan;\n}\n\n/**\n * Starts a Sentry transaction with custom tags\n * @param client Sentry BrowserClient instance\n * @param transactionType Options for the transaction span including name and operation type\n * @returns The created transaction span\n */\nexport function startSentryTransaction(\n    client: BrowserClient,\n    transactionType: (typeof SentryTransactionTypes)[keyof typeof SentryTransactionTypes],\n    attributes?: Record<string, string | boolean | number>,\n): Span | undefined {\n    if (!client) {\n        return undefined;\n    }\n\n    if (currentSpan) {\n        currentSpan.setStatus({ code: 1 });\n        currentSpan.end();\n    }\n\n    currentSpan = Sentry.startSpanManual(\n        {\n            name: transactionType.name,\n            op: transactionType.op,\n        },\n        (span) => {\n            return span;\n        },\n    );\n\n    if (!!attributes) {\n        Object.keys(attributes).forEach((key) => {\n            currentSpan?.setAttribute(key, attributes[key]);\n        });\n    }\n\n    return currentSpan;\n}\n\n/*async function captureScreenshot(): Promise<Uint8Array> {\n    const canvas = await html2canvas(document.body);\n\n    return new Promise((resolve, reject) => {\n        canvas.toBlob(\n            (blob) => {\n                if (blob) {\n                    const reader = new FileReader();\n                    reader.onloadend = () => {\n                        const arrayBuffer = reader.result as ArrayBuffer;\n                        resolve(new Uint8Array(arrayBuffer)); // Convert to Uint8Array\n                    };\n                    reader.onerror = reject;\n                    reader.readAsArrayBuffer(blob);\n                } else {\n                    reject(new Error('Failed to create blob'));\n                }\n            },\n            'image/jpeg', // Use JPEG for better compression\n            0.7 // Compression quality (adjust for smaller size)\n        );\n    });\n\n}*/\n","// Import enums, contracts and  data from their leaf files (NOT the '@egt/core' barrel) — this module is\n// created during `new Core()` execution, while the barrel is still mid-evaluation. See FeatureFlagsData.ts.\nimport type { IFeatureFlag } from '../interfaces/IFeatureFlags';\nimport { FeatureFlags } from '../enums/FeatureFlags';\nimport RestrictionType from '../enums/RestrictionType';\nimport FeatureFlagGroups from '../enums/FeatureFlagGroups';\nimport LocalFeatureFlags, { requireFlagMetadata } from '../data/FeatureFlagsData';\n// The two host values this store needs — `gameKey` and `devTools` — arrive through a leaf provider\n// instead of an import of the `Core` singleton, so this module imports nothing outside\n// `packages/core/src/egt/core`, so the `Core.ts` <-> flag-store cycle no longer exists. Reads stay\n// at call time, so a `gameKey` assigned from the load-game response after construction is still seen.\nimport { readFlagsHostConfig } from './FlagsHostConfig';\n\n/**\n * Storage-key prefix for the persisted feature-flags configuration. The effective key is suffixed\n * with the current game's `gameKey` (see `getConfigStorageKey`) so configurations are scoped per\n * game: switching to a different game reads a different key, and a game with no stored configuration\n * sees an empty config instead of inheriting another game's flags.\n */\nexport const FEATURE_FLAGS_CONFIG_STORAGE_KEY = 'egt_feature_flags_config';\n\n/** On-disk shape: a plain record of FeatureFlags enum key → desired isActive. */\nexport type PersistedFlagsConfig = Partial<Record<FeatureFlags, boolean>>;\n\n/**\n * Every valid flag identifier, built once at module evaluation.\n *\n * `assertKnown` runs on every `isActive` and `get` call across the client. Building\n * `Object.values(FeatureFlags)` there allocated a fresh array and scanned it linearly per read; a\n * `Set` built once answers the same question in constant time. No flag read sits in a ticker or\n * per-frame path today, so this was never a live defect — it is simply free.\n */\nconst KNOWN_FLAGS: ReadonlySet<FeatureFlags> = new Set(Object.values(FeatureFlags));\n\n/**\n * Global feature-flags store, accessible via `Core.flags`.\n * Feature flags are written once at gameResponseLoaded (by Core / SlotGame / ScratchGame)\n * and read synchronously everywhere. This is global app config —\n * same depth as `Core.configuration` / `Core.environment`.\n * Concrete core base store: it owns core flags storage, the two-check getters, group queries, and\n * the URL override. Per-game subclasses contribute only their own `registerGameFlags`.\n * Example usage:\n *   Core.flags.isActive(FeatureFlags.USE_PAYTABLE_ON_LOAD)\n *   Core.flags.get(FeatureFlags.USE_PAYTABLE_ON_LOAD) -> the full flag object with metadata\n *   Core.flags.all(FeatureFlags.USE_PAYTABLE_ON_LOAD) -> the full flags object with all flags and their metadata\n */\nexport default class FeatureFlagsStore {\n    protected _flags = new Map<FeatureFlags, IFeatureFlag>();\n\n    /**\n     * @name constructor\n     * Constructs the store and, WHEN a load-game response is supplied, seeds it by running\n     * `initialize`. Called with no argument — `new FeatureFlagsStore()` in the `Core` field\n     * initializer and in `Core.destroyGame` — it yields an empty store and reads no configuration,\n     * which matters because `Core.configuration` does not exist yet at field-initialiser time.\n     *\n     * Per-game subclasses declare NO constructor: the implicit forwarding constructor passes the\n     * response through, so the construction sequence lives in exactly one place. A subclass must\n     * also declare no instance field — `super()` completes before a subclass field initializer\n     * runs, so a field that `registerGameFlags` read would still be `undefined`.\n     */\n    public constructor(loadGameResponse?: unknown) {\n        if (loadGameResponse !== undefined) this.initialize(loadGameResponse);\n    }\n\n    /**\n     * @name initialize\n     * The construction sequence, in the only place it exists: core restriction seeding, then the\n     * per-game registration hook, then `settle`. `private` on purpose — TypeScript has no `final`,\n     * and `private` is the only construct that makes a redeclaration in a subclass a compile error.\n     * The overridable seams are `setBaseFlags`, `registerClientFlags`, `registerGameFlags` and\n     * `applyDerivedMetadata`.\n     */\n    private initialize(loadGameResponse: unknown): void {\n        this.setBaseFlags(loadGameResponse);\n        this.registerClientFlags();\n        this.registerGameFlags(loadGameResponse);\n        this.settle();\n    }\n\n    /**\n     * @name settle\n     * The override pass followed by the derived-metadata hook, as one unit. `applyDerivedMetadata`\n     * is documented as required to run LAST, after `applyOverrides`, because both overrides derive\n     * from post-override state; binding the two together is what stops a caller from running one\n     * without the other. `private` for the same reason as `initialize`.\n     *\n     * `reset()` deliberately does NOT route through this: it must leave the store neutral for\n     * `Core.destroyGame`, and re-applying overrides there was removed on purpose.\n     */\n    private settle(): void {\n        this.applyOverrides();\n        this.applyDerivedMetadata();\n    }\n\n    /**\n     * @name set\n     * Set/update a single flag, then settle: re-apply the overrides and re-derive metadata from the\n     * resulting states. */\n    public set(key: FeatureFlags, value: IFeatureFlag): void {\n        this._flags.set(key, value);\n        this.settle();\n    }\n\n    /**\n     * @name get\n     * Get the full flag object (for metadata like `assetSuffix` / `translationPrefix`). Runs\n     * check (2) — enum membership — first (unknown identifier → throws), then check (1): an\n     * unregistered-but-valid flag throws because there is no metadata to return. Reads no-mutate.\n     */\n    public get(flag: FeatureFlags): IFeatureFlag {\n        this.assertKnown(flag); // check (2): enum membership → throw on typo\n        const featureFlag = this._flags.get(flag);\n        if (!featureFlag) {\n            throw new Error(`FeatureFlagsStore.get: unregistered feature flag \"${flag}\".`); // check (1)\n        }\n        return featureFlag;\n    }\n\n    /**\n     * @name setAll\n     * Set/replace the whole collection (called once at load), then settle: re-apply the overrides\n     * and re-derive metadata from the resulting states. */\n    public setAll(flags: Map<FeatureFlags, IFeatureFlag>): void {\n        this._flags = flags;\n        this.settle();\n    }\n\n    /**\n     * @name all\n     * Getter for the whole collection (read-only use / iteration). */\n    public get all(): Map<FeatureFlags, IFeatureFlag> {\n        return this._flags;\n    }\n\n    /**\n     * @name byGroup\n     * Get all registered flags whose `group` exactly equals the requested value (empty map when\n     * none). Unregistered flags are never included regardless of their catalog group.\n     */\n    public byGroup(group: FeatureFlagGroups): Map<FeatureFlags, IFeatureFlag> {\n        const result = new Map<FeatureFlags, IFeatureFlag>();\n        this._flags.forEach((value, key) => {\n            if (value.group === group) result.set(key, value);\n        });\n        return result;\n    }\n\n    /**\n     * @name setBaseFlags\n     * Seeds ONLY the all-games core restriction flags (USE_PAYTABLE_ON_LOAD,\n     * USE_DEFAULT_BET_ON_LOAD, DISABLE_HOLD_AND_PLAY) driven by the load-game response's\n     * jurisdiction restrictions. These are the root-level restrictions that apply to every\n     * game-type (game-specific restrictions stay in the per-game `registerGameFlags`).\n     * Called by `initialize` before `registerGameFlags`, so game flags can override these\n     * defaults. Writes directly to `this._flags` (no per-entry URL override re-application —\n     * `settle` applies the overrides once at the end).\n     *\n     * Reaching a `case` means the restriction IS present in the response, so the flag is\n     * registered ACTIVE: the catalog entry supplies metadata only and its `isActive: false`\n     * default must not be copied through. Seeding the catalog value verbatim is what left\n     * `HIDE_HOLD_AND_PLAY` permanently inactive at every consumer.\n     */\n    protected setBaseFlags(loadGameResponse: unknown): void {\n        const response = loadGameResponse as {\n            settings?: { jurisdiction?: { restrictions?: string[] } };\n        };\n        response?.settings?.jurisdiction?.restrictions?.forEach((restrictionFromResponse: string) => {\n            let newFlag: { key: FeatureFlags; value?: IFeatureFlag } | null = null;\n            switch (restrictionFromResponse) {\n                case RestrictionType.PAYTABLE_ON_LOAD:\n                    newFlag = {\n                        key: FeatureFlags.USE_PAYTABLE_ON_LOAD,\n                        value: LocalFeatureFlags[FeatureFlags.USE_PAYTABLE_ON_LOAD],\n                    };\n                    break;\n                case RestrictionType.DEFAULT_BET_ON_LOAD:\n                    newFlag = {\n                        key: FeatureFlags.USE_DEFAULT_BET_ON_LOAD,\n                        value: LocalFeatureFlags[FeatureFlags.USE_DEFAULT_BET_ON_LOAD],\n                    };\n                    break;\n                case RestrictionType.DISABLE_HOLD_AND_PLAY:\n                    newFlag = {\n                        key: FeatureFlags.HIDE_HOLD_AND_PLAY,\n                        value: LocalFeatureFlags[FeatureFlags.HIDE_HOLD_AND_PLAY],\n                    };\n                    break;\n            }\n            if (newFlag?.key && newFlag?.value) {\n                this._flags.set(newFlag.key, { ...newFlag.value, isActive: true });\n            }\n        });\n    }\n\n    /**\n     * @name registerClientFlags\n     * Seeds the client-only flags that exist for every game type, straight from the catalog with\n     * their default state. They take no server or jurisdiction input and are switched only by the\n     * Feature Flags panel or the `?featureFlag=` URL override. Registering them here, rather than\n     * leaving them unregistered until an override arrives, is what lets the panel show their\n     * description (`get` throws for an unregistered flag) and lets `isActive` answer from a real\n     * entry. Runs after `setBaseFlags` and before `registerGameFlags`, so a per-game store may\n     * still override a default.\n     */\n    protected registerClientFlags(): void {\n        this._flags.set(FeatureFlags.USE_LEGACY_CUSTOM, { ...requireFlagMetadata(FeatureFlags.USE_LEGACY_CUSTOM) });\n    }\n\n    /**\n     * @name registerGameFlags\n     * Base is not game-specific → no-op. Per-game subclasses override this to register their\n     * own flags on top of the seeded defaults.\n     */\n    protected registerGameFlags(_loadGameResponse: unknown): void {\n        // no-op in base\n    }\n\n    /**\n     * @name applyDerivedMetadata\n     * Base is not game-specific → no-op. The seam for flag metadata that is a function of the FINAL\n     * flag states rather than of the load-game response.\n     *\n     * Called LAST by `settle`, after `applyOverrides`. That ordering is the whole point.\n     * `removeComponents` is never in the catalog — it is attached at runtime by\n     * `SlotFeatureFlagsStore` (to the buy-bonus pair, only when both are active) and by\n     * `ScratchFeatureFlagsStore` (to whichever autoplay flag survives). While that derivation ran\n     * inside `registerGameFlags`, it saw only the server response: a flag the Feature Flags panel\n     * switched ON afterwards had no `removeComponents`, because the derivation had already skipped\n     * it as inactive and `mergeOverride`'s catalog fallback has none to supply. The panel could\n     * therefore produce a state the production path cannot reach — flag active, component still\n     * mounted.\n     *\n     * An override implementation must only DECORATE entries that already exist. It must not register\n     * a flag, and it must not re-derive anything the override is entitled to have changed — replaying\n     * a server-driven choice here would overwrite the developer's pin, which is the same defect\n     * inverted.\n     */\n    protected applyDerivedMetadata(): void {\n        // no-op in base\n    }\n\n    /**\n     * @name isActive\n     * The main Boolean getter for flags.Checks flag existence in\n     * FeatureFlags enum and throws (guards against typos). Then check (1) —\n     * registration: a valid-but-unregistered flag → `false` (flags are registered conditionally,\n     * e.g. only under a matching jurisdiction restriction). Reads no-mutate.\n     */\n    public isActive(flag: FeatureFlags): boolean {\n        this.assertKnown(flag); // check (2): enum membership → throw on typo\n        return this._flags.get(flag)?.isActive ?? false; // check (1): unregistered ⇒ inactive\n    }\n\n    /**\n     * @name assertKnown\n     * Check: rejects any flag identifier that is not an exact member of the FeatureFlags enum\n     * (including `null`, `undefined`, and empty string), throwing an error that names the\n     * unknown identifier.\n     */\n    protected assertKnown(flag: FeatureFlags): void {\n        if (!KNOWN_FLAGS.has(flag)) {\n            throw new Error(`FeatureFlagsStore: unknown feature flag \"${flag}\". Not a member of FeatureFlags enum.`);\n        }\n    }\n\n    /**\n     * @name reset\n     * Clear the flag store state, leaving it empty.\n     *\n     */\n    public reset(): void {\n        this._flags = new Map();\n    }\n\n    /**\n     * @name applyOverrides\n     * Re-applies the external flag overrides in priority order: the `?featureFlag=` URL override\n     * first, then the persisted configured override on top, so configured flags win the final write\n     * (highest priority). Called by the mutators and by the per-game store constructors.\n     *\n     * Gated on `devTools` and failing closed — see `isDevToolsEnabled`. This is the single choke\n     * point for the whole override channel; nothing below it is reachable on a production build.\n     */\n    protected applyOverrides(): void {\n        if (!this.isDevToolsEnabled()) return;\n        this.applyUrlOverride();\n        this.applyConfiguredOverride();\n    }\n\n    /**\n     * @name isDevToolsEnabled\n     * Whether the developer-tools build is active, read at call time and failing closed.\n     *\n     * This is the ONLY gate on the override channel, and it sits on `applyOverrides` rather than on\n     * the two override methods so that no future caller can bypass it by invoking one directly.\n     *\n     * Why it has to exist: `applyConfiguredOverride` writes arbitrary booleans straight from\n     * `window.localStorage` into the store. Ungated, a player on a production build could set\n     * `HIDE_BUY_BONUS` / `HIDE_DOUBLE_CHANCE` / `HIDE_HOLD_AND_PLAY` to `false` and have the client\n     * present features the jurisdiction forbids, persisting across reloads. A licensed client must\n     * not *present* a restricted feature, and server-side bet rejection does not cover that.\n     * `Core.restrictions` offered no equivalent channel, so this door is new and must stay shut.\n     *\n     * `devTools` is not player-reachable: it comes from the operator's integration options\n     * (`Configuration.ts`) and is only forced true inside the prebuild-generated block of the dev\n     * client entry. Failing closed is `readFlagsHostConfig`'s job — an unregistered, unreadable or\n     * throwing provider reads `false`, never a throw, and never an applied override.\n     */\n    protected isDevToolsEnabled(): boolean {\n        return readFlagsHostConfig().devTools;\n    }\n\n    /**\n     * @name applyUrlOverride\n     * Applies a `?featureFlag=NAME` URL override, merging onto the live entry so the override\n     * behaves exactly like a real flag (see `mergeOverride`).\n     */\n    protected applyUrlOverride(): void {\n        const flagsParam = new URLSearchParams(window.location.search).get('featureFlag');\n        if (!flagsParam) return;\n\n        const matchedFlag = flagsParam as FeatureFlags;\n        if (!KNOWN_FLAGS.has(matchedFlag)) return;\n\n        this._flags.set(\n            matchedFlag,\n            this.mergeOverride(matchedFlag, true, `Feature flag added from URL: ${matchedFlag}`),\n        );\n    }\n\n    /**\n     * @name mergeOverride\n     * The entry an override should store: the LIVE entry with only `isActive` replaced.\n     *\n     * Both override methods used to rebuild the entry from `LocalFeatureFlags`, and that silently\n     * destroyed metadata. The catalog carries NO `removeComponents` by design — it is attached after\n     * registration by `SlotFeatureFlagsStore._applyBuyBonusComponentRemoval` (only when\n     * hideBuyBonus AND noDoubleChance are both active) and by\n     * `ScratchFeatureFlagsStore._processScratchRestrictions`. Because `applyOverrides` runs LAST in\n     * every per-game store constructor, rebuilding from the catalog discarded exactly that work:\n     * pinning the buy-bonus pair left `BUY_BONUS` mounted where the real jurisdiction path removes\n     * it, and pinning `USE_NUMERIC_AUTOPLAY` on scratch mounted both autoplay popups. The dev tool\n     * was producing states the production path cannot reach.\n     *\n     * Falls back to the catalog only for a flag that is not registered yet, and to a synthesised\n     * description/group only for a flag the catalog does not list either — the phantom-flag case the\n     * dev panel can still reach for enum members with no catalog entry.\n     */\n    private mergeOverride(flag: FeatureFlags, isActive: boolean, fallbackDescription: string): IFeatureFlag {\n        const current = this._flags.get(flag) ?? LocalFeatureFlags[flag];\n        return {\n            ...current,\n            description: current?.description ?? fallbackDescription,\n            group: current?.group ?? FeatureFlagGroups.CLIENT,\n            isActive,\n        };\n    }\n\n    /**\n     * @name applyConfiguredOverride\n     * Applies the persisted configured flags on top of every other source (highest priority).\n     * For each flag in the persisted configuration, sets `_flags` to the live entry with `isActive`\n     * replaced by the configured value (see `mergeOverride`). Non-configured flags are left\n     * untouched and `LocalFeatureFlags` is never mutated. A no-op when the configuration is empty\n     * (absent/corrupt/storage unavailable), and unreachable at all without `devTools`.\n     *\n     * Deliberately does NOT purge: the single-configuration invariant belongs to the write path\n     * (`setConfiguredFlags`). Purging from here destroyed data — in the portal/lobby flow `gameKey`\n     * is empty, so the key resolved to the bare prefix and every per-game configuration was deleted.\n     */\n    protected applyConfiguredOverride(): void {\n        const config = this.readPersistedConfig();\n        if (config.size === 0) return;\n\n        config.forEach((desiredActive, flag) => {\n            this._flags.set(flag, this.mergeOverride(flag, desiredActive, `Configured feature flag: ${flag}`));\n        });\n    }\n\n    /**\n     * @name getConfigStorageKey\n     * Builds the per-game local-storage key for the persisted configuration by suffixing\n     * `FEATURE_FLAGS_CONFIG_STORAGE_KEY` with the current game's `gameKey`, read at call time from\n     * the host config provider (which closes over the authoritative `Core.configuration.gameKey`,\n     * assigned from the load-game response before the per-game store is constructed). This scopes\n     * the configuration per game: a different game resolves a different key, so its flags do not\n     * leak across games.\n     *\n     * Returns `null` when no `gameKey` is available (the portal/lobby flow, or an unreadable host),\n     * and every caller treats `null` as \"no configuration in play\". It must NOT fall back to the\n     * bare prefix: that key is a prefix of every real key, so a purge keyed on it deleted all of\n     * them. Never throws — `readFlagsHostConfig` absorbs that.\n     */\n    protected getConfigStorageKey(): string | null {\n        const { gameKey } = readFlagsHostConfig();\n        return gameKey ? `${FEATURE_FLAGS_CONFIG_STORAGE_KEY}_${gameKey}` : null;\n    }\n\n    /**\n     * @name purgeOtherGameConfigs\n     * Enforces the single-configuration invariant: removes every persisted feature-flags\n     * configuration whose key belongs to the prefix family (`FEATURE_FLAGS_CONFIG_STORAGE_KEY*`)\n     * except `keepKey`. Called ONLY from `setConfiguredFlags`, i.e. only on an explicit Apply, so\n     * that at most one game's configuration ever exists in storage at a time. Iterates a snapshot of\n     * the keys (collected first) to avoid mutating `localStorage` while indexing it; total and\n     * non-throwing.\n     *\n     * `keepKey` is always a fully-qualified per-game key. Never pass the bare prefix: it is a prefix\n     * of every real key, so nothing would be kept.\n     */\n    protected purgeOtherGameConfigs(keepKey: string): void {\n        try {\n            const staleKeys: string[] = [];\n            for (let i = 0; i < window.localStorage.length; i++) {\n                const key = window.localStorage.key(i);\n                if (key !== null && key !== keepKey && key.startsWith(FEATURE_FLAGS_CONFIG_STORAGE_KEY)) {\n                    staleKeys.push(key);\n                }\n            }\n            staleKeys.forEach((key) => window.localStorage.removeItem(key));\n        } catch {\n            // storage unavailable → no-op, do not throw\n        }\n    }\n\n    /**\n     * @name readPersistedConfig\n     * Total, non-throwing read of the persisted configuration from `window.localStorage`.\n     * Parses the stored JSON inside a `try/catch` and keeps only entries whose key is a member\n     * of the `FeatureFlags` enum and whose value is a boolean (mirroring `assertKnown`\n     * defensiveness — unknown identifiers and non-boolean values never reach the store).\n     * Returns an empty map when no configuration is persisted, when the content is corrupt, or\n     * when storage is unavailable; it never throws.\n     */\n    protected readPersistedConfig(): Map<FeatureFlags, boolean> {\n        const result = new Map<FeatureFlags, boolean>();\n        try {\n            const storageKey = this.getConfigStorageKey();\n            if (storageKey === null) return result; // no gameKey → no configuration in play\n\n            const raw = window.localStorage.getItem(storageKey);\n            if (raw === null) return result;\n\n            const parsed = JSON.parse(raw) as Record<string, unknown>;\n            Object.entries(parsed).forEach(([key, value]) => {\n                if (Object.values(FeatureFlags).includes(key as FeatureFlags) && typeof value === 'boolean') {\n                    result.set(key as FeatureFlags, value);\n                }\n                // else: silently drop unknown key or non-boolean value\n            });\n        } catch {\n            return new Map(); // corrupt JSON / storage unavailable → empty config\n        }\n        return result;\n    }\n\n    /**\n     * @name getConfiguredFlags\n     * Read the persisted configured flags as a map of FeatureFlags → desired isActive.\n     * Delegates to `readPersistedConfig`, so it never throws and returns an empty map when no\n     * configuration is persisted, corrupt, or storage is unavailable. Does not mutate the current\n     * session's `_flags` or storage.\n     */\n    public getConfiguredFlags(): Map<FeatureFlags, boolean> {\n        return this.readPersistedConfig();\n    }\n\n    /**\n     * @name setConfiguredFlags\n     * Persist the configured-flags draft (overwriting any previous configuration) as a single\n     * enum-key→boolean record under the per-game storage key (see `getConfigStorageKey`), then\n     * purge every other game's persisted configuration so at most one config ever exists at a time\n     * (see `purgeOtherGameConfigs`). Does NOT mutate the current session's `_flags`; the\n     * configuration takes effect on the next load via `applyOverrides`. If storage is unavailable\n     * (e.g. incognito) the write is a no-op and no exception escapes.\n     */\n    public setConfiguredFlags(config: ReadonlyMap<FeatureFlags, boolean>): void {\n        try {\n            const storageKey = this.getConfigStorageKey();\n            if (storageKey === null) return; // no gameKey → nothing to scope a configuration to\n\n            const record: PersistedFlagsConfig = {};\n            config.forEach((isActive, flag) => {\n                record[flag] = isActive;\n            });\n            window.localStorage.setItem(storageKey, JSON.stringify(record));\n            this.purgeOtherGameConfigs(storageKey);\n        } catch {\n            // storage unavailable (e.g. incognito) → no-op, do not throw\n        }\n    }\n\n    /**\n     * @name clearConfiguredFlags\n     * Remove the persisted configuration entirely so no configured override is applied on the next\n     * load. Does NOT mutate the current session's `_flags`. Idempotent; if storage is unavailable\n     * the removal is a no-op and no exception escapes.\n     */\n    public clearConfiguredFlags(): void {\n        try {\n            const storageKey = this.getConfigStorageKey();\n            if (storageKey === null) return; // no gameKey → nothing scoped to clear\n            window.localStorage.removeItem(storageKey);\n        } catch {\n            // storage unavailable → no-op, do not throw\n        }\n    }\n}\n","// This module deliberately contains NO import statement. It is the seam that lets\n// `FeatureFlagsStore` read the two host values it needs without importing the `Core` singleton, so\n// the flag store stays a leaf and the `Core.ts` <-> flag-store import cycle stops existing. Adding\n// an import here — of any kind, from any package — reinstates that cycle by proxy.\n\n/** The only two host values the flags store reads. */\nexport interface IFlagsHostConfig {\n    readonly gameKey: string;\n    readonly devTools: boolean;\n}\n\n/**\n * Supplies the host values at call time. `Core` registers a closure over its own configuration, so\n * values assigned after the flag store is constructed are still seen.\n */\nexport type FlagsHostConfigProvider = () => IFlagsHostConfig;\n\n/** No provider, an unreadable host, or a throwing provider all resolve to this. */\nconst FAIL_CLOSED: IFlagsHostConfig = { gameKey: '', devTools: false };\n\nlet provider: FlagsHostConfigProvider | null = null;\n\n/** Called once by `Core`. Later calls replace the provider; there is no unregister. */\nexport function setFlagsHostConfigProvider(next: FlagsHostConfigProvider): void {\n    provider = next;\n}\n\n/**\n * Total and non-throwing. Normalises both fields so a partial object cannot leak through: an absent\n * or non-string `gameKey` reads as empty (no configuration key resolves) and a missing `devTools`\n * reads as false (the override channel stays shut). Fails closed by construction.\n */\nexport function readFlagsHostConfig(): IFlagsHostConfig {\n    if (provider === null) return FAIL_CLOSED;\n\n    try {\n        const config = provider();\n\n        return {\n            gameKey: typeof config?.gameKey === 'string' ? config.gameKey : '',\n            devTools: !!config?.devTools,\n        };\n    } catch {\n        return FAIL_CLOSED;\n    }\n}\n","import { Logger } from 'unicorn.console-logger';\nimport { LoggerGroups } from '../enums/LoggerGroups';\n\nexport function initAdvancedLog(location: string) {\n    const urlParams = new URLSearchParams(location);\n    const enableAdvancedLog = urlParams.get('advancedLog') === 'true';\n    if (enableAdvancedLog) {\n        Logger.init({ allowLogs: true });\n        Logger.openGroup(LoggerGroups.INIT);\n    }\n    return enableAdvancedLog;\n}\n","import { Container, DisplayObject, Graphics, Point } from 'pixi.js';\nimport Log from './Log';\n\n/**\n * Recalculates the position of a `DisplayObject` as if it were moved from its current parent container\n * to a new target container, returning the new local position relative to the target container.\n *\n * This is useful when you want to preserve the object's global position after changing its parent container.\n *\n * @param objectToMove - The display object whose position needs to be recalculated.\n * @param targetContainer - The container to which the object's position should be recalculated.\n * @returns The new local position (`Point`) of the object relative to the target container.\n */\nexport function recalculateObjectPositionInNewContainer(\n    objectToMove: DisplayObject,\n    targetContainer: Container,\n): Point {\n    const { parent, position }: { parent: Container; position: Point } = objectToMove;\n    if (!parent) {\n        throw new Error('objectToMove does not have a parent Container.');\n    }\n    const globalPosition: Point = parent.toGlobal(position);\n    const finalPosition: Point = targetContainer.toLocal(globalPosition);\n\n    return finalPosition;\n}\n\nexport function createPerformanceTimer(name: string = ''): () => void {\n    let startTime: number | null = null;\n    const innerName: string = name;\n    return () => {\n        if (startTime === null) {\n            startTime = performance.now();\n        } else {\n            const elapsed = performance.now() - startTime;\n            Log.colorfulLog(`Elapsed time ${innerName}: ${elapsed.toFixed()} ms`, '#black#yellow');\n            startTime = null;\n        }\n    };\n}\n\nexport function getDocumentCookie(str) {\n    const cookies = document.cookie;\n    if (!cookies) return false;\n\n    const match = cookies.split('; ').find((cookie) => cookie.startsWith(str + '='));\n\n    return match ? decodeURIComponent(match.split('=')[1]) : false;\n}\n\nexport function drawDebugPoint(x: number, y: number, color = 0xaa00ff, radius = 5): Graphics {\n    const gfx = new Graphics();\n    gfx.beginFill(color);\n    gfx.drawCircle(0, 0, radius);\n    gfx.endFill();\n    gfx.x = x;\n    gfx.y = y;\n    return gfx;\n}\n\n/**\n * Maximum delta (in seconds) that can be applied to a spine animation in a single frame.\n * Prevents animation jumps caused by tab-switch accumulation, GC pauses, or compositor stalls.\n * 100ms = the equivalent of a 10fps floor; any gap longer than this is clamped.\n * The clamp is applied AFTER the speed factor, so this ceiling holds at every playback speed.\n */\nconst MAX_DELTA_CLAMP = 0.1;\n\n/**\n * Computes the delta time (in seconds) for Spine animation updates,\n * using wall-clock time via performance.now() unconditionally.\n * This makes spine animation timing fully independent of the ticker's reported deltaMS\n * and stable across all display refresh rates (60Hz, 120Hz, 144Hz, 180Hz, 240Hz, VRR).\n *\n * The update frequency itself is governed by Stage.fps (100 normally, 30 under battery\n * saver); this function only converts the interval between successive calls into a delta.\n *\n * @param lastUpdateTime - The timestamp (ms) of the previous call, or 0 if first call / reset.\n * @param tickerDeltaMS - Used only as a first-frame fallback when lastUpdateTime is 0.\n *                        PIXI has already scaled it by Ticker.speed, so speedFactor is NOT\n *                        applied to it.\n * @param speedFactor - Pass Core.stage.ticker.speed. Scales wall-clock advancement so the\n *                      dev-tools 'f'/'g' hotkeys affect spine playback the same way they\n *                      affect GSAP and the ticker. 1 = normal speed.\n * @returns An object with `delta` (seconds) and `nextUpdateTime` (ms) to store for the next call.\n */\nexport function computeSpineDelta(\n    lastUpdateTime: number,\n    tickerDeltaMS: number,\n    speedFactor: number = 1,\n): { delta: number; nextUpdateTime: number } {\n    const now = performance.now();\n    if (lastUpdateTime === 0) {\n        // PIXI already folded Ticker.speed into deltaMS (elapsedMS capped at\n        // _maxElapsedMS, then multiplied by speed), so do not scale it again.\n        return { delta: Math.min(tickerDeltaMS / 1000, MAX_DELTA_CLAMP), nextUpdateTime: now };\n    }\n    const factor = speedFactor > 0 ? speedFactor : 0;\n    const scaledGap = ((now - lastUpdateTime) / 1000) * factor;\n    return { delta: Math.min(scaledGap, MAX_DELTA_CLAMP), nextUpdateTime: now };\n}\n\n/**\n * Creates a spine animation speed logger.\n * Tracks cumulative delta passed to spine.update() and reports total per wall-clock second.\n * A correct implementation will report ~1.0 regardless of display refresh rate.\n * Usage: private _logFPS = createSpineFPSLogger('SpineAnimations'); this._logFPS(delta);\n * delta = Math.min((now - lastUpdateTime) / 1000, MAX_DELTA_CLAMP);\n * lastUpdateTime = lastUpdateTime - The timestamp (ms) of the previous call, or 0 if first call / reset.\n * @param label - Console log prefix\n * @returns A function to call on every frame, passing the delta that was used for spine.update().\n */\nexport function createSpineFPSLogger(label: string = 'SpineAnimations'): (delta: number) => void {\n    let accumulatedDelta = 0;\n    let frameCount = 0;\n    let lastLogTime = 0;\n\n    return (delta: number) => {\n        frameCount++;\n        accumulatedDelta += delta;\n        const now = performance.now();\n        if (lastLogTime === 0) {\n            lastLogTime = now;\n        } else if (now - lastLogTime >= 1000) {\n            const wallClockElapsed = (now - lastLogTime) / 1000;\n            const speed = accumulatedDelta / wallClockElapsed;\n            // biome-ignore lint/suspicious/noConsole: <explanation>\n            console.log(\n                `[${label}] speed: ${speed.toFixed(3)}x | ticks: ${frameCount} | accumulated: ${accumulatedDelta.toFixed(3)}s / ${wallClockElapsed.toFixed(3)}s wall`,\n            );\n            accumulatedDelta = 0;\n            frameCount = 0;\n            lastLogTime = now;\n        }\n    };\n}\n","export default class DomHelpers {\n    /**\n     * Returns element with given id or document body if not found.\n     * @param {string} elementId - Element id.\n     * @returns {HTMLElement} Element or body.\n     */\n    public static getElementOrBody(elementId: string): HTMLElement {\n        const element = document.getElementById(elementId);\n\n        if (element !== null) {\n            return element;\n        } else {\n            return document.body;\n        }\n    }\n\n    /**\n     * Returns element wih given id. If not found, a new element is created and appended to specified container or document body.\n     * @param {string} elementId - Element id.\n     * @param {string} tagName - Tag name to create the element if not found.\n     * @param {Element} container - Container to append the new element. Defaults to document body.\n     * @returns {T} Element or a new one if not found.\n     */\n    public static getElementOrCreateNew<T extends HTMLElement>(\n        elementId: string,\n        tagName: string,\n        container?: Element | null,\n    ): T {\n        let element = document.getElementById(elementId);\n\n        if (element === null) {\n            element = document.createElement(tagName);\n            element.id = elementId;\n\n            container = container ? container : document.body;\n            container.appendChild(element);\n        }\n\n        return element as T;\n    }\n}\n","import Core, { BaseFeature } from '../Core';\nimport type BaseComponent from '../BaseComponent';\n\nexport interface IComponentLogEntry {\n    // 'Component Name': string;\n    // 'Component Type': string;\n    Mode: string;\n    // 'Has Mode': boolean;\n    'Layout Type': string;\n}\n\nexport const NOT_MIGRATE_TEXT: string = '!!! NOT MIGRATE !!!';\n\nexport function logGameComponents(logIntoConsole: boolean = true): any {\n    try {\n        const components: BaseComponent[] = Core.getGameComponents();\n        const features: BaseFeature[] = Core.getGameFeatures();\n        const layoutType: string = Core.gameLayout || 'N/A';\n\n        if (!components || components.length === 0) {\n            // biome-ignore lint/suspicious/noConsole: <explanation>\n            console.warn('[GameComponentsLogger] No components found.');\n            return;\n        }\n\n        const supportedLayouts = Core.getSupportedLayouts();\n\n        const componentTableData: Record<string, IComponentLogEntry> = {};\n        components.forEach((component) => {\n            const modeFactory = (component as any).modeFactory;\n            const modeType = modeFactory?.modeType;\n            const hasMode = modeType !== undefined && modeType !== null;\n            const key = component.componentType;\n\n            componentTableData[key] = {\n                // 'Component Name': component.componentName || component.constructor.name,\n                // 'Component Type': String(component.componentType ?? '-'),\n                Mode: hasMode ? String(modeType) : NOT_MIGRATE_TEXT,\n                // 'Has Mode': hasMode,\n                'Layout Type': layoutType,\n            };\n        });\n\n        const featureTableData: Record<string, IComponentLogEntry> = {};\n        features.forEach((features) => {\n            const modeFactory = (features as any).modeFactory;\n            const modeType = modeFactory?.modeType;\n            const hasMode = modeType !== undefined && modeType !== null;\n            const key = features.featureType;\n\n            featureTableData[key] = {\n                // 'Component Name': component.componentName || component.constructor.name,\n                // 'Component Type': String(component.componentType ?? '-'),\n                Mode: hasMode ? String(modeType) : NOT_MIGRATE_TEXT,\n                // 'Has Mode': hasMode,\n                'Layout Type': layoutType,\n            };\n        });\n\n        if (!logIntoConsole) {\n            return {\n                layoutType,\n                componentTableData,\n                featureTableData,\n            };\n        }\n\n        // biome-ignore lint/suspicious/noConsole: <explanation>\n        console.log(\n            `%c Game layout supporting: ${supportedLayouts}`,\n            'color: #ffa200; font-weight: bold; font-size: 12px;',\n        );\n\n        // biome-ignore lint/suspicious/noConsole: <explanation>\n        console.log(`%c Current layout: ${layoutType}`, 'color: #ffa200; font-weight: bold; font-size: 12px;');\n\n        // biome-ignore lint/suspicious/noConsole: <explanation>\n        console.groupCollapsed(\n            `%c Game Components: (${components.length} components | Layout: ${layoutType})`,\n            'color: #ffa200; font-weight: bold; font-size: 12px;',\n        );\n        // biome-ignore lint/suspicious/noConsole: <explanation>\n        console.table(componentTableData);\n        // biome-ignore lint/suspicious/noConsole: <explanation>\n        console.groupEnd();\n\n        // biome-ignore lint/suspicious/noConsole: <explanation>\n        console.groupCollapsed(\n            `%c Game Features: (${features.length} components | Layout: ${layoutType})`,\n            'color: #ffa200; font-weight: bold; font-size: 12px;',\n        );\n        // biome-ignore lint/suspicious/noConsole: <explanation>\n        console.table(featureTableData);\n        // biome-ignore lint/suspicious/noConsole: <explanation>\n        console.groupEnd();\n    } catch (error) {\n        // biome-ignore lint/suspicious/noConsole: <explanation>\n        console.error('[GameComponentsLogger] Error logging components:', error);\n    }\n}\n","import Core from '@egt/core';\nimport { BehaviorSubject, fromEvent } from 'rxjs';\nimport LifeCycle from '../enums/LifeCycle';\nimport { Logger } from 'unicorn.console-logger';\n\nexport default class Log {\n    public static readonly customConsole: BehaviorSubject<any> = new BehaviorSubject<any>({});\n    public static mobileDebug(s: any): void {\n        if (Core.configuration.devTools) {\n            let debugEl = document.getElementById('debugMobile') as HTMLDivElement;\n            if (!debugEl) {\n                debugEl = document.createElement('div');\n                debugEl.setAttribute('draggable', 'true');\n                debugEl.style.position = 'fixed';\n                debugEl.style.zIndex = '99999';\n                debugEl.style.top = '0';\n                debugEl.style.left = '0';\n                debugEl.style.width = '100%';\n                debugEl.style.height = '30%';\n                debugEl.style.backgroundColor = '#fff';\n                debugEl.style.color = '#000';\n                debugEl.style.overflow = 'auto';\n                // debugEl.style.whiteSpace = 'nowrap';\n                debugEl.id = 'debugMobile';\n                document.body.insertAdjacentElement('afterbegin', debugEl);\n                let x;\n                let y;\n                fromEvent(debugEl, 'dragstart').subscribe((e: any) => {\n                    y = e.pageY;\n                    x = e.pageX;\n                });\n                (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/core/src/egt/core/utils/Log.ts:32:17\",(debugEl),\"touchstart\"]), fromEvent(debugEl, 'touchstart')).subscribe((e: any) => {\n                    const evt = typeof e.originalEvent === 'undefined' ? e : e.originalEvent;\n                    const touch = evt.touches[0] || evt.changedTouches[0];\n                    y = touch.clientY;\n                    x = touch.clientX;\n                });\n                fromEvent(debugEl, 'touchmove').subscribe((e: any) => {\n                    const evt = typeof e.originalEvent === 'undefined' ? e : e.originalEvent;\n                    const touch = evt.touches[0] || evt.changedTouches[0];\n                    debugEl.style.left = touch.pageX - x + 'px';\n                    debugEl.style.top = touch.pageY - y + 'px';\n                });\n                fromEvent(document, 'dragover').subscribe((e: DragEvent) => {\n                    debugEl.style.left = e.clientX - x + 'px';\n                    debugEl.style.top = e.clientY - y + 'px';\n                });\n            }\n            if (debugEl) {\n                const today = new Date();\n                const time = today.getHours() + ':' + today.getMinutes() + ':' + today.getSeconds();\n                debugEl.innerHTML = '<b>' + time + '</b> ' + JSON.stringify(s) + '<br>' + debugEl.innerHTML;\n            }\n        }\n    }\n\n    public static server(text, source?: any): void {\n        source = source || 'Server';\n        if (Core.configuration.devTools) {\n            const isObject = this.isJsonStringOrObject(text);\n            if (isObject) {\n                text = this.toObject(text);\n            }\n            let eventCommand = isObject && text.event ? 'event: ' + text.event : '';\n            if (isObject && eventCommand === '' && text.jackpotStats) {\n                eventCommand = 'jpstats';\n            }\n            if (isObject && eventCommand === '' && text.balance) {\n                eventCommand = 'balance: ' + text.balance.balance;\n            }\n\n            if (Logger.allowLogs) {\n                const event = text.event ? text.event : '';\n                Logger.logServiceMessage([`${event}::`, text], source, 'log');\n            } else {\n                // biome-ignore lint/suspicious/noConsole: <explanation>\n                window.console.log(\n                    '%c ' + '[' + this.getTimeAsString() + ']' + '[SERVER]: ' + eventCommand + (isObject ? '' : text),\n                    'background-color: rgba(0, 0, 0, 0.8); padding:5px 2px; color: #4ED;',\n                    isObject ? text : '',\n                );\n            }\n            if (text.event !== 'gamble') {\n                if (\n                    !Core.configuration.devTools ||\n                    text.event === 'echo' ||\n                    text.event === 'jpstats' ||\n                    text.event === 'ingress' ||\n                    text.event === 'changeState'\n                ) {\n                    return;\n                }\n                Core.devTools?.consoleViewer?.jsonLog(\n                    '[' + this.getTimeAsString() + ']' + '[SERVER]: ' + eventCommand + (isObject ? '' : text),\n                    'padding:5px 2px; color: #4ED; font-size:10px;',\n                    isObject ? text : '',\n                    text,\n                );\n            }\n\n            Core.devTools?.consoleViewer?.updateScroll();\n            Log.customConsole.next({\n                content: text,\n                contentTitle: '[SERVER]: ' + eventCommand + ` [ ` + this.getTimeAsString() + ` ]`,\n            });\n            if (\n                !Core.configuration.devTools ||\n                text.event === 'echo' ||\n                text.event === 'jpstats' ||\n                text.event === 'ingress'\n            ) {\n                return;\n            }\n        }\n    }\n    /**\n     * Useful to print debug logs in the console. If the last argument is a string starting with '#', it will be used as a color.\n     * If the string contains two colors ('#color1#color2'), the first one will be used as the text color and the second one as the background color.\n     * There are also some predefined colors.\n     *\n     * @param args - The arguments to be printed in the console.\n     *\n     * Log.colorfulLog('TEST 1: ', 1, 'testString1', '#red');\n     *\n     * Log.colorfulLog('TEST 2: ', 2, 'testString2', '#red #green');\n     *\n     * Log.colorfulLog('TEST 3: ', 3, 'testString3', '#45b891');\n     *\n     * Log.colorfulLog('TEST 4: ', 4, 'testString4', '#b845b3 #45b891');\n     *\n     */\n    public static colorfulLog(...args): void {\n        const predefinedColors: Map<string, string> = new Map<string, string>([\n            ['red', '#ff0000'],\n            ['lightred', '#ff5454'],\n            ['green', '#069326'],\n            ['lightgreen', '#09ff41'],\n            ['blue', '#305fe4'],\n            ['lightblue', '#54f7ff'],\n            ['yellow', '#e4e130'],\n            ['orange', '#ffb82b'],\n            ['white', '#ffffff'],\n            ['purple', '#b845b3'],\n            ['grey', '#808080'],\n            ['black', '#000000'],\n            ['pink', '#ff00ff'],\n        ]);\n\n        const lastElement = args[args.length - 1];\n\n        let defaultColor: string = 'f5f208';\n        let backgroundColor: string = '000000';\n        let textOpacity: number = 1.0;\n        let backgroundOpacity: number = 1.0;\n\n        if (typeof lastElement === 'string' && lastElement.startsWith('#')) {\n            args.pop();\n\n            const lastElementArray: string[] = lastElement.split('#');\n            if (lastElementArray.length > 1) {\n                const predefinedColor: string | undefined = predefinedColors.get(lastElementArray[1].trim());\n                if (predefinedColor) {\n                    defaultColor = predefinedColor.slice(1);\n                } else {\n                    defaultColor = lastElementArray[1].trim();\n                }\n            }\n            if (lastElementArray.length > 2) {\n                const predefinedBackgroundColor: string | undefined = predefinedColors.get(lastElementArray[2].trim());\n                if (predefinedBackgroundColor) {\n                    backgroundColor = predefinedBackgroundColor.slice(1);\n                } else {\n                    backgroundColor = lastElementArray[2].trim();\n                }\n            }\n            if (lastElementArray.length > 3) {\n                textOpacity = parseFloat(lastElementArray[3].trim());\n            }\n            if (lastElementArray.length > 4) {\n                backgroundOpacity = parseFloat(lastElementArray[4].trim());\n            }\n        }\n\n        const label: string = args.shift();\n        // biome-ignore lint/suspicious/noConsole: <explanation>\n        window.console.log(\n            '%c' + label,\n            `background-color: rgba(${parseInt(backgroundColor.slice(0, 2), 16)}, ${parseInt(backgroundColor.slice(2, 4), 16)}, ${parseInt(backgroundColor.slice(4, 6), 16)}, ${backgroundOpacity}); padding:5px 2px; color: rgba(${parseInt(defaultColor.slice(0, 2), 16)}, ${parseInt(defaultColor.slice(2, 4), 16)}, ${parseInt(defaultColor.slice(4, 6), 16)}, ${textOpacity});`,\n            ...args,\n        );\n    }\n    public static logText(text): void {\n        Core.devTools?.consoleViewer?.log(\n            '[' + this.getTimeAsString() + ']' + '[USER]: User Log: ' + text,\n            'padding:5px 2.3em; color: #7E0; font-size:10px;',\n        );\n    }\n\n    public static client(text, source?: any): void {\n        source = source || 'Client';\n        if (Core.configuration.devTools) {\n            const isObject = this.isJsonStringOrObject(text);\n            if (isObject) {\n                text = this.toObject(text);\n            }\n\n            const eventCommand = isObject && text.event ? 'event: ' + text.event : '';\n            if (\n                !Core.configuration.devTools ||\n                text.event === 'echo' ||\n                text.event === 'jpstats' ||\n                text.event === 'ingress'\n            ) {\n                return;\n            }\n            Core.devTools?.consoleViewer?.jsonLog(\n                '[' + this.getTimeAsString() + ']' + '[CLIENT]: ' + eventCommand + (isObject ? '' : text),\n                'padding:5px 2px; color: #7E0; font-size:10px;',\n                isObject,\n                text,\n            );\n\n            Log.customConsole.next({\n                content: text,\n                contentTitle: '[CLIENT]: ' + eventCommand + ` [ ` + this.getTimeAsString() + ` ]`,\n            });\n\n            if (Logger.allowLogs) {\n                const event = text.event ? `${text.event}::` : '';\n                Logger.logServiceMessage([event, text], source);\n            } else {\n                // biome-ignore lint/suspicious/noConsole: <explanation>\n                window.console.log(\n                    '%c ' + '[' + this.getTimeAsString() + ']' + '[CLIENT]: ' + eventCommand + (isObject ? '' : text),\n                    'background-color: rgba(0, 0, 0, 0.8); padding:5px 2px; color: #7E0;',\n                    isObject ? text : '',\n                );\n            }\n\n            if (\n                !Core.configuration.devTools ||\n                text.event === 'echo' ||\n                text.event === 'jpstats' ||\n                text.event === 'ingress'\n            ) {\n                return;\n            }\n        }\n    }\n    public static memory(text, optionalText = ''): void {\n        const isObject = this.isJsonStringOrObject(text);\n        if (isObject) {\n            text = this.toObject(text);\n        }\n\n        // biome-ignore lint/suspicious/noConsole: <explanation>\n        window.console.log(\n            '%c ' + '[MEMORY][' + optionalText + ']: ' + (isObject ? '' : text),\n            'background-color: rgba(0, 0, 0, 0.8); padding:5px 2px; color: #ffcc00;',\n            isObject ? text : '',\n        );\n        if (Core.configuration.devTools) {\n            Core.devTools?.consoleViewer?.jsonLog(\n                '[MEMORY][' + optionalText + ']: ' + (isObject ? '' : text),\n                'padding:5px 2px; color: #ffcc00; font-size:10px;',\n                isObject,\n                text,\n            );\n        }\n    }\n\n    public static lifecycle(type: LifeCycle, text?: any): void {\n        if (Core.configuration.devTools) {\n            const isObject = this.isJsonStringOrObject(text);\n            if (isObject) {\n                text = this.toObject(text);\n            }\n\n            // biome-ignore lint/suspicious/noConsole: <explanation>\n            window.console.log(\n                '%c ' + '[LIFECYCLE]: ' + type,\n                'background-color: rgba(0, 0, 0, 0.8); padding:5px 2px; color: #ff66ff;',\n                isObject ? text : '',\n            );\n\n            if (Core.configuration.devTools) {\n                Core.devTools?.consoleViewer?.jsonLog(\n                    '[LIFECYCLE]: ' + type,\n                    'padding:5px 2px; color: #ff66ff; font-size:10px;',\n                    isObject ? '' : text,\n                    text,\n                );\n            }\n        }\n    }\n\n    public static error(text: string | object, source: any, data?: any): void {\n        const isObject = this.isJsonStringOrObject(text);\n        const args = [isObject ? 'Error data:' : text];\n        source = source || 'LOG.error()';\n        if (data) {\n            args.push(data);\n        }\n\n        if (isObject) {\n            text = this.toObject(text);\n        }\n\n        if (Logger.allowLogs) {\n            Logger.logServiceMessage(args, source, 'error');\n        } else {\n            // biome-ignore lint/suspicious/noConsole: <explanation>\n            window.console.error(\n                '%c ' + '[' + this.getTimeAsString() + ']' + '[ERROR]: ' + (isObject ? '' : text),\n                'background-color: rgba(0, 0, 0, 0.8); padding:5px 2px; color: #ff0000;',\n                isObject ? text : '',\n            );\n        }\n\n        if (Core.configuration.devTools) {\n            Core.devTools?.consoleViewer?.jsonLog(\n                '[' + this.getTimeAsString() + ']' + '[ERROR]: ' + (isObject ? '' : text),\n                'padding:5px 2px; color: #ff0000; ',\n                isObject,\n                text,\n            );\n        }\n    }\n\n    public static warn(message: string, source: any = 'LOG.warn()', data?: any): void {\n        if (Core.configuration.devTools) {\n            const args = [message];\n            if (data) {\n                args.push(data);\n            }\n\n            if (Logger.allowLogs) {\n                Logger.logServiceMessage(args, source, 'warn');\n            } else {\n                // biome-ignore lint/suspicious/noConsole: <explanation>\n                window.console.warn(...args);\n            }\n        }\n    }\n\n    public static debug(message: string, source?: any, data?: any): void {\n        const args = [message];\n        source = source || 'LOG.debug()';\n        if (data) {\n            args.push(data);\n        }\n        if (Core.configuration.devTools) {\n            if (Logger.allowLogs) {\n                Logger.logServiceMessage(args, source, 'log');\n            } else {\n                // biome-ignore lint/suspicious/noConsole: <explanation>\n                window.console.log(...args);\n            }\n\n            Core.devTools?.consoleViewer?.log(\n                '[' + this.getTimeAsString() + ']' + '[USER]: User Log: ' + JSON.stringify(args),\n                'padding:5px 2.3em; color: #7E0; font-size:10px;',\n            );\n            Core.devTools?.consoleViewer?.updateScroll();\n        }\n    }\n\n    public static table(args: any[], source?: any): void {\n        if (Core.configuration.devTools) {\n            source = source || 'LOG.table()';\n            Logger.logServiceMessage([`table:`, args], source, 'log');\n\n            // biome-ignore lint/suspicious/noConsole: <explanation>\n            window.console.table(...args);\n\n            Core.devTools?.consoleViewer?.log(\n                '[' + this.getTimeAsString() + ']' + '[USER]: User Log: ' + JSON.stringify(args),\n                'padding:5px 2.3em; color: #7E0; font-size:10px;',\n            );\n            Core.devTools?.consoleViewer?.updateScroll();\n        }\n    }\n\n    public static time(args: any[]): void {\n        if (Core.configuration.devTools) {\n            // biome-ignore lint/suspicious/noConsole: <explanation>\n            window.console.time(...args);\n        }\n    }\n\n    public static timeEnd(...args: any[]): void {\n        if (Core.configuration.devTools) {\n            // biome-ignore lint/suspicious/noConsole: <explanation>\n            window.console.timeEnd(...args);\n        }\n    }\n\n    private static getTimeAsString(): string {\n        const time = new Date();\n        return time.getHours() + ':' + time.getMinutes() + ':' + time.getSeconds();\n    }\n\n    private static isJsonStringOrObject(text: any): boolean {\n        if (typeof text === 'object') {\n            return true;\n        }\n        try {\n            text = JSON.parse(text);\n            return true;\n        } catch (_e) {\n            return false;\n        }\n    }\n\n    private static toObject(text: any): any {\n        if (typeof text === 'object') {\n            return text;\n        }\n        try {\n            const obj = JSON.parse(text);\n            return obj;\n        } catch (_e) {\n            return undefined;\n        }\n    }\n}\n","export type OverrideType = 'ModifyValue' | 'OverrideDefaultProperties';\n\nexport interface IRedundantOverrideRecord {\n    configurationClassName: string;\n    extendedConfigurationClassName?: string;\n    propertyKey: string;\n    path: string;\n    overrideType: OverrideType;\n    matchedLevel: string;\n    value: unknown;\n    marker?: string;\n}\n\nexport default class OverrideRedundancyReporter {\n    private static readonly seen: Set<string> = new Set<string>();\n    private static readonly pendingRecords: IRedundantOverrideRecord[] = [];\n    private static flushScheduled: boolean = false;\n\n    public static areEqual(first: unknown, second: unknown): boolean {\n        if (!this.isSafelyComparable(first) || !this.isSafelyComparable(second)) {\n            return false;\n        }\n        return this.stableStringify(first) === this.stableStringify(second);\n    }\n\n    public static isSafelyComparable(value: unknown): boolean {\n        if (value === null || typeof value === 'undefined') {\n            return true;\n        }\n\n        const valueType = typeof value;\n        if (valueType === 'string' || valueType === 'number' || valueType === 'boolean') {\n            return true;\n        }\n\n        if (Array.isArray(value)) {\n            return value.every((item) => this.isSafelyComparable(item));\n        }\n\n        if (this.isPlainObject(value)) {\n            return Object.values(value as Record<string, unknown>).every((item) => this.isSafelyComparable(item));\n        }\n\n        return false;\n    }\n\n    public static report(record: IRedundantOverrideRecord): void {\n        const signature = this.createSignature(record);\n        if (this.seen.has(signature)) {\n            return;\n        }\n\n        this.seen.add(signature);\n        this.pendingRecords.push(record);\n        this.scheduleFlush();\n    }\n\n    private static scheduleFlush(): void {\n        if (this.flushScheduled) {\n            return;\n        }\n\n        this.flushScheduled = true;\n\n        setTimeout(() => {\n            this.flushScheduled = false;\n            this.flush();\n        }, 0);\n    }\n\n    private static flush(): void {\n        if (!this.pendingRecords.length) {\n            return;\n        }\n\n        const byConfig = new Map<string, IRedundantOverrideRecord[]>();\n        for (const record of this.pendingRecords) {\n            if (!byConfig.has(record.configurationClassName)) {\n                byConfig.set(record.configurationClassName, []);\n            }\n            byConfig.get(record.configurationClassName)!.push(record);\n        }\n\n        const sortedConfigs = Array.from(byConfig.entries()).sort((a, b) => b[1].length - a[1].length);\n        const totalCount = this.pendingRecords.length;\n        const configCount = byConfig.size;\n\n        // biome-ignore lint/suspicious/noConsole: Runtime diagnostics for redundant overrides in devTools mode.\n        console.groupCollapsed(\n            `%c🚨 [Override Redundancy] ${totalCount} issue${totalCount !== 1 ? 's' : ''} in ${configCount} configuration${configCount !== 1 ? 's' : ''}`,\n            'color: #FF3B30; background: #2B2F36; padding: 2px 6px; border-radius: 3px; font-weight: 800;',\n        );\n\n        // biome-ignore lint/suspicious/noConsole: Runtime diagnostics for redundant overrides in devTools mode.\n        console.table(\n            sortedConfigs.map(([configName, records]) => ({\n                Configuration: configName,\n                Extends: records[0].extendedConfigurationClassName ?? '—',\n                Issues: records.length,\n            })),\n        );\n\n        for (const [configName, records] of sortedConfigs) {\n            const extendedFrom = records[0].extendedConfigurationClassName;\n            const configLabel = extendedFrom ? `${configName}  →  ${extendedFrom}` : configName;\n\n            // biome-ignore lint/suspicious/noConsole: Runtime diagnostics for redundant overrides in devTools mode.\n            console.groupCollapsed(`%c📦 ${configLabel}  (${records.length})`, 'color: #E6B450; font-weight: 700;');\n\n            const byProperty = new Map<string, IRedundantOverrideRecord[]>();\n            for (const record of records) {\n                if (!byProperty.has(record.propertyKey)) {\n                    byProperty.set(record.propertyKey, []);\n                }\n                byProperty.get(record.propertyKey)!.push(record);\n            }\n\n            for (const [propKey, propRecords] of Array.from(byProperty.entries())) {\n                // biome-ignore lint/suspicious/noConsole: Runtime diagnostics for redundant overrides in devTools mode.\n                console.groupCollapsed(`%c🔑 ${propKey}  (${propRecords.length})`, 'color: #7EC8E3; font-weight: 600;');\n\n                const fullMatches = propRecords.filter(\n                    (r) => r.marker === 'FULL_MATCH_OBJECT' || r.marker === 'FULL_MATCH_ARRAY',\n                );\n                const partialMatches = propRecords.filter((r) => r.marker === 'PARTIAL_KEYS_MATCH');\n                const leaves = propRecords.filter((r) => !r.marker);\n\n                if (fullMatches.length > 0) {\n                    // biome-ignore lint/suspicious/noConsole: Runtime diagnostics for redundant overrides in devTools mode.\n                    console.log(\n                        '%c❌ Entire object is redundant — safe to remove:',\n                        'color: #FF6B6B; font-weight: 600;',\n                    );\n                    // biome-ignore lint/suspicious/noConsole: Runtime diagnostics for redundant overrides in devTools mode.\n                    console.table(fullMatches.map((r) => ({ Path: r.path, Value: this.formatValue(r.value) })));\n                }\n\n                if (partialMatches.length > 0) {\n                    // biome-ignore lint/suspicious/noConsole: Runtime diagnostics for redundant overrides in devTools mode.\n                    console.log(\n                        '%c🔶 All specified keys match — entire section safe to remove:',\n                        'color: #FFA500; font-weight: 600;',\n                    );\n                    // biome-ignore lint/suspicious/noConsole: Runtime diagnostics for redundant overrides in devTools mode.\n                    console.table(partialMatches.map((r) => ({ Path: r.path, Value: this.formatValue(r.value) })));\n                }\n\n                if (leaves.length > 0) {\n                    // biome-ignore lint/suspicious/noConsole: Runtime diagnostics for redundant overrides in devTools mode.\n                    console.log(\n                        `%c⚠️ ${leaves.length} redundant field${leaves.length !== 1 ? 's' : ''} — remove from override:`,\n                        'color: #FFD166; font-weight: 600;',\n                    );\n                    // biome-ignore lint/suspicious/noConsole: Runtime diagnostics for redundant overrides in devTools mode.\n                    console.table(leaves.map((r) => ({ Path: r.path, Value: this.formatValue(r.value) })));\n                }\n\n                // biome-ignore lint/suspicious/noConsole: Runtime diagnostics for redundant overrides in devTools mode.\n                console.groupEnd();\n            }\n\n            // biome-ignore lint/suspicious/noConsole: Runtime diagnostics for redundant overrides in devTools mode.\n            console.groupEnd();\n        }\n\n        // biome-ignore lint/suspicious/noConsole: Runtime diagnostics for redundant overrides in devTools mode.\n        console.groupEnd();\n\n        this.pendingRecords.length = 0;\n    }\n\n    private static createSignature(record: IRedundantOverrideRecord): string {\n        return [\n            record.configurationClassName,\n            record.propertyKey,\n            record.path,\n            record.overrideType,\n            record.marker || '',\n            record.matchedLevel,\n            this.stableStringify(record.value),\n        ].join('|');\n    }\n\n    private static formatValue(value: unknown): string {\n        const serialized = this.stableStringify(value);\n        if (serialized.length <= 120) {\n            return serialized;\n        }\n        return `${serialized.slice(0, 117)}...`;\n    }\n\n    private static stableStringify(value: unknown): string {\n        return JSON.stringify(this.normalize(value));\n    }\n\n    private static normalize(value: unknown): unknown {\n        if (Array.isArray(value)) {\n            return value.map((item) => this.normalize(item));\n        }\n\n        if (value && typeof value === 'object') {\n            const normalizedObject = {};\n            Object.keys(value as Record<string, unknown>)\n                .sort()\n                .forEach((key) => {\n                    normalizedObject[key] = this.normalize((value as Record<string, unknown>)[key]);\n                });\n            return normalizedObject;\n        }\n\n        return value;\n    }\n\n    private static isPlainObject(value: unknown): boolean {\n        if (!value || typeof value !== 'object' || Array.isArray(value)) {\n            return false;\n        }\n\n        const proto = Object.getPrototypeOf(value);\n        return proto === Object.prototype || proto === null;\n    }\n}\n","import { IDynamicPosition, IModifiedDynamicPosition } from '../interfaces/IDynamicPosition';\nimport OverrideRedundancyReporter, { OverrideType } from './OverrideRedundancyReporter';\n\nexport interface IOverrideInspectionContext {\n    overrideType: OverrideType;\n    configurationClassName: string;\n    extendedConfigurationClassName?: string;\n    propertyKey: string;\n}\n\nexport default class RedundantOverrideInspector {\n    public static inspectModifyValue(\n        dataNew: IModifiedDynamicPosition<unknown>,\n        positionData: Record<string, unknown>,\n        context: IOverrideInspectionContext,\n    ): void {\n        const matchedLevel = this.getMatchedLevelLabel(\n            context.configurationClassName,\n            context.extendedConfigurationClassName,\n        );\n        this.collectRedundantLeafPaths(dataNew, positionData, [], (leafPath, value, marker) => {\n            OverrideRedundancyReporter.report({\n                configurationClassName: context.configurationClassName,\n                extendedConfigurationClassName: context.extendedConfigurationClassName,\n                propertyKey: context.propertyKey,\n                path: leafPath,\n                overrideType: context.overrideType,\n                matchedLevel,\n                value,\n                marker,\n            });\n        });\n    }\n\n    public static inspectOverrideDefaultProperties(\n        dataNew: IDynamicPosition<unknown>,\n        positionData: Record<string, unknown>,\n        context: IOverrideInspectionContext,\n    ): void {\n        const matchedLevel = this.getMatchedLevelLabel(\n            context.configurationClassName,\n            context.extendedConfigurationClassName,\n        );\n        const defaults = (positionData.defaults as Record<string, unknown>) || {};\n        const dataNewRecord = dataNew as unknown as Record<string, unknown>;\n\n        Object.keys(dataNewRecord).forEach((key) => {\n            if (!Object.prototype.hasOwnProperty.call(defaults, key)) {\n                return;\n            }\n\n            const hasOrientationSpecificValue = Object.keys(positionData).some(\n                (orientation) =>\n                    orientation !== 'defaults' &&\n                    positionData[orientation] &&\n                    typeof positionData[orientation] === 'object' &&\n                    Object.prototype.hasOwnProperty.call(positionData[orientation] as Record<string, unknown>, key),\n            );\n\n            if (hasOrientationSpecificValue) {\n                return;\n            }\n\n            if (!this.canCompare(dataNewRecord[key], defaults[key])) {\n                return;\n            }\n\n            if (OverrideRedundancyReporter.areEqual(dataNewRecord[key], defaults[key])) {\n                OverrideRedundancyReporter.report({\n                    configurationClassName: context.configurationClassName,\n                    extendedConfigurationClassName: context.extendedConfigurationClassName,\n                    propertyKey: context.propertyKey,\n                    path: key,\n                    overrideType: context.overrideType,\n                    matchedLevel,\n                    value: dataNewRecord[key],\n                });\n            }\n        });\n    }\n\n    private static getMatchedLevelLabel(configurationClassName: string, extendedFrom?: string): string {\n        if (extendedFrom && extendedFrom !== configurationClassName) {\n            return `inherits: ${extendedFrom}`;\n        }\n        return 'inherits: base';\n    }\n\n    private static collectRedundantLeafPaths(\n        overrideValue: unknown,\n        positionData: Record<string, unknown>,\n        path: string[],\n        onRedundantLeaf: (leafPath: string, value: unknown, marker?: string) => void,\n    ): void {\n        const arrayMatch = this.getArrayFullMatchResult(overrideValue, positionData, path);\n        if (arrayMatch.handled) {\n            if (arrayMatch.isFullMatch) {\n                onRedundantLeaf(path.join('.'), overrideValue, 'FULL_MATCH_ARRAY');\n            }\n            return;\n        }\n\n        if (this.isClassInstance(overrideValue)) {\n            return;\n        }\n\n        if (this.isPlainObject(overrideValue)) {\n            if (path.length > 0) {\n                const resolved = this.resolveHigherLevelValueForPath(positionData, path);\n                if (typeof resolved !== 'undefined') {\n                    if (\n                        this.canCompare(overrideValue, resolved) &&\n                        OverrideRedundancyReporter.areEqual(overrideValue, resolved)\n                    ) {\n                        onRedundantLeaf(path.join('.'), overrideValue, 'FULL_MATCH_OBJECT');\n                        return;\n                    }\n                    if (\n                        this.isPlainObject(resolved) &&\n                        this.allSpecifiedKeysMatch(\n                            overrideValue as Record<string, unknown>,\n                            resolved as Record<string, unknown>,\n                        )\n                    ) {\n                        onRedundantLeaf(path.join('.'), overrideValue, 'PARTIAL_KEYS_MATCH');\n                        return;\n                    }\n                }\n            }\n\n            Object.keys(overrideValue as Record<string, unknown>).forEach((key) => {\n                this.collectRedundantLeafPaths(\n                    (overrideValue as Record<string, unknown>)[key],\n                    positionData,\n                    path.concat(key),\n                    onRedundantLeaf,\n                );\n            });\n            return;\n        }\n\n        if (path.length === 0) {\n            return;\n        }\n\n        const resolved = this.resolveHigherLevelValueForPath(positionData, path);\n        if (typeof resolved === 'undefined') {\n            return;\n        }\n\n        if (!this.canCompare(overrideValue, resolved)) {\n            return;\n        }\n\n        if (OverrideRedundancyReporter.areEqual(overrideValue, resolved)) {\n            onRedundantLeaf(path.join('.'), overrideValue);\n        }\n    }\n\n    private static getArrayFullMatchResult(\n        overrideValue: unknown,\n        positionData: Record<string, unknown>,\n        path: string[],\n    ): { handled: boolean; isFullMatch: boolean } {\n        if (!Array.isArray(overrideValue) || path.length === 0) {\n            return { handled: false, isFullMatch: false };\n        }\n\n        const resolved = this.resolveHigherLevelValueForPath(positionData, path);\n        if (typeof resolved === 'undefined') {\n            return { handled: true, isFullMatch: false };\n        }\n\n        if (!this.canCompare(overrideValue, resolved)) {\n            return { handled: true, isFullMatch: false };\n        }\n\n        return {\n            handled: true,\n            isFullMatch: OverrideRedundancyReporter.areEqual(overrideValue, resolved),\n        };\n    }\n\n    private static resolveHigherLevelValueForPath(positionData: Record<string, unknown>, path: string[]): unknown {\n        const directValue = this.getValueAtPath(positionData, path);\n        if (typeof directValue !== 'undefined') {\n            return directValue;\n        }\n\n        return this.getFallbackValue(positionData, path);\n    }\n\n    private static getFallbackValue(positionData: Record<string, unknown>, path: string[]): unknown {\n        const [first, second, third, ...rest] = path;\n        if (!first || !second) {\n            return undefined;\n        }\n\n        if (first === 'landscape' || first === 'portrait' || first === 'desktop') {\n            return this.firstDefinedValue(positionData, [['defaults', second, ...rest]]);\n        }\n\n        if (first === 'features') {\n            const featureKey = second;\n            if (!third) {\n                return undefined;\n            }\n\n            if (third === 'landscape' || third === 'portrait' || third === 'desktop') {\n                const prop = rest[0];\n                const tail = rest.slice(1);\n                if (!prop) {\n                    return undefined;\n                }\n\n                return this.firstDefinedValue(positionData, [\n                    [third, prop, ...tail],\n                    ['features', featureKey, 'defaults', prop, ...tail],\n                    ['defaults', prop, ...tail],\n                ]);\n            }\n\n            if (third === 'defaults') {\n                const prop = rest[0];\n                const tail = rest.slice(1);\n                if (!prop) {\n                    return undefined;\n                }\n\n                return this.firstDefinedValue(positionData, [['defaults', prop, ...tail]]);\n            }\n        }\n\n        return undefined;\n    }\n\n    private static firstDefinedValue(positionData: Record<string, unknown>, candidates: string[][]): unknown {\n        for (const candidate of candidates) {\n            const value = this.getValueAtPath(positionData, candidate);\n            if (typeof value !== 'undefined') {\n                return value;\n            }\n        }\n\n        return undefined;\n    }\n\n    private static getValueAtPath(source: unknown, path: string[]): unknown {\n        let current = source;\n        for (const token of path) {\n            if (!current || typeof current !== 'object') {\n                return undefined;\n            }\n            current = (current as Record<string, unknown>)[token];\n        }\n        return current;\n    }\n\n    private static canCompare(first: unknown, second: unknown): boolean {\n        return (\n            OverrideRedundancyReporter.isSafelyComparable(first) &&\n            OverrideRedundancyReporter.isSafelyComparable(second)\n        );\n    }\n\n    private static isClassInstance(value: unknown): boolean {\n        if (!value || typeof value !== 'object' || Array.isArray(value)) {\n            return false;\n        }\n\n        const proto = Object.getPrototypeOf(value);\n        return proto !== Object.prototype && proto !== null;\n    }\n\n    private static allSpecifiedKeysMatch(\n        overrideValue: Record<string, unknown>,\n        resolved: Record<string, unknown>,\n    ): boolean {\n        const keys = Object.keys(overrideValue);\n        if (keys.length === 0) {\n            return false;\n        }\n        return keys.every((key) => {\n            const overrideVal = overrideValue[key];\n            const resolvedVal = resolved[key];\n            if (typeof resolvedVal === 'undefined') {\n                return false;\n            }\n            if (this.isPlainObject(overrideVal) && this.isPlainObject(resolvedVal)) {\n                return this.allSpecifiedKeysMatch(\n                    overrideVal as Record<string, unknown>,\n                    resolvedVal as Record<string, unknown>,\n                );\n            }\n            if (!this.canCompare(overrideVal, resolvedVal)) {\n                return false;\n            }\n            return OverrideRedundancyReporter.areEqual(overrideVal, resolvedVal);\n        });\n    }\n\n    private static isPlainObject(value: unknown): boolean {\n        if (!value || typeof value !== 'object' || Array.isArray(value)) {\n            return false;\n        }\n\n        const proto = Object.getPrototypeOf(value);\n        return proto === Object.prototype || proto === null;\n    }\n}\n","import Core from '@egt/core';\nimport { BangUpBitMapCurrencyText, BangUpBitMapText } from '@egt/ui-lib';\nimport { Spine } from 'pixi-spine';\nimport { Container } from 'pixi.js';\n\nexport default class SpineUseAnimatorSlotPosition {\n    public static useAnimatorSlotPosition(spine: Spine, slotName: string, container: Container): void {\n        const slotIndex: any = spine.skeleton.findSlotIndex(slotName);\n        const slotSum = spine.slotContainers[slotIndex];\n        slotSum.addChild(container);\n        slotSum.name = slotName;\n    }\n\n    public static setBangUpContainerPivotY(\n        bangUpContainer: Container,\n        moneyValueText: BangUpBitMapCurrencyText,\n        creditsValueText: BangUpBitMapText,\n    ): void {\n        const pivotY = Core.MONEY_MODE_IN_CREDITS.value\n            ? Math.round(creditsValueText.arrayDigits[0].height / 2) * -1\n            : Math.round(moneyValueText.arrayDigits[0].height / 2) * -1;\n        bangUpContainer.pivot.set(0, pivotY);\n    }\n}\n","import * as PIXI from 'pixi.js';\n\nexport function overrideTextMetrics() {\n    // Fix for the cases where the red background pixels are polluted intentionally\n    // with a different color, which causes the TextMetrics to calculate the wrong\n    // ascent, descent and fontSize values.\n    // Happens only on Safari and Firefox in private strict mode.\n\n    // This is the function used in PixiJS v.8+ to calculate the font metrics.\n    PIXI.TextMetrics.measureFont = (font) => {\n        // as this method is used for preparing assets, don't recalculate things if we don't need to\n        if (PIXI.TextMetrics._fonts[font]) {\n            return PIXI.TextMetrics._fonts[font];\n        }\n\n        const context = PIXI.TextMetrics._context;\n\n        context.font = font;\n        const metrics = context.measureText(PIXI.TextMetrics.METRICS_STRING + PIXI.TextMetrics.BASELINE_SYMBOL);\n\n        const properties = {\n            ascent: metrics.actualBoundingBoxAscent,\n            descent: metrics.actualBoundingBoxDescent,\n            fontSize: metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent,\n        };\n\n        PIXI.TextMetrics._fonts[font] = properties;\n        return properties;\n    };\n}\n","import gsap from 'gsap';\n\nexport default class Timers {\n    /** create timeout and store it */\n    public static setTimeout(handler: any, timeout: number): any {\n        const tweenId = gsap.delayedCall(timeout / 1000, () => {\n            this.timeouts.delete(tweenId);\n            handler();\n        });\n        this.timeouts.add(tweenId);\n        return tweenId;\n    }\n    /** clear single timeout */\n    public static clearTimeout(id: gsap.core.Tween): void {\n        // Log.debug('clearTimeout', id);\n        this.timeouts.delete(id);\n        if (id) {\n            id.kill();\n            // @ts-ignore\n            id = null;\n        }\n\n        // clearTimeout(id);\n    }\n    /** clear all timeouts */\n    public static clearTimeoutAll(): void {\n        // Log.debug('clearTimeout ALL');\n        this.timeouts.forEach((timeoutId) => {\n            this.clearTimeout(timeoutId);\n        });\n    }\n    /** returns true if timeout is still stored */\n    public static isActiveTimeout(id: gsap.core.Tween): boolean {\n        return this.timeouts.has(id);\n    }\n    /** create interval and store it */\n    public static setInterval(handler: any, timeout: number): any {\n        // const id = setInterval(handler, timeout);\n        const id = gsap.set(handler, {\n            delay: timeout / 1000,\n            onRepeat: handler,\n            repeat: -1,\n            repeatDelay: timeout / 1000,\n        });\n        this.intervals.add(id);\n        // Log.debug('setInterval', id);\n\n        return id;\n    }\n    /** clear single interval intervals */\n    public static clearInterval(id: gsap.core.Tween): void {\n        this.intervals.delete(id);\n        if (id) {\n            id.kill();\n            // @ts-ignore\n            id = null;\n        }\n        // Log.debug('clearInterval', id);\n    }\n    /** if id is post then stop this interval, in other case all intervals */\n    public static clearIntervalAll(): void {\n        // Log.debug('clearInterval ALL');\n        this.intervals.forEach((timeoutId) => {\n            this.clearInterval(timeoutId);\n        });\n    }\n    /** returns true if interval is still stored */\n    public static isActiveInterval(id: gsap.core.Tween): boolean {\n        return this.intervals.has(id);\n    }\n\n    private static timeouts: Set<gsap.core.Tween> = new Set<gsap.core.Tween>();\n    private static intervals: Set<gsap.core.Tween> = new Set<gsap.core.Tween>();\n}\n","const enum Align {\n    TOP_CENTER = 'top-center',\n    TOP_RIGHT = 'top-right',\n    TOP_LEFT = 'top-left',\n    MIDDLE_LEFT = 'middle-left',\n    MIDDLE = 'middle',\n    MIDDLE_RIGHT = 'middle-right',\n    BOTTOM_LEFT = 'bottom-left',\n    BOTTOM_CENTER = 'bottom-center',\n    BOTTOM_RIGHT = 'bottom-right',\n}\nexport default Align;\n","import { IAlignStrategy } from '../../interfaces/IAlignStrategy';\n\nexport class AlignBottomCenter implements IAlignStrategy {\n    public align(\n        width: number,\n        height: number,\n        containerWidth: number,\n        containerHeight: number,\n    ): { x: number; y: number } {\n        return {\n            x: Math.round(containerWidth / 2 - width / 2),\n            y: Math.round(containerHeight - height),\n        };\n    }\n}\n","import { IAlignStrategy } from '../../interfaces/IAlignStrategy';\n\nexport class AlignBottomLeft implements IAlignStrategy {\n    public align(\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        width: number,\n        height: number,\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        containerWidth: number,\n        containerHeight: number,\n    ): { x: number; y: number } {\n        return {\n            x: 0,\n            y: Math.round(containerHeight - height),\n        };\n    }\n}\n","import { IAlignStrategy } from '../../interfaces/IAlignStrategy';\n\nexport class AlignBottomRight implements IAlignStrategy {\n    public align(\n        width: number,\n        height: number,\n        containerWidth: number,\n        containerHeight: number,\n    ): { x: number; y: number } {\n        return {\n            x: Math.round(containerWidth - width),\n            y: Math.round(containerHeight - height),\n        };\n    }\n}\n","import { IAlignStrategy } from '../../interfaces/IAlignStrategy';\n\nexport class AlignMiddle implements IAlignStrategy {\n    public align(\n        width: number,\n        height: number,\n        containerWidth: number,\n        containerHeight: number,\n    ): { x: number; y: number } {\n        return {\n            x: Math.round(containerWidth / 2 - width / 2),\n            y: Math.round(containerHeight / 2 - height / 2),\n        };\n    }\n}\n","import { IAlignStrategy } from '../../interfaces/IAlignStrategy';\n\nexport class AlignMiddleLeft implements IAlignStrategy {\n    public align(\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        width: number,\n        height: number,\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        containerWidth: number,\n        containerHeight: number,\n    ): { x: number; y: number } {\n        return {\n            x: 0,\n            y: Math.round(containerHeight / 2 - height / 2),\n        };\n    }\n}\n","import { IAlignStrategy } from '../../interfaces/IAlignStrategy';\n\nexport class AlignMiddleRight implements IAlignStrategy {\n    public align(\n        width: number,\n        height: number,\n        containerWidth: number,\n        containerHeight: number,\n    ): { x: number; y: number } {\n        return {\n            x: Math.round(containerWidth - width),\n            y: Math.round(containerHeight / 2 - height / 2),\n        };\n    }\n}\n","import { IAlignStrategy } from '../../interfaces/IAlignStrategy';\nimport Align from './Align';\nimport { AlignBottomCenter } from './AlignBottomCenter';\nimport { AlignBottomLeft } from './AlignBottomLeft';\nimport { AlignBottomRight } from './AlignBottomRight';\nimport { AlignMiddle } from './AlignMiddle';\nimport { AlignMiddleLeft } from './AlignMiddleLeft';\nimport { AlignMiddleRight } from './AlignMiddleRight';\nimport { AlignTopCenter } from './AlignTopCenter';\nimport { AlignTopLeft } from './AlignTopLeft';\nimport { AlignTopRight } from './AlignTopRight';\n\nexport default class AlignStrategy {\n    private _alignStrategy: IAlignStrategy;\n\n    constructor(align?: Align) {\n        switch (align) {\n            case Align.TOP_CENTER:\n                this._alignStrategy = new AlignTopCenter();\n                break;\n\n            case Align.TOP_RIGHT:\n                this._alignStrategy = new AlignTopRight();\n                break;\n\n            case Align.MIDDLE_LEFT:\n                this._alignStrategy = new AlignMiddleLeft();\n                break;\n\n            case Align.MIDDLE:\n                this._alignStrategy = new AlignMiddle();\n                break;\n\n            case Align.MIDDLE_RIGHT:\n                this._alignStrategy = new AlignMiddleRight();\n                break;\n\n            case Align.BOTTOM_LEFT:\n                this._alignStrategy = new AlignBottomLeft();\n                break;\n\n            case Align.BOTTOM_CENTER:\n                this._alignStrategy = new AlignBottomCenter();\n                break;\n\n            case Align.BOTTOM_RIGHT:\n                this._alignStrategy = new AlignBottomRight();\n                break;\n\n            default:\n                this._alignStrategy = new AlignTopLeft();\n                break;\n        }\n    }\n\n    public getStrategy(): IAlignStrategy {\n        return this._alignStrategy;\n    }\n}\n","import { IAlignStrategy } from '../../interfaces/IAlignStrategy';\n\nexport class AlignTopCenter implements IAlignStrategy {\n    public align(\n        width: number,\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        height: number,\n        containerWidth: number,\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        containerHeight: number,\n    ): { x: number; y: number } {\n        return {\n            x: Math.round(containerWidth / 2 - width / 2),\n            y: 0,\n        };\n    }\n}\n","import { IAlignStrategy } from '../../interfaces/IAlignStrategy';\n\nexport class AlignTopLeft implements IAlignStrategy {\n    public align(\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        width?: number,\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        height?: number,\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        containerWidth?: number,\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        containerHeight?: number,\n    ): { x: number; y: number } {\n        return { x: 0, y: 0 };\n    }\n}\n","import { IAlignStrategy } from '../../interfaces/IAlignStrategy';\n\nexport class AlignTopRight implements IAlignStrategy {\n    public align(\n        width: number,\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        height: number,\n        containerWidth: number,\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        containerHeight: number,\n    ): { x: number; y: number } {\n        return {\n            x: Math.round(containerWidth - width),\n            y: 0,\n        };\n    }\n}\n","const enum Scale {\n    KEEP_ASPECT_RATIO = 'keep-aspect-ratio',\n    FULL_SIZE = 'full-size',\n    NONE = 'none',\n}\nexport default Scale;\n","import { IScaleStrategy } from '../../interfaces/IScaleStrategy';\n\nexport class ScaleFullSize implements IScaleStrategy {\n    public scale(\n        initialWidth: number,\n        initialHeight: number,\n        finalWidth: number,\n        finalHeight: number,\n    ): { scaleX: number; scaleY: number } {\n        return {\n            scaleX: finalWidth / initialWidth,\n            scaleY: finalHeight / initialHeight,\n        };\n    }\n}\n","import { IScaleStrategy } from '../../interfaces/IScaleStrategy';\n\nexport class ScaleKeepAspectRatio implements IScaleStrategy {\n    public scale(\n        initialWidth: number,\n        initialHeight: number,\n        finalWidth: number,\n        finalHeight: number,\n    ): { scaleX: number; scaleY: number } {\n        // Determine which screen dimension is most constrained\n        const scale = Math.min(finalWidth / initialWidth, finalHeight / initialHeight);\n\n        return { scaleX: scale, scaleY: scale };\n    }\n}\n","import { IScaleStrategy } from '../../interfaces/IScaleStrategy';\n\nexport class ScaleNone implements IScaleStrategy {\n    public scale(\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        initialWidth?: number,\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        initialHeight?: number,\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        finalWidth?: number,\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        finalHeight?: number,\n    ): { scaleX: number; scaleY: number } {\n        return {\n            scaleX: 1,\n            scaleY: 1,\n        };\n    }\n}\n","import { IScaleStrategy } from '../../interfaces/IScaleStrategy';\nimport Scale from './Scale';\nimport { ScaleFullSize } from './ScaleFullSize';\nimport { ScaleKeepAspectRatio } from './ScaleKeepAspectRatio';\nimport { ScaleNone } from './ScaleNone';\n\nexport default class ScaleStrategy {\n    private _scaleStrategy: IScaleStrategy;\n\n    constructor(scale?: Scale) {\n        switch (scale) {\n            case Scale.KEEP_ASPECT_RATIO:\n                this._scaleStrategy = new ScaleKeepAspectRatio();\n                break;\n\n            case Scale.FULL_SIZE:\n                this._scaleStrategy = new ScaleFullSize();\n                break;\n\n            default:\n                this._scaleStrategy = new ScaleNone();\n                break;\n        }\n    }\n    public getStrategy(): IScaleStrategy {\n        return this._scaleStrategy;\n    }\n}\n","import { BitmapText } from 'pixi.js';\n\nexport default class ScaleUntil {\n    public static scaleBitmapTextUntilFitInDimension(\n        text: BitmapText,\n        dimensionWidth: number,\n        scaleStep: number = 0.1,\n    ): void {\n        text.scale.set(1);\n        while (text.width > dimensionWidth) {\n            text.scale.set(text.scale.x - scaleStep);\n        }\n    }\n\n    public static computeTargetScaleForBitmapText(\n        text: BitmapText,\n        maxWidth: number,\n        maxHeight?: number,\n        paddingRatio: number = 1,\n        minScale: number = 0.3,\n    ): number {\n        const prevX = text.scale.x;\n        const prevY = text.scale.y;\n        text.scale.set(1);\n\n        const bounds = text.getLocalBounds();\n        const textWidth = Math.max(1, bounds.width);\n        const textHeight = Math.max(1, bounds.height);\n\n        const availableWidth = maxWidth * paddingRatio;\n        const availableHeight = maxHeight ? maxHeight * paddingRatio : Number.POSITIVE_INFINITY;\n\n        const scaleByWidth = Math.min(1, availableWidth / textWidth);\n        const scaleByHeight = maxHeight ? Math.min(1, availableHeight / textHeight) : 1;\n\n        const targetScale = Math.min(scaleByWidth, scaleByHeight);\n        const clamped = Math.max(minScale, targetScale);\n\n        text.scale.set(prevX, prevY);\n        return clamped;\n    }\n\n    public static applyScaleAndCenterBitmapText(\n        text: BitmapText,\n        maxWidth: number,\n        maxHeight?: number,\n        paddingRatio: number = 1,\n        minScale: number = 0.3,\n    ): number {\n        const targetScale = ScaleUntil.computeTargetScaleForBitmapText(\n            text,\n            maxWidth,\n            maxHeight,\n            paddingRatio,\n            minScale,\n        );\n        text.scale.set(targetScale);\n        const bounds = text.getLocalBounds();\n        text.pivot.set(bounds.width / 2, bounds.height / 2);\n        return targetScale;\n    }\n}\n","import Core from '@egt/core';\nimport { Container, Graphics, Ticker } from 'pixi.js';\nimport { injectable, singleton } from 'tsyringe';\n\n@injectable()\n@singleton()\nexport default class LoadingView extends Container {\n    public initialized: boolean = false;\n    private loadingBackground: Graphics;\n    private spinner: Graphics;\n    private percent: number = 0;\n    private backgroundColor: number = 0x000000;\n    private backgroundAlpha: number = 0.5;\n    private spinnerColor: number = 0xffffff;\n    private spinnerStroke: number = 4;\n    private spinnerAlpha: number = 1;\n    private spinnerRadius: number = 50;\n    private animationPercentageSetting: number = 1000;\n    private spinnerRotationStep: number = 0.12;\n    private animationFn: any;\n\n    constructor() {\n        super();\n    }\n\n    public initLoading(): void {\n        if (this.initialized) {\n            return;\n        }\n        const width: number = Core.display.stage.width;\n        const height: number = Core.display.stage.height;\n\n        this.loadingBackground = new Graphics()\n            .beginFill(this.backgroundColor, this.backgroundAlpha)\n            .drawRect(0, 0, width, height)\n            .endFill();\n        this.addChild(this.loadingBackground);\n\n        this.spinner = new Graphics();\n        this.spinner.x = this.loadingBackground.width / 2;\n        this.spinner.y = this.loadingBackground.height / 2;\n        this.addChild(this.spinner);\n\n        this.visible = false;\n        this.interactive = true;\n\n        Core.LOADING_ASSETS.subscribe(this.onAssetsLoading.bind(this));\n\n        Core.ORIENTATION.subscribe(this.setOrientation.bind(this));\n        this.initialized = true;\n    }\n\n    private setOrientation(): void {\n        this.loadingBackground.width = Core.display.stage.width;\n        this.loadingBackground.height = Core.display.stage.height;\n        this.spinner.x = this.loadingBackground.width / 2;\n        this.spinner.y = this.loadingBackground.height / 2;\n    }\n\n    private onAssetsLoading(loadingAssets: boolean): void {\n        this.visible = loadingAssets;\n        if (loadingAssets) {\n            this.animationFn = this.animateSpinner.bind(this);\n            Ticker.shared.add(this.animationFn);\n        } else {\n            Ticker.shared.remove(this.animationFn);\n        }\n    }\n\n    private animateSpinner(): void {\n        this.spinner.rotation += this.spinnerRotationStep;\n        this.spinner\n            .clear()\n            .lineStyle(this.spinnerStroke, this.spinnerColor, this.spinnerAlpha)\n            .moveTo(this.spinnerRadius, 0)\n            .arc(0, 0, this.spinnerRadius, 0, Math.PI * 2 * this.percent, false);\n        this.percent = Math.abs(Math.sin(Date.now() / this.animationPercentageSetting));\n    }\n}\n","import { BaseModesConfigurations, IForceSetConfig, IModes } from '@egt/core';\nimport { FreeSpinFeatureConfigurationFactoryBlurred } from './modes/blurred/configuration/FreeSpinFeatureConfigurationBlurred';\n// import { FreeSpinFeatureConfigurationFactorySided } from './modes/sided/configuration/FreeSpinFeatureConfigurationSided';\nimport { FreeSpinFeatureConfigurationFactoryDefault } from './modes/default/configuration/FreeSpinFeatureConfigurationDefault';\nimport FreeSpinControllerDefault from './modes/default/controllers/FreeSpinControllerDefault';\nimport FreeSpinMessageBarView from './modes/default/views/FreeSpinMessageBarView';\nimport FreeSpinViewDefault from './modes/default/views/FreeSpinViewDefault';\n\nexport interface IFreeSpinMode extends IModes {\n    secondView?: any;\n}\n\nexport default class FreeSpinModesConfigurations extends BaseModesConfigurations<FreeSpinModes> {\n    constructor(modeType: FreeSpinModes, forceSetConfig?: IForceSetConfig) {\n        super(modeType, forceSetConfig);\n    }\n\n    protected createBaseModesConfig(modeType: FreeSpinModes): IFreeSpinMode {\n        switch (modeType) {\n            case FreeSpinModes.BLURRED:\n                return {\n                    view: FreeSpinViewDefault,\n                    controller: FreeSpinControllerDefault,\n                    secondView: FreeSpinMessageBarView,\n                    configuration: FreeSpinFeatureConfigurationFactoryBlurred(),\n                };\n            default:\n                return {\n                    view: FreeSpinViewDefault,\n                    controller: FreeSpinControllerDefault,\n                    secondView: FreeSpinMessageBarView,\n                    configuration: FreeSpinFeatureConfigurationFactoryDefault(),\n                };\n        }\n    }\n}\n\nexport enum FreeSpinModes {\n    DEFAULT = 'default',\n    BLURRED = 'blurred',\n}\n","import Core, { AssetPriority, BaseFeature, IModeConfig, Log } from '@egt/core';\nimport { Features, GameState, ISlotConfiguration, RootView, UIState, ZOrders } from '@egt/slot';\nimport { Lifecycle } from 'tsyringe';\nimport FreeSpinModesConfigurations, { FreeSpinModes, IFreeSpinMode } from './FreeSpinFactory';\nimport { FreeSpinFeatureConfigurationFactoryBlurred } from './modes/blurred/configuration/FreeSpinFeatureConfigurationBlurred';\nimport { FreeSpinFeatureConfigurationFactoryDefault } from './modes/default/configuration/FreeSpinFeatureConfigurationDefault';\nimport FreeSpinViewDefault from './modes/default/views/FreeSpinViewDefault';\nimport FreeSpinControllerDefault from './modes/default/controllers/FreeSpinControllerDefault';\nimport FreeSpinStore from './modes/default/stores/FreeSpinStore';\nimport FreeSpinMessageBarView from './modes/default/views/FreeSpinMessageBarView';\nimport { IFreeSpinFeatureConfiguration } from './interfaces/IFreeSpinFeatureConfiguration';\n\nexport default class FreeSpinFeature extends BaseFeature {\n    public FREE_SPIN_VIEW: FreeSpinViewDefault;\n    public featureType: Features = Features.FREE_SPINS;\n    public configurationName = 'FreeSpinFeature';\n    protected mainAssetID: any = 'freespin';\n\n    private gameSettings: any;\n    private freespinController: FreeSpinControllerDefault;\n    private freeSpinStore: FreeSpinStore;\n\n    private configuration: IFreeSpinFeatureConfiguration;\n\n    constructor(\n        // private classType: any,\n        // private fsMessageBarView?: any,\n        modeConfig: IModeConfig,\n        _mainAssetsID?: any,\n    ) {\n        super();\n        if (_mainAssetsID) {\n            this.mainAssetID = _mainAssetsID;\n        }\n        const baseConfigs = {\n            [FreeSpinModes.DEFAULT]: FreeSpinFeatureConfigurationFactoryDefault,\n            [FreeSpinModes.BLURRED]: FreeSpinFeatureConfigurationFactoryBlurred,\n        };\n\n        this.modeFactory = this.initMode<FreeSpinModesConfigurations>(modeConfig, {\n            defaultModeType: FreeSpinModes.DEFAULT,\n            baseConfigs,\n            defaultFactory: FreeSpinModesConfigurations,\n        });\n    }\n\n    public onInitComplete(_view: any): void {\n        this.freespinController.onInitComplete();\n    }\n    public destroy(): void {\n        this.freespinController.destroy();\n\n        // @ts-ignore\n        this.FREE_SPIN_VIEW = null;\n\n        // @ts-ignore\n        this.freespinController = null;\n\n        // @ts-ignore\n        this.freeSpinStore = null;\n        this.gameSettings = null;\n        // @ts-ignore\n        this.dependencyContainer = null;\n\n        // @ts-ignore\n        this.mainAssetID = null;\n\n        super.destroy();\n    }\n\n    // initial state\n    public onGameSettings(gameSettings: any): void {\n        this.freeSpinStore = new FreeSpinStore();\n        this.gameSettings = gameSettings;\n        // analyze initial state if we are in freespin\n        const freespin = this.gameSettings.game?.state?.rounds?.find((round) => round.type === 'FREESPIN');\n        if (this.gameSettings.state === GameState.FREESPIN) {\n            this.freeSpinStore.initialNumberOfFreeSpins = freespin?.count;\n            this.freeSpinStore.finishedNumberOfFreeSpins = freespin?.count - freespin?.remain;\n            this.freeSpinStore.state = UIState.FREESPIN;\n            this.freeSpinStore.comeFromRefresh = true;\n        } else if (this.gameSettings.game && this.gameSettings.game.state && this.gameSettings.game.state.rounds) {\n            if (freespin && freespin.remain > 0) {\n                this.freeSpinStore.initialNumberOfFreeSpins = freespin.count;\n                this.freeSpinStore.finishedNumberOfFreeSpins = freespin.count - freespin.remain;\n                this.freeSpinStore.state = 'CREATE';\n            }\n        } else {\n            this.freeSpinStore.state = UIState.UNSET;\n        }\n        // IN CASE OF LAST FREESPIN IN RESPIN - WE DO NOT RECEIVE\n        // FROM SERVER BONUS FREESPIN AND WE KNOW ONLY FROM STATE\n        if (this.freeSpinStore.state === UIState.UNSET && this.gameSettings.state === GameState.FREERESPIN) {\n            this.freeSpinStore.state = 'CREATE';\n            const megaRespin = this.gameSettings.game.state.rounds.find((round) => round.type === 'MEGA_RESPIN');\n            if (megaRespin && freespin) {\n                this.freeSpinStore.initialNumberOfFreeSpins = freespin.count;\n                this.freeSpinStore.finishedNumberOfFreeSpins = freespin.count - freespin.remain;\n            } else {\n                this.freeSpinStore.initialNumberOfFreeSpins = -1;\n            }\n        }\n\n        // IN CASE OF LAST FREESPIN IN MEGARESPIN\n        if (this.freeSpinStore.state === UIState.UNSET && this.gameSettings.state === GameState.MEGARESPIN) {\n            if (freespin) {\n                this.freeSpinStore.initialNumberOfFreeSpins = freespin.count;\n                this.freeSpinStore.finishedNumberOfFreeSpins = freespin.count - freespin.remain;\n                this.freeSpinStore.state = UIState.WAITING_FOR_RESPONSE_IN_FREESPIN;\n            }\n        }\n\n        // IN CASE OF LAST FREESPIN IN PICK\n        if (this.freeSpinStore.state === UIState.UNSET && this.gameSettings.state === GameState.PICK) {\n            if (freespin && freespin.remain === 0) {\n                this.freeSpinStore.initialNumberOfFreeSpins = freespin.count;\n                this.freeSpinStore.finishedNumberOfFreeSpins = freespin.count - freespin.remain;\n                // this.freeSpinStore.state = UIState.WAITING_FOR_RESPONSE;\n            }\n        }\n    }\n\n    public onGameStarted(): void {\n        Log.debug('FREE SPIN onGameStarted', this.constructor.name);\n        this.freespinController.onGameStarted();\n    }\n\n    public onRegisterDependencies(container: any): void {\n        super.onRegisterDependencies(container);\n        const mode = this.mode as IFreeSpinMode;\n        if (!this.dependencyContainer.isRegistered('FreeSpinController')) {\n            this.dependencyContainer.register(\n                'FreeSpinController',\n                { useClass: mode.controller },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n\n        this.dependencyContainer.register('FreeSpinView', { useClass: mode.view }, { lifecycle: Lifecycle.Singleton });\n\n        this.dependencyContainer.register(\n            'FreeSpinFeatureConfiguration',\n            { useClass: mode.configuration },\n            { lifecycle: Lifecycle.Singleton },\n        );\n\n        this.dependencyContainer.register(\n            'FreeSpinMessageBarView',\n            { useClass: mode.secondView || FreeSpinMessageBarView },\n            { lifecycle: Lifecycle.Singleton },\n        );\n        this.dependencyContainer.registerInstance('FreeSpinStore', this.freeSpinStore);\n    }\n\n    public onResolveDependencies(_container: any): void {\n        this.freespinController = this.dependencyContainer.resolve('FreeSpinController');\n        this.FREE_SPIN_VIEW = this.dependencyContainer.resolve('FreeSpinView');\n        this.configuration = this.dependencyContainer.resolve('FreeSpinFeatureConfiguration');\n        this.freespinController.ready = this.ready.bind(this);\n    }\n\n    public onInitialRender(rootView: RootView): void {\n        // rootView.addChildAt(this.FREE_SPIN_VIEW, rootView.getChildIndex(rootView.popupVisualizer) + 1);\n        this.FREE_SPIN_VIEW.zIndex = ZOrders.POPUP_LEVEL + 1;\n        rootView.addChild(this.FREE_SPIN_VIEW);\n    }\n\n    public onIndividualAssetLoaded(asset: any): void {\n        super.onIndividualAssetLoaded.apply(this, arguments);\n        if (asset.asset.id === 'freeSpinsSounds') {\n            this.freespinController?.onSoundLoadedEvent();\n        }\n    }\n\n    public onPrepareResources(): void {\n        if (!this.configuration) {\n            this.configuration = this.dependencyContainer.resolve('FreeSpinFeatureConfiguration');\n        }\n        const game = this.gameSettings.game;\n        let priority: AssetPriority = AssetPriority.NORMAL;\n\n        if (game && game.state && game.state.rounds) {\n            const rounds = this.gameSettings.game.state.rounds;\n            if (rounds && rounds.length && rounds.find((round) => round.type === 'FREESPIN')) {\n                priority = AssetPriority.HIGHEST;\n            }\n        }\n\n        const freeSpinAssets = this.configuration?.assets?.toArray?.() || [];\n\n        freeSpinAssets.forEach((asset) => {\n            asset.priority = priority;\n        });\n\n        Core.assets.addAssets(freeSpinAssets);\n\n        const config: ISlotConfiguration = this.dependencyContainer.resolve('ISlotConfiguration');\n\n        if (config.freespinElements) {\n            const definedFSAsset: any = config.assets.find((element) => {\n                return element.id === this.mainAssetID;\n            });\n\n            if (!definedFSAsset) {\n                Core.assets.addAssets([\n                    {\n                        id: 'freespin',\n                        url:\n                            '../assets/' +\n                            Core.configuration.gameKey +\n                            '/freespin/freespin_' +\n                            Core.configuration.language.toLowerCase() +\n                            '.json',\n                        priority,\n                        type: 'texture',\n                    },\n                ]);\n            } else {\n                Core.assets.addAssets([\n                    {\n                        id: 'freespin',\n                        url: definedFSAsset.url,\n                        priority,\n                        type: 'texture',\n                    },\n                ]);\n            }\n        } else {\n            Core.assets.addAssets([\n                {\n                    id: 'freespin',\n                    url: '../assets/' + Core.configuration.gameKey + '/freespin/freespin.json',\n                    priority,\n                    type: 'texture',\n                },\n            ]);\n        }\n\n        if (config.freespinSpine) {\n            const spinePriority: AssetPriority = priority === AssetPriority.HIGHEST ? priority : AssetPriority.HIGH;\n            Core.assets.addAssets([\n                {\n                    id: 'freespinSpine',\n                    url: '../assets/' + Core.configuration.gameKey + '/freespin/freespinSpine.json',\n                    priority: spinePriority,\n                    hasDesktopVersion: config.freespinSpineDesktop,\n                    type: 'texture',\n                },\n            ]);\n        }\n\n        Core.assets.addAssets([\n            {\n                id: 'freeSpinTranslate',\n                url:\n                    '../assets/features/slot/free-spins/common/translations/' +\n                    Core.configuration.language.toLowerCase() +\n                    '.json',\n                priority,\n                type: 'translation',\n            },\n        ]);\n\n        // set highest priorty (we are in freespin) for all mainAssets send in cunstructor\n        // the reason: we use more than usually files for freespin in JWSlot game\n        if (priority === AssetPriority.HIGHEST && Array.isArray(this.mainAssetID)) {\n            this.mainAssetID.forEach((assetyId) => {\n                const asset = config.assets.find((element) => {\n                    return element.id === assetyId;\n                });\n                if (asset) {\n                    asset.priority = AssetPriority.HIGHEST;\n                }\n            });\n        }\n    }\n}\n","import FreeSpinFeature from './FreeSpinFeature';\nimport FreeSpinControllerDefault from './modes/default/controllers/FreeSpinControllerDefault';\nimport FreeSpinType from './modes/default/enums/FreeSpinType';\nimport FreeSpinStore from './modes/default/stores/FreeSpinStore';\nimport FreeSpinMessageBarView from './modes/default/views/FreeSpinMessageBarView';\nimport FreeSpinViewDefault from './modes/default/views/FreeSpinViewDefault';\nimport { FreeSpinModes } from './FreeSpinFactory';\nimport FreeSpinsFeatureConfigurationBlurred from './modes/blurred/configuration/FreeSpinFeatureConfigurationBlurred';\nimport FreeSpinsFeatureConfigurationDefault from './modes/default/configuration/FreeSpinFeatureConfigurationDefault';\nimport { IFreeSpinFeatureConfiguration } from './interfaces/IFreeSpinFeatureConfiguration';\n\nconst FreeSpinController = FreeSpinControllerDefault; //TODO: remove this after all features will be migrated to use Factory functions for controllers and configurations\nconst FreeSpinView = FreeSpinViewDefault; //TODO: remove this after all features will be migrated to use Factory functions for controllers and configurations\n\nexport {\n    FreeSpinFeature,\n    FreeSpinViewDefault,\n    FreeSpinView,\n    FreeSpinStore,\n    FreeSpinControllerDefault,\n    FreeSpinController,\n    FreeSpinMessageBarView,\n    FreeSpinType,\n    FreeSpinModes,\n    FreeSpinsFeatureConfigurationBlurred,\n    FreeSpinsFeatureConfigurationDefault,\n    IFreeSpinFeatureConfiguration,\n};\nexport default FreeSpinFeature;\n","import Core, { AssetPriority, AssetsCollection, BaseComponentConfiguration, DefaultAssets } from '@egt/core';\nimport { IFreeSpinFeatureConfiguration } from '../../../interfaces/IFreeSpinFeatureConfiguration';\n\nexport default class FreeSpinsFeatureConfigurationBlurred extends BaseComponentConfiguration {}\nexport function FreeSpinFeatureConfigurationFactoryBlurred(): any {\n    class FreeSpinsFeatureConfigurationBlurredInternalClass\n        extends FreeSpinsFeatureConfigurationBlurred\n        implements IFreeSpinFeatureConfiguration\n    {\n        @DefaultAssets([\n            {\n                id: 'freeSpinMainResources',\n                url: '../assets/' + Core.configuration.gameKey + '/freespin/modes/blurred/freeSpinMainResources.json',\n                priority: AssetPriority.LOW,\n                hasDesktopVersion: true,\n                type: 'texture',\n            },\n        ])\n        public assets: AssetsCollection;\n    }\n\n    return FreeSpinsFeatureConfigurationBlurredInternalClass;\n}\n","import { AssetsCollection, BaseComponentConfiguration, DefaultAssets } from '@egt/core';\nimport { IFreeSpinFeatureConfiguration } from '../../../interfaces/IFreeSpinFeatureConfiguration';\nexport default class FreeSpinsFeatureConfigurationDefault extends BaseComponentConfiguration {}\nexport function FreeSpinFeatureConfigurationFactoryDefault(): any {\n    class FreeSpinsFeatureConfigurationDefaultInternalClass\n        extends FreeSpinsFeatureConfigurationDefault\n        implements IFreeSpinFeatureConfiguration\n    {\n        @DefaultAssets([\n            // {\n            //     id: 'freeSpinMainResources',\n            //     url:\n            //         '../assets/' +\n            //         Core.configuration.gameKey +\n            //         '/freespin/modes/default/freeSpinMainResources.json',\n            //     priority: AssetPriority.LOW,\n            //     hasDesktopVersion: true,\n            //     type: 'texture',\n            // },\n        ])\n        public assets: AssetsCollection;\n    }\n\n    return FreeSpinsFeatureConfigurationDefaultInternalClass;\n}\n","import Core, { BaseController, Timers } from '@egt/core';\nimport {\n    BangupActionConsts,\n    BetResponse,\n    Features,\n    GameState,\n    ISlotConfiguration,\n    InitialSettings,\n    RootStore,\n    SlotComponents,\n    SpinAnalyzer,\n    UIState,\n    ZOrders,\n} from '@egt/slot';\nimport { ButtonStates } from '@egt/ui-lib';\nimport { UIViewDefault } from '@egt/ui-view';\nimport { Subject, merge } from 'rxjs';\nimport { filter, take, takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { Machine, assign, interpret } from 'xstate';\nimport FreeSpinStore from '../stores/FreeSpinStore';\nimport FreeSpinViewDefault from '../views/FreeSpinViewDefault';\n\n@injectable()\nexport default class FreeSpinControllerDefault extends BaseController {\n    public ready: () => Promise<void>;\n    public waitingForUserAction: boolean = false;\n    public hideIntroViaKeyboard: boolean = false;\n    public hideAutoplayBetoptionButtons: boolean = false;\n    protected stateMachineService;\n    protected clearFeatureEvents = new Subject();\n    // biome-ignore lint/correctness/noUndeclaredVariables: <explanation>\n    protected waitingSoundTimeout: gsap.core.Tween;\n    // biome-ignore lint/correctness/noUndeclaredVariables: <explanation>\n    protected spinTimeout: gsap.core.Tween;\n    protected stateMachine;\n\n    constructor(\n        @inject('FreeSpinView') protected view: FreeSpinViewDefault,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('FreeSpinStore') protected freeSpinStore: FreeSpinStore,\n        @inject('UIView') protected uiView: UIViewDefault,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('ISlotConfiguration') public slotConfiguration: ISlotConfiguration,\n        @inject('SpinAnalyzer') protected spinAnalyzer: SpinAnalyzer,\n    ) {\n        super(view);\n    }\n    public onInitComplete(): void {\n        this.createStateMachine();\n        this.view.onInitComplete();\n        this.view.stateMachineService = this.stateMachineService;\n    }\n\n    // caled once from feature when game and root controler / view is loaded\n    public onGameStarted(): void {\n        this.rootStore.subjects.REELS_STOPPED.chainSubscribe(Features.FREE_SPINS, () => {\n            this.stateMachineService.send('START_FEATURE');\n        });\n\n        this.rootStore.subjects.SECONDARY_BAR_VISIBLE.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onShowHideBar.bind(this),\n        );\n        this.rootStore.subjects.FEATURE_FINISHED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onFeatureFinished.bind(this),\n        );\n\n        this.rootStore.subjects.KEY_UP.pipe(takeUntil(this.DESTROY)).subscribe((e: KeyboardEvent) => {\n            this.stateMachineService.send('ON_KEY_RELEASED', { e });\n        });\n\n        this.rootStore.subjects.FEATURE_COMPLETE.pipe(\n            filter((f) => f === Features.COIN),\n            takeUntil(this.DESTROY),\n        ).subscribe((_value) => {\n            this.stateMachineService.send('COIN_FEATURE_SKIPPED');\n        });\n        this.rootStore.domainStore.BET.pipe(takeUntil(this.DESTROY)).subscribe((betResponse) => {\n            this.stateMachineService.send('ON_BET', { betResponse });\n        });\n\n        this.rootStore.subjects.RESTORE.chainSubscribe(Features.FREE_SPINS, () => {\n            this.stateMachineService.send('ON_RESTORE');\n        });\n\n        this.uiView.stopButton.CLICK.pipe(\n            filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n            takeUntil(this.DESTROY),\n        ).subscribe(() => {\n            this.stateMachineService.send('ON_STOP_CLICKED');\n        });\n\n        // if (this.freeSpinStore.comeFromRefresh) {\n        //     this.rootStore.subjects.FEATURE_STARTED.next(Features.FREE_SPINS);\n        // }\n\n        this.stateMachineService.send('START_FEATURE');\n    }\n\n    public destroy(): void {\n        this.stateMachineService.stop();\n        this.stateMachineService = null;\n        this.stateMachine = null;\n        super.destroy();\n    }\n\n    public onSoundLoadedEvent(): void {\n        this.stateMachineService.send('SOUND_LOADED');\n    }\n    // caled once from feature when sound asset for FS is loaded\n    public onSoundLoaded(context, event): void {\n        if (context.state !== UIState.FREESPIN || Core.ON_GAME_PAUSED.value !== 'NONE') {\n            return;\n        }\n\n        if (this.isIntro(context, event)) {\n            Core.sounds.play('pressStartSound');\n        } else {\n            Core.sounds.play('freeSpinsBackgroundSound', true);\n        }\n    }\n    // next come from UIController\n\n    protected onSpinClickedInIntro(_context, _event): void {\n        this.uiView.spinButton.state = ButtonStates.Disabled;\n\n        this.rootStore.uiStore.CLEAR_BANG_UP.next();\n\n        this.stateMachineService.send('START_FREE_SPIN');\n    }\n\n    protected onStopClicked(context, _event): void {\n        if (context.state === UIState.FREESPIN || this.onForceStopLastSpin()) {\n            this.rootStore.subjects.REELS_STOP_ALL.next();\n        }\n        if (this.rootStore.uiStore.BANGUP_RUNNING.value && this.rootStore.domainStore.currentSpinResults > 0) {\n            this.rootStore.subjects.BEFORE_SPIN.next();\n        }\n    }\n\n    protected onBet(context, event): void {\n        // fs state - check first, retriger or update\n        const betResponse = event.betResponse;\n        const newContext = { ...context };\n        newContext.freeSpinBonus = false;\n        newContext.state = betResponse.state;\n        newContext.numberOfSpinsToExclude = 0;\n        if (\n            betResponse.freespin &&\n            !betResponse.restoreResponse &&\n            this.rootStore.domainStore.SERVER_STATE.value === GameState.FREESPIN &&\n            this.rootStore.domainStore.currentSpinResults === 0\n        ) {\n            if (\n                this.rootStore.domainStore.SPIN_MODE.value === Features.FREE_SPINS &&\n                context.initialNumberOfFreeSpins < betResponse.freespin.count\n            ) {\n                newContext.freeSpinBonus = true;\n                newContext.retriggeredNumberOfFreeSpins = betResponse.freespin.count - context.initialNumberOfFreeSpins;\n                newContext.numberOfSpinsToExclude = newContext.retriggeredNumberOfFreeSpins;\n            }\n            newContext.initialNumberOfFreeSpins = betResponse.freespin.count;\n\n            this.rootStore.subjects.SPIN_BUTTON_SPECIAL_TEXT_VISIBLE.next(false);\n            this.rootStore.domainStore.SPIN_MODE.next(Features.FREE_SPINS);\n\n            newContext.finishedNumberOfFreeSpins = betResponse.freespin.count - betResponse.freespin.remain;\n        }\n        newContext.comeFromRefresh = false;\n        this.stateMachineService.send('UPDATE_STATE', { context: newContext });\n    }\n\n    protected spin(): void {\n        Timers.clearTimeout(this.spinTimeout);\n        Core.sounds.setVolume('freeSpinsBackgroundSound', 1);\n        if (\n            this.rootStore.uiStore.STATE.value === UIState.FREESPIN ||\n            this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT_IN_FREE_SPINS\n        ) {\n            if (this.rootStore.domainStore.currentSpinResults === 0) {\n                // this.rootStore.uiStore.SHOW_SETTINGS.next(false);\n                this.rootStore.subjects.CLOSE_ALL_POPUPS.next();\n                this.rootStore.subjects.BEFORE_SPIN.next();\n                this.rootStore.subjects.SPIN_STARTED.next();\n                this.stateMachineService.send('SPIN');\n                this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_RESPONSE_IN_FREESPIN);\n                this.rootStore.domainStore.bet();\n                Core.sounds.play('spinSound');\n            } else {\n                this.processNextResultFromSpin();\n            }\n        }\n    }\n\n    // passed from the view to move on after Retrigger animation\n    protected onRetriggerFinished(context): void {\n        // if (!this.view.doNotUseStandartMessageBar) {\n        this.rootStore.subjects.SECONDARY_BAR_VISIBLE.next(true);\n        this.view.fsMessageBar.visible = true;\n        // }\n        this.rootStore.uiStore.STATE.next(UIState.FREESPIN);\n        if (Core.sounds.getSoundDuration('freeSpinsSounds', 'retriggerSound') > 0) {\n            Core.sounds.play('freeSpinsBackgroundSound', true);\n        }\n        this.rootStore.domainStore.SPIN_MODE.next(Features.FREE_SPINS);\n        context.numberOfSpinsToExclude = 0;\n        this.stepFeatureUpdate();\n    }\n\n    protected isMaxWinLimitHit(): boolean {\n        return this.rootStore.subjects.MAX_WIN_LIMIT_HIT.value && this.rootStore.domainStore.currentSpinResults === 0;\n    }\n\n    protected isOutro(context, _event): boolean {\n        return (\n            (context.initialNumberOfFreeSpins > 0 || context.initialNumberOfFreeSpins === -1) &&\n            (context.state === UIState.WIN ||\n                context.state === UIState.BONUS_SUMMARY ||\n                context.state === UIState.MYSTERY ||\n                context.state === UIState.PRIZE_POP) &&\n            this.rootStore.domainStore.currentSpinResults === 0\n        );\n    }\n\n    protected onForceStopLastSpin(): boolean {\n        return this.rootStore.domainStore.betResponse && this.rootStore.domainStore.betResponse.freespin?.remain === 0;\n    }\n\n    // passed from the view to move on after Intro animation\n    protected onIntroFinished(context, _event): void {\n        context.introFinished = true;\n        this.waitingForUserAction = false;\n        this.hideIntroViaKeyboard = false;\n        // this.stateMachineService.send('UPDATE_STATE', { context: { state: FreeSpinState.UPDATE } });\n        this.rootStore.uiStore.STATE.next(UIState.FREESPIN);\n        this.rootStore.uiStore.FAKE_REELS.next(this.rootStore.subjects.FREE_SPINS_FAKE_REELS.value);\n        Core.sounds.stopAll(context?.skipSoundsStop || []);\n        this.rootStore.uiStore.BACKGROUND_SOUND_PLAY.next({ sound: undefined, ms: 0 });\n        Core.sounds.play('freeSpinsBackgroundSound');\n        this.stateMachineService.send('WIN_VISUALIZATION_FINISHED');\n        this.rootStore.subjects.SPIN_BUTTON_SPECIAL_TEXT_VISIBLE.next(false);\n    }\n\n    // passed from the view to move on after Outro animation\n    protected onOutroFinished(context): void {\n        this.addPrizePopSoundsToSkip(context);\n        Core.sounds.stopAll(context?.skipSoundsStop || []);\n        context.initialNumberOfFreeSpins = 0;\n        context.finishedNumberOfFreeSpins = 0;\n        context.retriggeredNumberOfFreeSpins = 0;\n        this.rootStore.uiStore.BACKGROUND_SOUND_PLAY.next({ sound: 'backgroundMusic', ms: 400 });\n        // destroy events which are relative only when feature is running\n        this.clearFeatureEvents.next();\n        this.view.visible = false;\n        this.view.fsAnimations.alpha = 1;\n        if (!this.rootStore.isCampaignServerState) {\n            this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_COLLECT);\n        }\n        this.rootStore.subjects.SPIN_BUTTON_SPECIAL_TEXT_VISIBLE.next(false);\n        this.rootStore.domainStore.SPIN_MODE.next(Features.MANUAL_SPIN);\n        this.rootStore.uiStore.FAKE_REELS.next(this.rootStore.subjects.FAKE_REELS.value);\n        this.rootStore.subjects.FEATURE_COMPLETE.next(Features.FREE_SPINS);\n        this.rootStore.subjects.SPIN_BUTTON_SPECIAL_TEXT_VISIBLE.next(true);\n    }\n\n    protected onRestore(context, _event): void {\n        let comeFromFreeSpin: any[] = [];\n        if (this.rootStore.domainStore.betResponse && this.rootStore.domainStore.betResponse.restoreResponse) {\n            comeFromFreeSpin = this.rootStore.domainStore.betResponse.restoreResponse.bonuses.filter(\n                (bonus) => bonus.type === 'FREESPIN',\n            );\n        }\n        if (\n            this.rootStore.domainStore.SERVER_STATE.value === GameState.FREESPIN ||\n            this.rootStore.domainStore.SERVER_STATE.value === GameState.FREERESPIN\n        ) {\n            this.rootStore.uiStore.drawNow = true;\n            this.rootStore.uiStore.FAKE_REELS.next(this.rootStore.subjects.FREE_SPINS_FAKE_REELS.value);\n            this.rootStore.uiStore.REAL_REELS.next(this.rootStore.domainStore.betResponse.restoreResponse.reels);\n            this.rootStore.subjects.TINT_REELS.next(false);\n            const newContext = { ...context };\n            this.rootStore.subjects.SPIN_BUTTON_SPECIAL_TEXT_VISIBLE.next(false);\n            this.rootStore.domainStore.SPIN_MODE.next(Features.FREE_SPINS);\n\n            const freespin = this.rootStore.domainStore.betResponse.freespin;\n            if (freespin) {\n                newContext.initialNumberOfFreeSpins = freespin.count;\n                newContext.finishedNumberOfFreeSpins = freespin.count - freespin.remain;\n            }\n\n            const freeSpinBonus = this.rootStore.domainStore.betResponse.bonuses.find(\n                (bonus) => bonus.type === 'FREESPIN',\n            );\n\n            newContext.state = UIState.FREESPIN;\n\n            if (freeSpinBonus && freeSpinBonus.count) {\n                newContext.freeSpinBonus = true;\n                newContext.retriggeredNumberOfFreeSpins = freeSpinBonus.count;\n            }\n            if (context.finishedNumberOfFreeSpins > 0 || context.initialNumberOfFreeSpins === -1) {\n                this.rootStore.subjects.SECONDARY_BAR_VISIBLE.next(true);\n\n                newContext.numberOfSpinsToExclude = newContext.retriggeredNumberOfFreeSpins;\n            }\n            this.stateMachineService.send('UPDATE_STATE', { context: newContext });\n            this.stateMachineService.send('START_FEATURE');\n        } else if (\n            !this.rootStore.domainStore.betResponse ||\n            (this.rootStore.domainStore.betResponse?.state !== UIState.WIN &&\n                this.rootStore.domainStore.betResponse?.state !== UIState.BONUS_SUMMARY) ||\n            (context.restorePoint !== 'FREERESPIN' &&\n                (comeFromFreeSpin.length === 0 || this.rootStore.subjects.MAX_WIN_LIMIT_HIT.value))\n        ) {\n            // DO NOT MAKE RESTORE IF\n            // LAST FREESPIN_RESPIN NO WIN\n            // ALSO FOR JACKPOT WON IN LAST FREESPIN\n            // WAIT FOR OUTRO VISIBLE\n            this.rootStore.subjects.RESTORE.executorComplete();\n        }\n    }\n\n    protected showIntro(context, event?): void {\n        if (this.waitingSoundTimeout) {\n            Timers.clearTimeout(this.waitingSoundTimeout);\n        }\n\n        let duration: number;\n        if (context?.comeFromRefresh) {\n            duration = 0;\n        } else if (event?.type === 'COIN_FEATURE_SKIPPED') {\n            duration = 500;\n        } else if (this.rootStore.isGreatWin && !this.rootStore.uiStore.BANGUP_RUNNING.value) {\n            // In case of preceding BigWin, don't wait for the winScatterFs to finish, since it will be already played\n            duration = 200;\n        } else {\n            duration = Core.sounds.getSoundDuration('winSounds', 'winScatterFs');\n        }\n\n        this.waitingSoundTimeout = Timers.setTimeout(() => {\n            // if (!this.rootStore.subjects.ACTIVE_FEATURE.value.includes(Features.BASE_FREE_SPINS)) {\n            //     this.rootStore.subjects.FEATURE_STARTED.next(Features.FREE_SPINS);\n            // }\n            this.stateMachineService.send('SHOW_FREE_SPIN');\n            this.rootStore.uiStore.CLEAR_BANG_UP.next();\n            this.view.prestart();\n            this.waitingForUserAction = true;\n            this.toggleSpinSkipButton();\n        }, duration);\n    }\n\n    protected stepFeatureIntro(context): void {\n        this.addFeatureEvents();\n        this.rootStore.uiStore.BACKGROUND_SOUND_PLAY.next({ sound: undefined, ms: 0 });\n\n        // set win from scatters\n        const betResponse: BetResponse = this.rootStore.domainStore.betResponse;\n        if (betResponse) {\n            const win = betResponse.bonusGamesTotalWinAmount || betResponse.totalWinAmount;\n            if (win > 0) {\n                this.rootStore.uiStore.WIN.next({\n                    amount: win,\n                    action: BangupActionConsts.BANGUP,\n                    feature: Features.FREE_SPINS,\n                });\n            }\n        }\n\n        this.rootStore.uiStore.STATE.next(UIState.FREESPIN);\n        // start button vizualize after scatters sound\n        if (!this.rootStore.subjects.ACTIVE_FEATURE.value.includes(Features.COIN)) {\n            this.showIntro(context);\n        }\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'betPlusBtn',\n            actions: ['visible', 'enabled'],\n            values: [true, false],\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'betMinusBtn',\n            actions: ['visible', 'enabled'],\n            values: [true, false],\n        });\n    }\n\n    protected stepFeatureUpdate(_context?): void {\n        this.rootStore.domainStore.currentSpinResults > 0 ? this.setCurrentWin() : this.setWin();\n        this.rootStore.uiStore.STATE.next(UIState.FREESPIN);\n        if (this.rootStore.domainStore.betResponse.totalWinAmount && this.rootStore.uiStore.BANGUP_RUNNING.value) {\n            this.rootStore.uiStore.BANGUP_RUNNING.pipe(take(2)).subscribe(() => {\n                if (!this.rootStore.uiStore.BANGUP_RUNNING.value) {\n                    this.stateMachineService.send('WIN_VISUALIZATION_FINISHED');\n                }\n            });\n\n            if (Core.hasComponent(SlotComponents.BACKGROUND_SOUND)) {\n                // Get the fade out configuration based on the win sound\n                const winSound = this.spinAnalyzer.getHighestPayingSymbolSound(\n                    this.rootStore.domainStore.betResponse.entries,\n                );\n                const config = Core.sounds.getBGSoundConfiguration().freeSpinsBackgroundSound;\n                const soundConfig = config[winSound] ? config[winSound] : config.default;\n\n                // Keep the volume of the background up, for wins, without winSound\n                const shouldSyncBGSound = Core.sounds.getBGSoundConfiguration().syncCreditSoundWithBgSound;\n                if (\n                    shouldSyncBGSound &&\n                    (winSound === 'creditAnimationSound' || winSound === 'fsCreditAnimationSound')\n                ) {\n                    return;\n                }\n\n                // Fade out the fs bg\n                Core.sounds.fadeOutSound(\n                    'freeSpinsBackgroundSound',\n                    soundConfig.fadeOut.duration,\n                    soundConfig.fadeOut.volume,\n                );\n            } else {\n                Core.sounds.setVolume('freeSpinsBackgroundSound', 0.2);\n            }\n        } else {\n            this.stateMachineService.send('WIN_VISUALIZATION_FINISHED');\n        }\n    }\n\n    protected stepFeatureRetrigger(context, event): void {\n        this.addFeatureEvents();\n        this.setWin();\n        context.freeSpinBonus = false;\n\n        this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_RESPONSE);\n\n        let winSoundDuration: number = 0;\n        let soundName: string = '';\n\n        if (this.rootStore.uiStore.winSoundPlaying.length > 0) {\n            Core.sounds.setVolume('freeSpinsBackgroundSound', 0.2);\n            // WAIT UNTIL WIN ANIMATION END\n            const sound: string =\n                this.rootStore.uiStore.winSoundPlaying.indexOf('fullLine') !== -1 ? 'mainSounds' : 'winSounds';\n            winSoundDuration = Core.sounds.getSoundDuration(sound, this.rootStore.uiStore.winSoundPlaying);\n            soundName = this.rootStore.uiStore.winSoundPlaying;\n        }\n        if (soundName === 'creditAnimationSound' || soundName === 'coinFeatureSound') {\n            this.rootStore.uiStore.BANGUP_RUNNING.pipe(take(2)).subscribe(() => {\n                if (!this.rootStore.uiStore.BANGUP_RUNNING.value) {\n                    Timers.setTimeout(() => {\n                        this.view.startRetrigger(context, event);\n                    }, 1000);\n                }\n            });\n        } else if (\n            // if Core.hasComponent(SlotComponents.BACKGROUND_SOUND) - it is sync between\n            // creditAnimationSound and BackgroundSound\n            // this means the creditAnimationSound is very long - then hardcode 1000\n            // instead sound duration\n            (soundName === 'winScatterFs' && this.rootStore.isGreatWin) ||\n            (Core.hasComponent(SlotComponents.BACKGROUND_SOUND) &&\n                Core.sounds.getBGSoundConfiguration()?.syncCreditSoundWithBgSound)\n        ) {\n            Timers.setTimeout(() => {\n                this.rootStore.uiStore.CLEAR_BANG_UP.next();\n                this.view.startRetrigger(context, event);\n            }, 1000);\n        } else {\n            Timers.setTimeout(() => {\n                this.rootStore.uiStore.CLEAR_BANG_UP.next();\n                this.view.startRetrigger(context, event);\n            }, winSoundDuration);\n        }\n    }\n\n    protected stepFeatureOutro(context, _event): void {\n        this.addFeatureEvents();\n\n        if (this.rootStore.domainStore.betResponse && this.rootStore.domainStore.betResponse.totalWinAmount > 0) {\n            Core.sounds.setVolume('freeSpinsBackgroundSound', 0.2);\n        }\n\n        const totalWin = this.rootStore.domainStore.betResponse.overflow\n            ? 0\n            : this.rootStore.domainStore.betResponse.bonusGamesTotalWinAmount;\n        if (totalWin > 0) {\n            this.setWin();\n        }\n        // Delay the stop of the freespin mode to let the user see the reels of his final bet.\n        const startOutro = (tWin: number): void => {\n            this.rootStore.subjects.STOP_COIN_FEATURE_FROM_OTHER_FEATURE.next();\n            this.view.startOutro(tWin);\n        };\n\n        // call startOutro immedialtly if no win from the last spin or when bagup finished\n        if (this.rootStore.domainStore.betResponse.totalWinAmount > 0 && this.rootStore.uiStore.BANGUP_RUNNING.value) {\n            // take(2) because the first handler will be called immediatly with current value = true\n            this.rootStore.uiStore.BANGUP_RUNNING.pipe(take(2)).subscribe(() => {\n                if (!this.rootStore.uiStore.BANGUP_RUNNING.value) {\n                    Timers.setTimeout(async () => {\n                        startOutro(totalWin);\n                    }, 1000);\n                }\n            });\n        } else {\n            Timers.setTimeout(async () => {\n                startOutro(totalWin);\n            }, 2000);\n        }\n\n        context.totalWin = totalWin;\n        this.stateMachineService.send('UPDATE_STATE', context);\n    }\n\n    protected onOutroVisible(context, _event): void {\n        this.view.destroyFreeSpinBar();\n        this.outroUIButtonsState();\n\n        // this.uiView.stopButton.state = ButtonStates.Disabled;\n        context.introFinished = false;\n        this.waitingForUserAction = false;\n        this.hideIntroViaKeyboard = false;\n        this.stateMachineService.send('UPDATE_STATE', { context: { state: UIState.UNSET } });\n        this.rootStore.subjects.SECONDARY_BAR_VISIBLE.next(false);\n        if (this.rootStore.domainStore.betResponse.restoreResponse) {\n            this.rootStore.uiStore.CLEAR_LINES.next();\n        }\n        this.rootStore.subjects.FEATURE_FINISHED.next(Features.FREE_SPINS);\n        this.rootStore.subjects.BUY_BONUS_AND_DOUBLE_CHANCE_VISIBLE.next(ZOrders.MESSAGES_LEVEL + 3);\n        this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_BTN_VISIBLE.next(true);\n        const betResponse: BetResponse = this.rootStore.domainStore.betResponse;\n        // TO DO: find a clever way to find correct fs entry\n        const freeSpinScatterEntry = betResponse.restoreResponse.entries[0];\n        let win = 0;\n        let winAmount = 0;\n        const freeSpinFeatureWin = betResponse.rounds?.filter(\n            (bonus) => bonus.type === 'FREESPIN' || bonus.type === 'FREERESPIN',\n        );\n        freeSpinFeatureWin.forEach((bonus) => {\n            win += bonus.totalWin;\n            winAmount += bonus.totalWinAmount;\n        });\n        const messageKey = this.inSuperFreeSpins() ? 'FREESPIN.SUPER_SPINS_PAY' : 'FREESPIN.FREE_SPINS_PAY';\n\n        if (win !== 0 && winAmount !== 0) {\n            const freeSpinFeatureWinMessage = {\n                win,\n                winAmount,\n                mode: 'message',\n                message: Core.translator.translate(messageKey),\n                cells: freeSpinScatterEntry?.cells,\n                symbol: freeSpinScatterEntry?.symbol,\n            };\n\n            const currentLines = [...this.rootStore.uiStore.LINES_TO_SHOW.value];\n            currentLines.push(freeSpinFeatureWinMessage);\n            this.rootStore.uiStore.LINES_TO_SHOW.next(currentLines);\n        }\n\n        // Core.NO_SLEEP_ACTIVE.next(false);\n\n        this.rootStore.subjects.RESTORE.executorComplete();\n    }\n\n    protected setWin(): void {\n        const betResponse: BetResponse = this.rootStore.domainStore.betResponse;\n        if (betResponse) {\n            const win = betResponse.bonusGamesTotalWinAmount || betResponse.totalWinAmount;\n            if (win > 0) {\n                this.rootStore.uiStore.WIN.next({\n                    amount: win,\n                    action: BangupActionConsts.BANGUP,\n                    feature: Features.FREE_SPINS,\n                });\n            }\n        }\n    }\n\n    protected setCurrentWin(): void {\n        const betResponse: BetResponse = this.rootStore.domainStore.betResponse;\n        let win = this.rootStore.uiStore.WIN.value.amount + betResponse.totalWinAmount;\n        if (\n            this.rootStore.subjects.MAX_WIN_LIMIT_HIT.value &&\n            win > this.rootStore.domainStore.betResponse.stateWinAmount\n        ) {\n            win = this.rootStore.domainStore.betResponse.stateWinAmount;\n        }\n        if (betResponse && betResponse.totalWinAmount !== 0) {\n            this.rootStore.uiStore.WIN.next({\n                amount: win,\n                action: BangupActionConsts.BANGUP,\n                feature: Features.FREE_SPINS,\n            });\n        }\n    }\n\n    protected addFeatureEvents(): void {\n        this.clearFeatureEvents.next();\n        const sub = merge(this.DESTROY, this.clearFeatureEvents);\n\n        ///////////////////////////// FeatureUIState ////////////////////////////\n        // this event are needed only when feature is runing\n        this.uiView.spinButton.CLICK.pipe(\n            filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n            takeUntil(sub),\n        ).subscribe(() => {\n            this.stateMachineService.send('ON_SPIN_CLICKED');\n        });\n\n        this.rootStore.uiStore.STATE.pipe(takeUntil(sub)).subscribe(() => {\n            this.stateMachineService.send('ON_STATE_CHANGED');\n        });\n\n        Core.ORIENTATION.pipe(takeUntil(sub)).subscribe((orientation) => {\n            this.stateMachineService.send('SET_ORIENTATION', { orientation });\n        });\n\n        this.rootStore.subjects.HIDE_SPECIAL_BAR.pipe(takeUntil(this.DESTROY)).subscribe(() =>\n            this.stateMachineService.send('SPECIAL_BAR'),\n        );\n\n        ///////////////////////////////////////////////////////////////////////////\n    }\n\n    protected toggleSpinSkipButton(): void {\n        // we change skip/spin buttons only if there is waiting start button\n        if (this.view.find('startFreeSpinButton')) {\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'spinButton',\n                actions: 'visible',\n                values: !this.waitingForUserAction,\n            });\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'skipButton',\n                actions: 'visible',\n                values: this.waitingForUserAction,\n            });\n            this.uiView.skipButton.state = ButtonStates.Disabled;\n        }\n    }\n\n    protected stepFeatureRestore(context, event): void {\n        this.addFeatureEvents();\n        this.rootStore.subjects.SECONDARY_BAR_VISIBLE.next(true);\n        this.rootStore.subjects.BUY_BONUS_AND_DOUBLE_CHANCE_VISIBLE.next(0);\n        this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_BTN_VISIBLE.next(false);\n        this.rootStore.domainStore.SPIN_MODE.prevValue = Features.FREE_SPINS;\n        this.stepFeatureCreate(context, event);\n        if (context.initialNumberOfFreeSpins > 0) {\n            this.onIntroFinished(context, event);\n        }\n    }\n\n    protected updateRemainingCounterOnFS(context, event): void {\n        if (this.rootStore.domainStore.currentSpinResults === 0) {\n            context.finishedNumberOfFreeSpins += 1;\n            this.view.updateRemainingCounterOnFS(context, event);\n        }\n    }\n\n    protected stepFeatureCreate(context, event): void {\n        this.view.createFreeSpinBar(context, event);\n        if (context.initialNumberOfFreeSpins > 0) {\n            this.rootStore.subjects.SECONDARY_BAR_VISIBLE.next(true);\n            this.rootStore.subjects.SPIN_BUTTON_SPECIAL_TEXT_VISIBLE.next(false);\n            this.rootStore.domainStore.SPIN_MODE.next(Features.FREE_SPINS);\n            this.stateMachineService.send('SHOW_FREE_SPIN');\n        }\n        if (!this.rootStore.subjects.ACTIVE_FEATURE.value.includes(Features.FREE_SPINS)) {\n            this.rootStore.subjects.FEATURE_STARTED.next(Features.FREE_SPINS);\n        }\n    }\n\n    protected autoPlayTimeout(_context): number {\n        return 300;\n    }\n\n    protected waitingForCollectUIButtonsState(): void {\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'spinButton',\n            actions: ['visible', 'enabled'],\n            values: [true, true],\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'stopButton',\n            actions: 'visible',\n            values: false,\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'collectButton',\n            actions: 'visible',\n            values: false,\n        });\n    }\n\n    protected waitingForCollectInFreeSpinsUIButtonsState(): void {\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'spinButton',\n            actions: ['visible', 'enabled'],\n            values: [true, true],\n        });\n    }\n\n    protected bonusSummaryUIbuttonsState(): void {\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'stopButton',\n            actions: 'visible',\n            values: false,\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'betPlusBtn',\n            actions: 'visible',\n            values: true,\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'betMinusBtn',\n            actions: 'visible',\n            values: true,\n        });\n    }\n\n    protected waitingForResponseInFreeSpinUIButtonsState(): void {\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'spinButton',\n            actions: ['visible', 'enabled'],\n            values: [false, true],\n        });\n        if (this.settings.autoplay) {\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'autoPlayButton',\n                actions: ['visible', 'enabled'],\n                values: [true, false],\n            });\n        } else {\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'autoPlayButton',\n                actions: ['visible', 'enabled'],\n                values: [false, false],\n            });\n        }\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'stopButton',\n            actions: ['visible', 'enabled'],\n            values: [true, true],\n        });\n        if (this.uiView.denominationButton) {\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'denominationButton',\n                actions: ['visible', 'enabled'],\n                values: [true, false],\n            });\n        }\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'collectSmallButton',\n            actions: 'visible',\n            values: false,\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'betPlusBtn',\n            actions: ['visible', 'enabled'],\n            values: [true, false],\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'betMinusBtn',\n            actions: ['visible', 'enabled'],\n            values: [true, false],\n        });\n    }\n\n    protected freespinUIButtonsState(context): void {\n        if (this.settings.autoplay) {\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'autoPlayButton',\n                actions: ['visible', 'enabled'],\n                values: [true, false],\n            });\n        } else {\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'autoPlayButton',\n                actions: ['visible', 'enabled'],\n                values: [false, false],\n            });\n        }\n        if (this.uiView.denominationButton) {\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'denominationButton',\n                actions: ['visible', 'enabled'],\n                values: [true, false],\n            });\n        }\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'betPlusBtn',\n            actions: 'visible',\n            values: true,\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'betMinusBtn',\n            actions: 'visible',\n            values: true,\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'collectSmallButton',\n            actions: 'visible',\n            values: false,\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'stopButton',\n            actions: 'visible',\n            values: false,\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'spinButton',\n            actions: ['visible', 'enabled'],\n            values: [true, false],\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'spinSpeedButton',\n            actions: 'visible',\n            values: false,\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'spinSpeedButtonDisabled',\n            actions: 'visible',\n            values: true,\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'ropeText',\n            actions: 'visible',\n            values: false,\n        });\n\n        if (context.state === UIState.FREESPIN && context.introFinished) {\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'spinButton',\n                actions: 'enabled',\n                values: true,\n            });\n            if (\n                (this.rootStore.uiStore.BANGUP_RUNNING.value && this.rootStore.domainStore.currentSpinResults === 0) ||\n                context.finishedNumberOfFreeSpins === 0\n            ) {\n                this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                    name: 'stopButton',\n                    actions: 'visible',\n                    values: false,\n                });\n                this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                    name: 'spinButton',\n                    actions: 'visible',\n                    values: true,\n                });\n            } else {\n                this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                    name: 'stopButton',\n                    actions: 'visible',\n                    values: true,\n                });\n                this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                    name: 'spinButton',\n                    actions: 'visible',\n                    values: false,\n                });\n            }\n        }\n        // for games like Versailles Gold for last spin from fs if there is line win plus expand win\n        if (context.state === UIState.WIN) {\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'stopButton',\n                actions: ['visible', 'enabled'],\n                values: [true, true],\n            });\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'spinButton',\n                actions: 'visible',\n                values: false,\n            });\n        }\n    }\n\n    protected outroUIButtonsState(): void {\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'spinButton',\n            actions: ['visible', 'enabled'],\n            values: [true, false],\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'stopButton',\n            actions: ['visible', 'enabled'],\n            values: [false, false],\n        });\n        if (this.settings.autoplay) {\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'autoPlayButton',\n                actions: ['visible', 'enabled'],\n                values: [true, false],\n            });\n        } else {\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'autoPlayButton',\n                actions: ['visible', 'enabled'],\n                values: [false, false],\n            });\n        }\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'ropeText',\n            actions: 'visible',\n            values: false,\n        });\n        if (this.uiView.denominationButton) {\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'denominationButton',\n                actions: ['visible', 'enabled'],\n                values: [true, false],\n            });\n        }\n        /* if (this.featureController.isInGiftSpins) {\n            this.uiView.denominationButton.visible = false;\n        } */\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'spinSpeedButton',\n            actions: 'visible',\n            values: false,\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'spinSpeedButtonDisabled',\n            actions: 'visible',\n            values: true,\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'betPlusBtn',\n            actions: 'visible',\n            values: true,\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'betMinusBtn',\n            actions: 'visible',\n            values: true,\n        });\n    }\n    protected onStateChanged(context, _event): void {\n        switch (this.rootStore.uiStore.STATE.value) {\n            case UIState.WAITING_FOR_COLLECT:\n                if (context.introFinished) {\n                    this.waitingForCollectUIButtonsState();\n                }\n                break;\n            case UIState.WAITING_FOR_COLLECT_IN_FREE_SPINS:\n                this.waitingForCollectInFreeSpinsUIButtonsState();\n                break;\n            case UIState.BONUS_SUMMARY:\n                this.bonusSummaryUIbuttonsState();\n                break;\n            case UIState.WAITING_FOR_RESPONSE_IN_FREESPIN:\n                this.waitingForResponseInFreeSpinUIButtonsState();\n                break;\n            case UIState.FREESPIN:\n                this.freespinUIButtonsState(context);\n                break;\n        }\n    }\n\n    protected async startFeature(context, event): Promise<void> {\n        if (\n            context.state !== UIState.FREESPIN &&\n            !this.isOutro(context, event) &&\n            this.rootStore.domainStore.currentSpinResults === 0\n        ) {\n            return Promise.resolve();\n        }\n\n        await this.ready();\n\n        // if (!Core.NO_SLEEP_ACTIVE.value) {\n        //     Core.NO_SLEEP_ACTIVE.next(true);\n        // }\n\n        this.stateMachineService.send({ type: 'REELS_STOPPED' });\n    }\n\n    protected isIntro(context, _event): boolean {\n        return (\n            context.state === UIState.FREESPIN &&\n            context.finishedNumberOfFreeSpins === 0 &&\n            this.rootStore.domainStore.currentSpinResults === 0\n        );\n    }\n\n    protected isRestore(context, _event): boolean {\n        return context.finishedNumberOfFreeSpins > 0 && !context.introFinished;\n    }\n\n    protected isRetrigger(context, _event): boolean {\n        return context.state === UIState.FREESPIN && context.freeSpinBonus;\n    }\n\n    protected createStateMachine(): void {\n        const isIntro = this.isIntro.bind(this);\n        const isRetrigger = this.isRetrigger.bind(this);\n        const isOutro = this.isOutro.bind(this);\n        const isRestore = this.isRestore.bind(this);\n        const isCreate = this.isCreate.bind(this);\n        const isAutoPlayFreespins = this.isAutoPlayFreespins.bind(this);\n        const isNormalSpinTime = this.isNormalSpinTime.bind(this);\n        const isMaxWinLimitHit = this.isMaxWinLimitHit.bind(this);\n        const enableSpinButton = this.enableSpinButton.bind(this);\n        const disableSpinButton = this.disableSpinButton.bind(this);\n\n        const stepFeatureIntro = this.stepFeatureIntro.bind(this);\n        const showIntro = this.showIntro.bind(this);\n        const onStartFreeSpinClicked = this.onStartFreeSpinClicked.bind(this);\n        const stepFeatureUpdate = this.stepFeatureUpdate.bind(this);\n        const stepFeatureRetrigger = this.stepFeatureRetrigger.bind(this);\n        const stepFeatureOutro = this.stepFeatureOutro.bind(this);\n        const stepFeatureRestore = this.stepFeatureRestore.bind(this);\n        const updateState = assign(this.updateState.bind(this));\n        const enableKeyEnter = assign(this.enableKeyEnter.bind(this));\n        const enableIntroHiddenViaKeyboard = assign(this.enableIntroHiddenViaKeyboard.bind(this));\n        const guardEnableSpinButton = this.guardEnableSpinButton.bind(this);\n\n        const showMaxWinLimitHit = this.showMaxWinLimitHit.bind(this);\n\n        this.stateMachine = Machine(\n            {\n                id: 'freeSpin',\n                context: this.freeSpinStore,\n                initial: 'readyToStart',\n\n                on: {\n                    SOUND_LOADED: { actions: 'onSoundLoaded' },\n                    SHOW_FREE_SPIN: [{ actions: ['onInitAssets'] }],\n                    ON_BET: [{ actions: ['onBet'] }],\n                    ON_KEY_RELEASED: [{ actions: ['onKeyReleased'] }],\n                    ON_STATE_CHANGED: [{ actions: ['onStateChanged'] }],\n                    ON_STOP_CLICKED: [{ cond: isNormalSpinTime, actions: 'onStopClicked' }],\n                    ON_RESTORE_STATE: [{ actions: 'onRestoreState' }],\n\n                    UPDATE_STATE: [{ actions: ['updateState'] }],\n                    SET_ORIENTATION: [{ actions: 'setOrientation' }],\n                    START_FEATURE: [{ actions: 'startFeature' }],\n                    SPECIAL_BAR: [{ actions: 'toggleFsBar' }],\n                },\n                states: {\n                    readyToStart: {\n                        on: {\n                            REELS_STOPPED: [\n                                { cond: isIntro, target: 'startFreeSpin' },\n                                { cond: isOutro, target: 'outro' },\n                                { cond: isRetrigger, target: 'retrigger' },\n                                { cond: isCreate, target: 'waitingForResponse', actions: ['onIntroVisible'] },\n                                { cond: isRestore, target: 'idle', actions: ['stepFeatureRestore'] },\n                            ],\n                            ON_RESTORE: [{ actions: 'onRestore' }],\n                        },\n                    },\n                    waitForRestoreFromFeature: {\n                        on: {\n                            RETRIGGER: 'retrigger',\n                            WIN_VISUALIZATION_FINISHED: 'idle',\n                        },\n                    },\n                    startFreeSpin: {\n                        entry: 'stepFeatureIntro',\n                        on: {\n                            START_FREE_SPIN: [\n                                { actions: ['hideStartScreen', 'onStartFreeSpinClicked'], target: 'intro' },\n                            ],\n                            COIN_FEATURE_SKIPPED: [{ actions: ['showIntro'] }],\n                        },\n                    },\n                    intro: {\n                        on: {\n                            ENABLE_HIDE_INTRO_VIA_KEYBOARD: [{ actions: 'enableIntroHiddenViaKeyboard' }],\n                            CHOOSE_SYMBOL_ON_START: [{ actions: 'enableKeyEnter' }],\n                            ON_SPIN_CLICKED: [{ actions: 'onSpinClickedInIntro' }],\n                            FREESPIN_INTRO_VISIBLE: [{ actions: ['onIntroVisible'] }],\n                            FREESPIN_INTRO_FINISHED: 'idle',\n                        },\n                        exit: 'onIntroFinished',\n                    },\n                    idle: {\n                        entry: 'guardEnableSpinButton',\n                        on: {\n                            SPIN: 'waitingForResponse',\n                            ON_SPIN_CLICKED: [{ actions: 'spin' }],\n                            WAIT_EXPAND_WIN_VISUALIZATION: 'waitingForWinVisualization',\n                        },\n                        after: [\n                            {\n                                delay: (context, _event) => {\n                                    return this.autoPlayTimeout(context);\n                                },\n                                cond: isAutoPlayFreespins,\n                                target: 'waitingForResponse',\n                            },\n                            {\n                                delay: (context, _event) => {\n                                    return this.autoPlayTimeout(context);\n                                },\n                                actions: 'enableSpinButton',\n                            },\n                        ],\n                        // {\n                        //     300: [\n                        //         { cond: isAutoPlayFreespins, target: 'waitingForResponse' },\n                        //         { actions: 'enableSpinButton' },\n                        //     ],\n                        // },\n                        exit: ['updateRemainingCounterOnFS', 'spin'],\n                    },\n                    waitingForResponse: {\n                        entry: 'disableSpinButton',\n                        on: {\n                            REELS_STOPPED: [\n                                { cond: isIntro, target: 'startFreeSpin' },\n                                { cond: isMaxWinLimitHit, target: 'maxWinLimitHit' },\n                                { cond: isOutro, target: 'outro' },\n                                { cond: isRetrigger, target: 'retrigger' },\n                                { cond: isRestore, target: 'idle', actions: ['stepFeatureRestore'] },\n                                { target: 'waitingForWinVisualization' },\n                            ],\n                            ON_RESTORE: [\n                                { cond: isOutro }, // if outro do nothing here, wait for outro visible\n                                { actions: 'onRestore' },\n                            ],\n                        },\n                    },\n                    maxWinLimitHit: {\n                        entry: 'showMaxWinLimitHit',\n                        after: {\n                            1000: { target: 'outro' },\n                        },\n                    },\n                    waitingForAllLinesLoop: {\n                        on: {\n                            ON_SPIN_CLICKED: [{ actions: ['spin'] }],\n                            WIN_VISUALIZATION_FINISHED: 'idle',\n                        },\n                    },\n                    waitingForWinVisualization: {\n                        entry: 'stepFeatureUpdate',\n                        on: {\n                            ON_SPIN_CLICKED: [{ actions: ['spin'] }],\n                            WIN_VISUALIZATION_FINISHED: 'idle',\n                        },\n                    },\n                    retrigger: {\n                        entry: 'stepFeatureRetrigger',\n                        on: {\n                            FREESPIN_RETRIGGER_VISIBLE: [\n                                { actions: ['onRetriggerVisible', 'updateMessageContentOnRetrigger'] },\n                            ],\n                            FREESPIN_RETRIGGER_FINISHED: 'idle',\n                        },\n                        exit: 'onRetriggerFinished',\n                    },\n                    outro: {\n                        entry: ['stepFeatureOutro'],\n                        on: {\n                            FREESPIN_OUTRO_VISIBLE: [{ actions: ['onOutroVisible', 'onRestore'] }],\n                            FREESPIN_OUTRO_FINISHED: 'readyToStart',\n                        },\n                        exit: 'onOutroFinished',\n                    },\n                },\n            },\n            {\n                actions: {\n                    hideStartScreen: this.hideStartScreen.bind(this),\n                    updateMessageContentOnRetrigger: this.updateMessageContentOnRetrigger.bind(this),\n                    updateRemainingCounterOnFS: this.updateRemainingCounterOnFS.bind(this),\n                    onIntroVisible: this.onIntroVisible.bind(this),\n                    onIntroFinished: this.onIntroFinished.bind(this),\n                    onRetriggerFinished: this.onRetriggerFinished.bind(this),\n                    onOutroVisible: this.onOutroVisible.bind(this),\n                    onOutroFinished: this.onOutroFinished.bind(this),\n                    stepFeatureIntro,\n                    showIntro,\n                    onStartFreeSpinClicked,\n                    stepFeatureUpdate,\n                    stepFeatureRetrigger,\n                    stepFeatureOutro,\n                    stepFeatureRestore,\n                    onInitAssets: this.onInitAssets.bind(this),\n                    onSoundLoaded: this.onSoundLoaded.bind(this),\n                    spin: this.spin.bind(this),\n                    onBet: this.onBet.bind(this),\n                    updateState,\n                    showMaxWinLimitHit,\n                    onKeyReleased: this.onKeyReleased.bind(this),\n                    onStateChanged: this.onStateChanged.bind(this),\n                    onStopClicked: this.onStopClicked.bind(this),\n                    onSpinClickedInIntro: this.onSpinClickedInIntro.bind(this),\n                    onRestore: this.onRestore.bind(this),\n                    startFeature: this.startFeature.bind(this),\n                    setOrientation: this.setOrientation.bind(this),\n                    toggleFsBar: this.toggleBar.bind(this),\n                    enableKeyEnter,\n                    enableIntroHiddenViaKeyboard,\n                    enableSpinButton,\n                    guardEnableSpinButton,\n                    disableSpinButton,\n                },\n                guards: {\n                    isIntro,\n                    isRetrigger,\n                    isOutro,\n                    isRestore,\n                    isCreate,\n                    isNormalSpinTime,\n                    isMaxWinLimitHit,\n                    isAutoPlayFreespins,\n                },\n            },\n        );\n\n        this.stateMachineService = interpret(this.stateMachine, { devTools: Core.configuration.devTools }).start();\n    }\n\n    protected isCreate(context, _event): boolean {\n        return context.state === 'CREATE';\n    }\n\n    // Check GLI wait to custom set reels\n    ////////////////////////////////////////////////////////////////////////////\n    protected isAutoPlayFreespins(): boolean {\n        return (\n            (this.rootStore.customResultStore ? this.rootStore.customResultStore.isAutoPlayFeatures.value : true) ||\n            this.rootStore.domainStore.currentSpinResults > 0\n        );\n    }\n\n    protected isNormalSpinTime(_context, _event): boolean {\n        return this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value === 0;\n    }\n\n    protected hideStartScreen(): void {\n        this.view.hideStartScreen();\n    }\n\n    protected enableSpinButton(): void {\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'spinButton',\n            actions: ['visible', 'enabled'],\n            values: [true, true],\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'stopButton',\n            actions: 'visible',\n            values: false,\n        });\n    }\n    protected guardEnableSpinButton(): void {\n        if (!this.isAutoPlayFreespins()) {\n            this.enableSpinButton();\n        }\n        this.rootStore.subjects.BUY_BONUS_AND_DOUBLE_CHANCE_VISIBLE.next(0);\n        this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_BTN_VISIBLE.next(false);\n    }\n    protected disableSpinButton(): void {\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'stopButton',\n            actions: ['visible', 'enabled'],\n            values: [true, true],\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'spinButton',\n            actions: 'visible',\n            values: false,\n        });\n    }\n    protected enableKeyEnter(): void {\n        this.waitingForUserAction = true;\n    }\n    protected enableIntroHiddenViaKeyboard(): void {\n        this.waitingForUserAction = true;\n        this.hideIntroViaKeyboard = true;\n    }\n    protected updateMessageContentOnRetrigger(context, event): void {\n        this.view.updateMessageContentOnRetrigger(context, event);\n    }\n\n    protected setOrientation(context, event): void {\n        this.view.setOrientation(context, event.orientation);\n    }\n\n    protected showMaxWinLimitHit(): void {\n        this.rootStore.domainStore.currentSpinResults = 0;\n        this.rootStore.subjects.MAX_WIN_LIMIT_MESSAGE.next('MAX_WIN.LIMIT_HIT');\n        // Core.MAX_WIN_LIMIT_HIT.next(true);\n    }\n\n    // called when feature as SingleGame jackpot is finished and we continue fs with fsbackground\n    protected onFeatureFinished(feature: Features): void {\n        if (Features.FREE_SPINS === feature) {\n            return;\n        }\n\n        if (this.rootStore.domainStore.SPIN_MODE.prevValue === Features.FREE_SPINS) {\n            Core.sounds.stopAll();\n            this.rootStore.uiStore.BACKGROUND_SOUND_PLAY.next({ sound: undefined, ms: 0 });\n            Core.sounds.play('freeSpinsBackgroundSound', true);\n        }\n    }\n\n    protected onShowHideBar(show: boolean): void {\n        this.view.fsMessageBar.visible = show;\n    }\n\n    protected onStartFreeSpinClicked(context, event): void {\n        this.waitingForUserAction = false;\n        this.toggleSpinSkipButton();\n        if (Timers.isActiveTimeout(this.waitingSoundTimeout)) {\n            Timers.clearTimeout(this.waitingSoundTimeout);\n        }\n        this.rootStore.subjects.STOP_COIN_FEATURE_FROM_OTHER_FEATURE.next();\n        this.view.startIntro(context, event);\n        this.rootStore.uiStore.STATE.next(UIState.FREESPIN);\n    }\n\n    protected onIntroVisible(context, event): void {\n        this.rootStore.subjects.BEFORE_SPIN.next();\n        this.stepFeatureCreate(context, event);\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'betPlusBtn',\n            actions: ['visible', 'enabled'],\n            values: [true, false],\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'betMinusBtn',\n            actions: ['visible', 'enabled'],\n            values: [true, false],\n        });\n    }\n\n    protected onKeyReleased(_context, event): void {\n        const e = event.e;\n        if (e === null || this.rootStore.domainStore.SPIN_MODE.value !== Features.FREE_SPINS) {\n            return;\n        }\n\n        if (\n            (e.code !== undefined && (e.code === 'Space' || e.code === 'Enter' || e.code === 'NumpadEnter')) ||\n            (e.keyCode !== undefined && (e.keyCode === 32 || e.keyCode === 13))\n        ) {\n            if (this.uiView.stopButton.visible) {\n                this.stateMachineService.send('ON_STOP_CLICKED');\n            }\n\n            const button = this.waitingForUserAction ? this.uiView.skipButton : this.uiView.spinButton;\n            if (button.visible && button.enabled) {\n                this.stateMachineService.send('ON_SPIN_CLICKED');\n            }\n            if (this.waitingForUserAction) {\n                this.stateMachineService.send('START_FREE_SPIN');\n\n                if (this.hideIntroViaKeyboard) {\n                    this.view.hideIntroViaKeyboard();\n                } else {\n                    this.view.startSymbolAnimation();\n                }\n            }\n        }\n    }\n\n    protected onInitAssets(context, _event): void {\n        this.view.onInitAssets(context, true);\n        // if (!this.rootStore.subjects.ACTIVE_FEATURE.value.includes(Features.FREE_SPINS)) {\n        //     this.rootStore.subjects.FEATURE_STARTED.next(Features.FREE_SPINS);\n        // }\n    }\n\n    protected updateState(_context, event: any): any {\n        return event.context;\n    }\n\n    protected toggleBar(context): void {\n        this.view.toggleFsBar(context);\n    }\n\n    protected processNextResultFromSpin(): void {\n        this.rootStore.subjects.BEFORE_SPIN.next();\n        this.rootStore.domainStore.bet();\n    }\n\n    protected inSuperFreeSpins(): boolean {\n        return (\n            this.rootStore.settings.haveGameMode(this.slotConfiguration.superBuyBonusGameMode) &&\n            this.rootStore.domainStore.betResponse.gameState.bet.factor ===\n                this.rootStore.settings.getFactorByUniqueGameMode(this.slotConfiguration.superBuyBonusGameMode)\n        );\n    }\n\n    protected addPrizePopSoundsToSkip(context: any): void {\n        const prizePopSoundsSpritesheet = Core.sounds.getAllSounds().find((s) => s.id === 'prizePopSounds')?.sprite;\n\n        if (prizePopSoundsSpritesheet) {\n            if (context && !context.skipSoundsStop) {\n                context.skipSoundsStop = [];\n            }\n\n            const allPrizePopSounds = Object.keys(prizePopSoundsSpritesheet);\n            context?.skipSoundsStop.push(...allPrizePopSounds);\n        }\n    }\n}\n","const enum FreeSpinType {\n    DEFAULT = 'freespin',\n    STICKY_WILDS = 'freeSpinStickyWilds',\n    RAINING_WILDS = 'freeSpinRainingWilds',\n}\nexport default FreeSpinType;\n","import { UIState } from '@egt/slot';\nimport { injectable } from 'tsyringe';\nimport { BaseStore } from '@egt/core';\n\n@injectable()\nexport default class FreeSpinStore extends BaseStore {\n    public state: UIState | 'CREATE';\n    public totalWin: number;\n    public freeSpinBonus: boolean;\n    public introFinished: boolean;\n    public initialNumberOfFreeSpins: number;\n    public finishedNumberOfFreeSpins: number;\n    public retriggeredNumberOfFreeSpins: number;\n    public comeFromRefresh: boolean;\n    public numberOfSpinsToExclude: number;\n    public freespinsType: string;\n    public get remainingNumberOfFreeSpins(): number {\n        return this.initialNumberOfFreeSpins - this.finishedNumberOfFreeSpins;\n    }\n\n    constructor() {\n        super();\n        this.enableLogging();\n        this.state = UIState.UNSET;\n        this.totalWin = 0;\n        this.introFinished = false;\n        this.initialNumberOfFreeSpins = 0;\n        this.finishedNumberOfFreeSpins = 0;\n        this.retriggeredNumberOfFreeSpins = 0;\n        this.freeSpinBonus = false;\n        this.comeFromRefresh = false;\n        this.numberOfSpinsToExclude = 0;\n        this.freespinsType = '';\n    }\n}\n","import Core, { IOrientation } from '@egt/core';\nimport { ISlotConfiguration, RootStore } from '@egt/slot';\nimport { ViewContainer } from '@egt/ui-lib';\nimport { Container, Sprite, Text, TextStyle, Texture } from 'pixi.js';\nimport { inject, injectable } from 'tsyringe';\nimport FreeSpinStore from '../stores/FreeSpinStore';\n\n@injectable()\nexport default class FreeSpinMessageBarView extends ViewContainer {\n    protected fsLandscapeStyle: TextStyle;\n    protected initialSettings: any;\n    protected fsSmallLandscapeStyle: TextStyle;\n    protected fsPortraitStyle: TextStyle;\n    protected fsSmallPortraitStyle: TextStyle;\n    protected fsBackgroundColor: string = '201, 0, 12';\n    private _fsContent: Container;\n    private fsBackground: Sprite;\n    private statusBarTextValues: any;\n\n    private fsSpaceBetweenWords: number = 10;\n\n    protected fsMessageBackgroundHeight: number = 34;\n    protected fsMessageTopOffset: number = 10;\n\n    private wingsWidth: number = 160; // 130\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('FreeSpinStore') protected freeSpinStore: FreeSpinStore,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n    ) {\n        super();\n\n        this.setInitialTextConfigs();\n\n        this.initialSettings = {\n            topOffset: 620,\n            messageBarrFreeSpinXOffset: 950,\n            freeSpinTopOffset: 580,\n            freeSpinXOffset: 320,\n        };\n\n        this.fsLandscapeStyle = new TextStyle({\n            fontFamily: 'FuturaPT, Arial',\n            fontSize: 24,\n            fontWeight: 'bold',\n            fill: '#FFD035',\n        });\n\n        this.fsSmallLandscapeStyle = new TextStyle({\n            fontFamily: 'FuturaPT, Arial,',\n            fontSize: 24,\n            fontWeight: 'bold',\n            fill: '#FFFFFF',\n        });\n\n        this.fsPortraitStyle = new TextStyle({\n            fontFamily: 'FuturaPT, Arial',\n            fontSize: 18,\n            fontWeight: 'bold',\n            fill: '#FFD035',\n        });\n\n        this.fsSmallPortraitStyle = new TextStyle({\n            fontFamily: 'FuturaPT, Arial',\n            fontSize: 18,\n            fontWeight: 'bold',\n            fill: '#FFFFFF',\n        });\n    }\n\n    public createFreeSpinBar(context, event): void {\n        this.setMessageBarsPositions();\n        this.showFreeSpins(context, event);\n    }\n\n    public destroy(): void {\n        if (this.fsBackground) {\n            this.fsBackground.removeChild(this.fsBackground);\n            this.fsBackground.destroy();\n            // @ts-ignore\n            this.fsBackground = undefined;\n        }\n        if (this._fsContent) {\n            if (this._fsContent.children.length) {\n                this._fsContent.children.forEach((child) => {\n                    child.destroy();\n                });\n            }\n            this.removeChild(this._fsContent);\n            this._fsContent.destroy();\n            // @ts-ignore\n            this._fsContent = null;\n        }\n    }\n\n    public updateMessageContentOnRetrigger(context, event): void {\n        if (!this._fsContent) {\n            this.showFreeSpins(context, event);\n        }\n        (this._fsContent.getChildByName('allFreeSpins') as Text).text = context.initialNumberOfFreeSpins.toString();\n        this.updateSize();\n    }\n\n    /**\n     *\n     * @param orientation\n     * Change elements properties based on current orientation.\n     */\n    public setMessageBarOrientation(context, _orientation: IOrientation): void {\n        this.showFreeSpins(context, null);\n        this.setMessageBarsPositions();\n        this.positionFSMessageBar();\n    }\n\n    public updateRemainingCounterOnFS(context, _event): void {\n        if (!this._fsContent) {\n            return;\n        }\n        (this._fsContent.getChildByName('fsCounter') as Text).text = context.finishedNumberOfFreeSpins.toString();\n        (this._fsContent.getChildByName('allFreeSpins') as Text).text = context.initialNumberOfFreeSpins.toString();\n\n        this.updateSize();\n    }\n\n    public toggleFsBar(context): void {\n        if (this.rootStore.subjects.SECONDARY_BAR_VISIBLE.value && context.introFinished) {\n            this.visible = !this.rootStore.subjects.HIDE_SPECIAL_BAR.value;\n        }\n    }\n\n    /**\n     * Generate free spins message content\n     */\n    protected generateFSMessageContent(context, _event): void {\n        this._fsContent = new Container();\n        const fsText1: Text = new Text(this.statusBarTextValues.firstFSText, this.getFSTextStyle());\n        const fsCounter: Text = new Text(context.finishedNumberOfFreeSpins.toString(), this.getSmallFSTextStyle());\n        fsCounter.name = 'fsCounter';\n        const fsText2: Text = new Text(this.statusBarTextValues.secondFSText, this.getFSTextStyle());\n        fsText2.name = 'fsText2';\n        const allFreeSpins: Text = new Text(\n            (context.initialNumberOfFreeSpins - context.numberOfSpinsToExclude).toString(),\n            this.getSmallFSTextStyle(),\n        );\n        allFreeSpins.name = 'allFreeSpins';\n\n        fsText1.x = 0;\n        fsCounter.x = fsText1.x + fsText1.width + this.fsSpaceBetweenWords;\n        fsText2.x = fsCounter.x + fsCounter.width + this.fsSpaceBetweenWords;\n        allFreeSpins.x = fsText2.x + fsText2.width + this.fsSpaceBetweenWords;\n\n        this.addChild(this._fsContent);\n\n        this._fsContent.addChild(fsText1);\n        this._fsContent.addChild(fsCounter);\n        this._fsContent.addChild(fsText2);\n        this._fsContent.addChild(allFreeSpins);\n    }\n    /**\n     * Set position for free spins bar depend on orientation\n     */\n    protected positionFSMessageBar(): void {\n        if (this.fsBackground) {\n            if (Core.ORIENTATION.value.isLandscape) {\n                this.fsBackground.x = this.initialSettings.freeSpinXOffset + this.fsBackground.width / 2;\n            } else {\n                this.fsBackground.x = this.initialSettings.freeSpinXOffset;\n            }\n            this.fsBackground.y = this.initialSettings.freeSpinTopOffset;\n        }\n        if (this._fsContent) {\n            this._fsContent.x = this.fsBackground.x - this._fsContent.width / 2;\n            this._fsContent.y = this.fsBackground.y - this._fsContent.height / 2;\n        }\n    }\n\n    /**\n     * Show free spins message bar and counter\n     */\n    protected showFreeSpins(context, event): void {\n        this.removeChildren();\n\n        this.generateFSMessageContent(context, event);\n        this.generateFSBackground();\n\n        this.positionFSMessageBar();\n\n        this.addChild(this.fsBackground);\n        this.addChild(this._fsContent);\n\n        if (this.rootStore.subjects.SECONDARY_BAR_VISIBLE.value && context.introFinished) {\n            this.visible = !this.rootStore.subjects.HIDE_SPECIAL_BAR.value;\n        }\n    }\n\n    /**\n     * Returns proper free spins text style one based on current device orientation\n     */\n    private getFSTextStyle(): TextStyle {\n        if (Core.ORIENTATION.value.isLandscape) {\n            return this.fsLandscapeStyle;\n        } else {\n            return this.fsPortraitStyle;\n        }\n    }\n\n    /**\n     * Sets initial configs for text fields.\n     */\n    private setInitialTextConfigs(): void {\n        this.statusBarTextValues = {\n            firstFSText: Core.translator.translate('FREE SPIN'),\n            secondFSText: Core.translator.translate('OF'),\n        };\n    }\n\n    /**\n     * Returns proper free spins text style two based on current device orientation\n     */\n    private getSmallFSTextStyle(): TextStyle {\n        if (Core.ORIENTATION.value.isLandscape) {\n            return this.fsSmallLandscapeStyle;\n        } else {\n            return this.fsSmallPortraitStyle;\n        }\n    }\n\n    /**\n     * Generate free spins background\n     */\n    private generateFSBackground(): void {\n        const fsBackgroundHeight: number = Core.ORIENTATION.value.isLandscape\n            ? this.fsMessageBackgroundHeight\n            : this.fsMessageBackgroundHeight - 10;\n\n        this.fsBackground = this.generateBackground(\n            this._fsContent.width,\n            fsBackgroundHeight,\n            this.fsBackgroundColor,\n            110,\n        );\n        this.fsBackground.alpha = 1;\n    }\n\n    // TODO: instead caluctae sizes - make with translator.replace\n    // and only one resource translation as \"FREE SPIN ##fsnumber## OF ##fstotal##\"\n    private updateSize(): void {\n        const fscounter = this._fsContent.getChildByName('fsCounter') as Text;\n        const fsText2 = this._fsContent.getChildByName('fsText2') as Text;\n        this._fsContent.getChildByName('fsText2').x =\n            fscounter.x + this._fsContent.getChildByName('fsCounter').getLocalBounds().width + this.fsSpaceBetweenWords;\n        this._fsContent.getChildByName('allFreeSpins').x = fsText2.x + fsText2.width + this.fsSpaceBetweenWords;\n    }\n\n    /**\n     * @param width  submit the width of content method will add wings automatically\n     * @param height submit th height of background\n     * @param color this parameter is optional you can send color of the background if don't background will be black\n     *\n     * Generates background for fs bar view based on passed container properties\n     */\n    private generateBackground(\n        width: number,\n        height: number,\n        color: string = '0,0,0',\n        wingsWidth: number = this.wingsWidth,\n    ): Sprite {\n        let canvas = document.createElement('canvas');\n        canvas.width = width + wingsWidth;\n        canvas.height = height;\n\n        const context: CanvasRenderingContext2D | null = canvas.getContext('2d');\n        const gradient: any = context!.createLinearGradient(0.0, height, width + wingsWidth, height);\n\n        gradient.addColorStop(0.0, 'rgba(' + color + ', 0.000)');\n        gradient.addColorStop(0.1, 'rgba(' + color + ', 0.850)');\n        gradient.addColorStop(0.9, 'rgba(' + color + ', 0.850)');\n        gradient.addColorStop(1.0, 'rgba(' + color + ', 0)');\n        context!.fillStyle = gradient;\n        context!.fillRect(0, 0, width + wingsWidth, height);\n\n        const background: Sprite = new Sprite();\n\n        background.texture = Texture.from(canvas);\n        background.anchor.set(0.5);\n        background.alpha = 0;\n\n        canvas.remove();\n        // @ts-ignore\n        canvas = null;\n        return background;\n    }\n\n    /**\n     * Positioning free spins message bar\n     */\n    protected setMessageBarsPositions(): void {\n        const isLandscape: boolean = Core.ORIENTATION.value.isLandscape;\n\n        if (isLandscape) {\n            this.initialSettings.freeSpinTopOffset =\n                this.rootStore.subjects.REELS_POSITION.value.reelY +\n                this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value *\n                    this.rootStore.subjects.REELS_POSITION.value.symbolHeight -\n                this.fsMessageBackgroundHeight +\n                this.fsMessageTopOffset;\n            this.initialSettings.freeSpinXOffset = this.rootStore.subjects.REELS_POSITION.value.reelX;\n        } else if (!isLandscape) {\n            this.initialSettings.freeSpinTopOffset = 677;\n            this.initialSettings.freeSpinXOffset = Core.ORIENTATION.value.width / 2;\n        }\n    }\n}\n","import Core, { IOrientation } from '@egt/core';\nimport { ISlotConfiguration, RootStore } from '@egt/slot';\nimport { UIBlocker, ViewContainer } from '@egt/ui-lib';\nimport { Container } from 'pixi.js';\nimport { inject, injectable } from 'tsyringe';\nimport FreeSpinStore from '../stores/FreeSpinStore';\nimport FreeSpinMessageBarView from './FreeSpinMessageBarView';\n\n@injectable()\nexport default class FreeSpinViewDefault extends ViewContainer {\n    public fsAnimations: Container = new Container();\n    // public fsMessageBar: Container = new Container();\n    public initialized: boolean = false;\n    public currentOrientation: IOrientation;\n    // public doNotUseStandartMessageBar: boolean = false;\n    // protected initialSettings: any;\n    protected blockerOverlay: UIBlocker;\n\n    // private _fsContent: Container;\n    // private fsBackground: Sprite;\n    // private fsLandscapeStyle: TextStyle;\n    // private fsPortraitStyle: TextStyle;\n    // private fsSmallLandscapeStyle: TextStyle;\n    // private fsSmallPortraitStyle: TextStyle;\n    // private statusBarTextValues: any;\n\n    // private fsSpaceBetweenWords: number = 10;\n\n    // private fsMessageBackgroundHeight: number = 34;\n    // private fsMessageTopOffset: number = 10;\n    // private fsBackgroundColor: string = '201, 0, 12';\n\n    // private wingsWidth: number = 160; // 130\n\n    private _stateMachineService: any;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('FreeSpinStore') protected freeSpinStore: FreeSpinStore,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('FreeSpinMessageBarView') public fsMessageBar: FreeSpinMessageBarView,\n    ) {\n        super();\n\n        // this.setInitialTextConfigs();\n        this.generateBlockerOverlay();\n\n        this.addChild(this.fsMessageBar);\n        this.addChild(this.fsAnimations);\n\n        this.visible = true;\n        this.fsMessageBar.visible = false;\n        this.fsAnimations.visible = false;\n\n        // this.initialSettings = {\n        //     topOffset: 620,\n        //     messageBarrFreeSpinXOffset: 950,\n        //     freeSpinTopOffset: 580,\n        //     freeSpinXOffset: 320,\n        // };\n\n        // this.fsLandscapeStyle = new TextStyle({\n        //     fontFamily: 'Arial',\n        //     fontSize: 24,\n        //     fontWeight: 'bold',\n        //     fill: '#FFD035',\n        // });\n\n        // this.fsSmallLandscapeStyle = new TextStyle({\n        //     fontFamily: 'Arial',\n        //     fontSize: 24,\n        //     fontWeight: 'bold',\n        //     fill: '#FFFFFF',\n        // });\n\n        // this.fsPortraitStyle = new TextStyle({\n        //     fontFamily: 'Arial',\n        //     fontSize: 18,\n        //     fontWeight: 'bold',\n        //     fill: '#FFD035',\n        // });\n\n        // this.fsSmallPortraitStyle = new TextStyle({\n        //     fontFamily: 'Arial',\n        //     fontSize: 18,\n        //     fontWeight: 'bold',\n        //     fill: '#FFFFFF',\n        // });\n    }\n\n    public onInitComplete(): void {\n        // To do implement\n    }\n\n    public destroy(): void {\n        this.fsAnimations.destroy();\n        // @ts-ignore\n        this.fsAnimations = null;\n        this.fsMessageBar.destroy();\n        // @ts-ignore\n        this.fsMessageBar = null;\n        // @ts-ignore\n        this.rootStore = null;\n        this.blockerOverlay.destroy();\n        // @ts-ignore\n        this.blockerOverlay = null;\n        // @ts-ignore\n        this._fsContent = null;\n        // @ts-ignore\n        this.fsBackground = null;\n        // @ts-ignore\n        this.fsLandscapeStyle = null;\n        // @ts-ignore\n        this.fsPortraitStyle = null;\n        // @ts-ignore\n        this.fsSmallLandscapeStyle = null;\n        // @ts-ignore\n        this.fsSmallPortraitStyle = null;\n        // @ts-ignore\n        this.statusBarTextValues = null;\n        // @ts-ignore\n        this.initialSettings = null;\n\n        super.destroy({ children: true, texture: true });\n    }\n\n    public createFreeSpinBar(context, event): void {\n        this.blockerOverlay.disable();\n        this.fsMessageBar.createFreeSpinBar(context, event);\n        this.fsMessageBar.visible = false;\n    }\n\n    /**\n     * Use this method when want to destroy free spins message bar\n     */\n    public destroyFreeSpinBar(): void {\n        this.fsMessageBar.destroy();\n    }\n\n    public prestart(): void {\n        Core.sounds.stopAll();\n        this.rootStore.uiStore.BACKGROUND_SOUND_PLAY.next({ sound: undefined, ms: 0 });\n        Core.sounds.play('pressStartSound');\n        this.visible = true;\n        this.interactive = true;\n        this.buttonMode = true;\n        this.fsAnimations.visible = true;\n    }\n\n    public startIntro(_context, _event): void {\n        Core.sounds.stopAll();\n        this.rootStore.uiStore.BACKGROUND_SOUND_PLAY.next({ sound: undefined, ms: 0 });\n        Core.sounds.play('introSound');\n        this.blockerOverlay.enable();\n        this.fsAnimations.visible = true;\n        this.interactive = false;\n        this.buttonMode = false;\n\n        Core.stage.setDefaultCursor();\n    }\n\n    public startOutro(_totalWin): void {\n        Core.sounds.stopAll();\n        this.rootStore.uiStore.BACKGROUND_SOUND_PLAY.next({ sound: undefined, ms: 0 });\n        Core.sounds.play('outroSound');\n        this.blockerOverlay.enable();\n        this.fsAnimations.visible = true;\n        Core.stage.setDefaultCursor();\n    }\n\n    public startRetrigger(_context, _event): void {\n        this.rootStore.uiStore.BACKGROUND_SOUND_PLAY.next({ sound: undefined, ms: 0 });\n        if (Core.sounds.getSoundDuration('freeSpinsSounds', 'retriggerSound') > 0) {\n            Core.sounds.stopAll();\n            Core.sounds.play('retriggerSound');\n        } else {\n            Core.sounds.fadeInSound('freeSpinsBackgroundSound', 900);\n        }\n        this.blockerOverlay.enable();\n        this.fsAnimations.visible = true;\n        Core.stage.setDefaultCursor();\n    }\n\n    public setOrientation(context, orientation: IOrientation): void {\n        if (this.currentOrientation?.orientation !== orientation.orientation) {\n            this.fsMessageBar.setMessageBarOrientation(context, orientation);\n\n            if (this.blockerOverlay && this.blockerOverlay.visible) {\n                this.blockerOverlay.resize();\n            }\n        }\n    }\n\n    public hideStartScreen(_context?): void {\n        // implement in overwrites\n    }\n\n    public set stateMachineService(stateMachineService: any) {\n        this._stateMachineService = stateMachineService;\n    }\n    public get stateMachineService(): any {\n        return this._stateMachineService;\n    }\n\n    public updateMessageContentOnRetrigger(context, event): void {\n        this.fsMessageBar.updateMessageContentOnRetrigger(context, event);\n        this.blockerOverlay.disable();\n    }\n\n    public onInitAssets(_context, _show: boolean): void {\n        // Implement\n    }\n\n    public startSymbolAnimation(): void {\n        // for freespins with symbol animations only - implement in extended view\n    }\n\n    public hideIntroViaKeyboard(): void {\n        // for freespins with intro and intro loop animations where the loop should be skipped via keyboard - implement in extended view\n    }\n\n    public updateRemainingCounterOnFS(context, event): void {\n        this.fsMessageBar.updateRemainingCounterOnFS(context, event);\n    }\n\n    public toggleFsBar(context): void {\n        if (this.fsMessageBar) {\n            this.fsMessageBar.toggleFsBar(context);\n        }\n    }\n\n    private generateBlockerOverlay(): void {\n        this.blockerOverlay = new UIBlocker();\n        this.addChild(this.blockerOverlay);\n    }\n}\n","import Core, { AssetPriority, BaseFeature, IModeConfig, IModes, Log } from '@egt/core';\nimport { Features, RootView, ZOrders } from '@egt/slot';\nimport { Container } from 'pixi.js';\nimport { Lifecycle } from 'tsyringe';\nimport GambleModesConfigurations, { GambleModes } from './GambleModeFactory';\nimport { GambleFeatureConfigurationFactoryDefault } from './modes/default/configuration/GambleFeatureConfigurationDefault';\nimport { IGambleFeatureConfigurationDefault } from './modes/default/configuration/IGambleFeatureConfigurationDefault';\nimport { GambleFeatureConfigurationFactoryTurtle } from './modes/turtle/configuration/GambleFeatureConfigurationTurtle';\n\nexport default class GambleFeature extends BaseFeature {\n    public GAMBLE_VIEW: any;\n    public featureType: Features = Features.GAMBLE;\n    public configurationName = 'GambleFeature';\n    protected mainAssetID: string[] = ['gamble', 'gambleWinTextTranslate'];\n    private configuration: IGambleFeatureConfigurationDefault;\n\n    private gambleController: any;\n    private zIndexElement: string = 'uiMainView';\n\n    constructor(configOrModeConfig?: IModeConfig | ((base: any) => any), classType?: any, zIndexElement?: string) {\n        super();\n\n        if (zIndexElement) {\n            this.zIndexElement = zIndexElement;\n        }\n\n        // baseConfigs MUST list EVERY mode, else BaseModeFactory throws at runtime.\n        const baseConfigs = {\n            [GambleModes.DEFAULT]: GambleFeatureConfigurationFactoryDefault,\n            [GambleModes.TURTLE]: GambleFeatureConfigurationFactoryTurtle,\n        };\n\n        // Backward compatibility: old call sites pass a config-factory FUNCTION (+ optional view).\n        let modeConfig: IModeConfig = {};\n        if (typeof configOrModeConfig === 'function') {\n            modeConfig = {\n                modeType: GambleModes.DEFAULT,\n                configuration: { [GambleModes.DEFAULT]: configOrModeConfig },\n            };\n            if (classType) {\n                modeConfig.view = { [GambleModes.DEFAULT]: classType };\n            }\n        } else if (configOrModeConfig) {\n            modeConfig = configOrModeConfig;\n            // `mode` is accepted as an alias for `modeType`\n            if ((modeConfig as any).mode && !modeConfig.modeType) {\n                modeConfig.modeType = (modeConfig as any).mode;\n            }\n            if (classType && !modeConfig.view) {\n                modeConfig.view = { [modeConfig.modeType ?? GambleModes.DEFAULT]: classType };\n            }\n        }\n\n        this.modeFactory = this.initMode<GambleModesConfigurations>(modeConfig, {\n            defaultModeType: GambleModes.DEFAULT,\n            baseConfigs,\n            defaultFactory: GambleModesConfigurations,\n        });\n    }\n\n    public onGameStarted(): void {\n        this.gambleController.onGameStarted();\n    }\n\n    public onRegisterDependencies(container: any): void {\n        super.onRegisterDependencies(container);\n\n        this.dependencyContainer.register(\n            'GambleFeatureConfiguration',\n            { useClass: this.mode.configuration },\n            { lifecycle: Lifecycle.Singleton },\n        );\n\n        if (!this.dependencyContainer.isRegistered('GambleController')) {\n            this.dependencyContainer.register(\n                'GambleController',\n                { useClass: this.mode.controller },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n        if (!this.dependencyContainer.isRegistered('GambleView')) {\n            this.dependencyContainer.register(\n                'GambleView',\n                { useClass: this.mode.view },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n        this.dependencyContainer.register(\n            'GambleStore',\n            { useClass: (this.mode as IModes & { store?: any }).store },\n            { lifecycle: Lifecycle.Singleton },\n        );\n    }\n    public destroy(): void {\n        this.gambleController.destroy();\n        // @ts-ignore\n        this.gambleController = null;\n        // @ts-ignore\n        this.GAMBLE_VIEW = null;\n\n        if (this.zIndexElement) {\n            // @ts-ignore\n            this.zIndexElement = null;\n        }\n        (this.configuration as any).destroy();\n\n        // @ts-ignore\n        this.configuration = null;\n\n        super.destroy();\n    }\n\n    public onResolveDependencies(container: any): void {\n        super.onResolveDependencies(container);\n        this.gambleController = this.dependencyContainer.resolve('GambleController');\n        this.GAMBLE_VIEW = this.dependencyContainer.resolve('GambleView');\n\n        if (Core?.devTools) {\n            const scalerInstance = this.dependencyContainer.resolve('CustomScaler');\n            import('./modes/default/configuration/GambleScalerConfigInitializer')\n                .then((initializerImport) => initializerImport.default(scalerInstance))\n                .catch((err) => Log.debug('error loading scaler config file: ', err));\n        }\n    }\n    public onInitialRender(rootView: RootView): void {\n        this.GAMBLE_VIEW.zIndex = ZOrders.SPIN_BUTTONS_LEVEL - 1;\n        rootView.addChild(this.GAMBLE_VIEW);\n    }\n\n    public onPrepareResources(_rootView: Container): void {\n        Core.assets.addAssets([\n            {\n                id: 'gamble',\n                url: '../assets/features/slot/gamble/common/gamble.json',\n                priority: AssetPriority.HIGHEST,\n                type: 'texture',\n            },\n            {\n                id: 'gambleTranslate',\n                url:\n                    '../assets/features/slot/gamble/common/translations/' +\n                    Core.configuration.language.toLowerCase() +\n                    '.json',\n                priority: AssetPriority.HIGHEST,\n                type: 'translation',\n            },\n            {\n                id: 'gambleWinTextTranslate',\n                url:\n                    '../assets/features/slot/gamble/common/gambleWinTextTranslated/' +\n                    'win_' +\n                    Core.configuration.language.toLowerCase() +\n                    '.png',\n                priority: AssetPriority.HIGHEST,\n                type: 'texture',\n            },\n        ]);\n\n        this.configuration = this.dependencyContainer.resolve('GambleFeatureConfiguration');\n        Core.assets.addAssets(this.configuration.featureAssets.toArray() || []);\n\n        Core.assets.addAsset({\n            id: 'gambleSounds',\n            url: '../assets/features/slot/gamble/common/sounds/gambleSounds.mp3',\n            priority: AssetPriority.LOW,\n            type: 'sound',\n            sprite: {\n                gambleCardClick: [0, 500],\n                gambleLostSound: [2000, 1355.78231292517],\n                gambleOpenSound: [5000, 1751.4739229024947],\n                gambleWonSound: [8000, 1416.9841269841274],\n            },\n        });\n    }\n}\n","import { BaseModesConfigurations, IForceSetConfig, IModes } from '@egt/core';\nimport { GambleFeatureConfigurationFactoryDefault } from './modes/default/configuration/GambleFeatureConfigurationDefault';\nimport GambleControllerDefault from './modes/default/controllers/GambleControllerDefault';\nimport GambleStoreDefault from './modes/default/stores/GambleStoreDefault';\nimport GambleViewDefault from './modes/default/views/GambleViewDefault';\nimport { GambleFeatureConfigurationFactoryTurtle } from './modes/turtle/configuration/GambleFeatureConfigurationTurtle';\n\nexport default class GambleModesConfigurations extends BaseModesConfigurations<GambleModes> {\n    constructor(modeType: GambleModes, forceSetConfig?: IForceSetConfig) {\n        super(modeType, forceSetConfig);\n    }\n\n    protected createBaseModesConfig(modeType: GambleModes): IModes {\n        switch (modeType) {\n            case GambleModes.TURTLE:\n                return {\n                    controller: GambleControllerDefault,\n                    view: GambleViewDefault,\n                    store: GambleStoreDefault,\n                    configuration: GambleFeatureConfigurationFactoryTurtle(),\n                } as IModes;\n            default:\n                return {\n                    controller: GambleControllerDefault,\n                    view: GambleViewDefault,\n                    store: GambleStoreDefault,\n                    configuration: GambleFeatureConfigurationFactoryDefault(),\n                } as IModes;\n        }\n    }\n}\n\nexport enum GambleModes {\n    DEFAULT = 'default',\n    TURTLE = 'turtle',\n}\n","import GambleFeature from './GambleFeature';\nimport GambleModesConfigurations, { GambleModes } from './GambleModeFactory';\n\n// ---- default mode ----\nimport { IGambleFeatureConfigurationDefault } from './modes/default/configuration/IGambleFeatureConfigurationDefault';\nimport GambleFeatureConfigurationDefault, {\n    GambleFeatureConfigurationFactoryDefault,\n} from './modes/default/configuration/GambleFeatureConfigurationDefault';\nimport GambleControllerDefault from './modes/default/controllers/GambleControllerDefault';\nimport GambleStoreDefault from './modes/default/stores/GambleStoreDefault';\nimport GambleViewDefault from './modes/default/views/GambleViewDefault';\nimport GambleRequest from './modes/default/data/GambleRequest';\n\n// ---- turtle mode ----\nimport { IGambleFeatureConfigurationTurtle } from './modes/turtle/configuration/IGambleFeatureConfigurationTurtle';\nimport GambleFeatureConfigurationTurtle, {\n    GambleFeatureConfigurationFactoryTurtle,\n} from './modes/turtle/configuration/GambleFeatureConfigurationTurtle';\n\n// ---- shared configuration interfaces ----\nimport { IAutoScalable } from './modes/default/configuration/IAutoScalable';\nimport { IBackgroundVisibility } from './modes/default/configuration/IBackgroundVisibility';\nimport { IButtonInterface } from './modes/default/configuration/IButtonInterface';\nimport { IGambleBalanceAndWinText } from './modes/default/configuration/IGambleBalanceAndWinText';\nimport { IGambleButtonData } from './modes/default/configuration/IGambleButtonData';\nimport { IGambleMoney, IGambleMoneyConfig } from './modes/default/configuration/IGambleMoneyConfig';\nimport { IGambleOverlaySettings } from './modes/default/configuration/IGambleOverlaySettings';\nimport { IGambleTextStyles } from './modes/default/configuration/IGambleTextStyles';\nimport { IPointWithScale } from './modes/default/configuration/IPointWithScale';\n\nimport(\n    /* webpackChunkName: \"features/gamble-styles\" */\n\n    './modes/default/styles.js'\n);\n\nexport {\n    GambleModes,\n    GambleModesConfigurations,\n    // default mode\n    IGambleFeatureConfigurationDefault,\n    GambleFeatureConfigurationDefault,\n    GambleFeatureConfigurationFactoryDefault,\n    GambleControllerDefault,\n    GambleViewDefault,\n    GambleStoreDefault,\n    GambleRequest,\n    // turtle mode\n    IGambleFeatureConfigurationTurtle,\n    GambleFeatureConfigurationTurtle,\n    GambleFeatureConfigurationFactoryTurtle,\n    // shared configuration interfaces\n    IBackgroundVisibility,\n    IGambleMoneyConfig,\n    IGambleTextStyles,\n    IGambleButtonData,\n    IGambleOverlaySettings,\n    IGambleBalanceAndWinText,\n    IPointWithScale,\n    IButtonInterface,\n    IAutoScalable,\n    IGambleMoney,\n};\nexport default GambleFeature;\n","import {\n    AssetPriority,\n    AssetsCollection,\n    BaseComponentConfiguration,\n    DefaultAssets,\n    DefaultValue,\n    DynamicPositionObject,\n} from '@egt/core';\nimport { TextAlign } from '@egt/ui-lib';\nimport { IPointData, ISize, TextStyle } from 'pixi.js';\nimport { IAutoScalable } from './IAutoScalable';\nimport { IBackgroundVisibility } from './IBackgroundVisibility';\nimport { IButtonInterface } from './IButtonInterface';\nimport { IGambleBalanceAndWinText } from './IGambleBalanceAndWinText';\nimport { IGambleButtonData } from './IGambleButtonData';\nimport { IBooleanData, IGambleFeatureConfigurationDefault } from './IGambleFeatureConfigurationDefault';\nimport { IGambleMoney } from './IGambleMoneyConfig';\nimport { IGambleOverlaySettings } from './IGambleOverlaySettings';\nimport { IGambleTextStyles } from './IGambleTextStyles';\nimport { IPointWithScale } from './IPointWithScale';\nexport default class GambleFeatureConfigurationDefault extends BaseComponentConfiguration {}\nexport function GambleFeatureConfigurationFactoryDefault(): any {\n    class GambleFeatureConfigurationInternal\n        extends GambleFeatureConfigurationDefault\n        implements IGambleFeatureConfigurationDefault\n    {\n        @DefaultAssets([\n            {\n                id: 'svgGambleX2',\n                url: '../assets/features/slot/gamble/modes/default/ui-svg/x2Button.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 132, height: 132 },\n                    desktop: { width: 100, height: 100 },\n                },\n            },\n            {\n                id: 'svgGambleX2Inactive',\n                url: '../assets/features/slot/gamble/modes/default/ui-svg/x2ButtonInactive.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 132, height: 132 },\n                    desktop: { width: 100, height: 100 },\n                },\n            },\n            {\n                id: 'svgGambleFrameX2',\n                url: '../assets/features/slot/gamble/modes/default/ui-svg/x2Frame.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 132, height: 132 },\n                    desktop: { width: 100, height: 100 },\n                },\n            },\n            {\n                id: 'svgCollect',\n                url: '../assets/features/slot/gamble/modes/default/ui-svg/collectButton.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 219, height: 219 },\n                    desktop: { width: 150, height: 150 },\n                },\n            },\n            {\n                id: 'svgCollectDisabled',\n                url: '../assets/features/slot/gamble/modes/default/ui-svg/collectButtonDisabled.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 219, height: 219 },\n                    desktop: { width: 150, height: 150 },\n                },\n            },\n        ])\n        public featureAssets: AssetsCollection;\n\n        public historyCardCounts: number = 5;\n\n        public moneyContainerTitleY: number = 10;\n        public historyTextKey: string = 'GAMBLE.HISTORY';\n        public selectTextOrnamentAsset: string[] = [];\n        public buttonsToHide: string[] = [];\n        public buttonsToShow: string[] = [];\n        public animationAssetInitialValues: object = {};\n        public setDifferentGambleToWinTextPositions: boolean = false;\n        public setDifferentGambleToWinMoneyPositions: boolean = false;\n        public gamblesLeftTextSpacing: number = 10;\n        public gambleWaitTime: number = 2000;\n        public buttonTextMargin: number = 50;\n        public gambleAnimationConfiguration: object[] = [\n            { rotation: 0 },\n            {\n                duration: 200,\n                rotation: 359,\n                repeat: -1,\n                ease: 'None',\n            },\n        ];\n        @DefaultValue<IPointData>({\n            defaults: { x: 0, y: 0 },\n        })\n        public gambleContainer: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IBooleanData>({\n            defaults: {\n                value: false,\n            },\n        })\n        public useVideoForBtnAnimation: DynamicPositionObject<IBooleanData> & IBooleanData;\n\n        @DefaultValue<IButtonInterface>({\n            defaults: {\n                x: 382,\n                y: 1060,\n                width: 0,\n                height: 0,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n                scale: 1,\n                visible: true,\n                textures: ['svgCollect', 'svgCollect', 'svgCollect', 'svgCollectDisabled'],\n                texturesSpecial: [\n                    'svgCollectButtonSpecial',\n                    'svgCollectButtonSpecial',\n                    'svgCollectButtonSpecial',\n                    'svgCollectButtonDisabledSpecial',\n                ],\n            },\n            landscape: { x: 1241, y: 276, leftHandX: 119 },\n            desktop: { x: 1271, y: 342 },\n        })\n        public collectButtonPosition: DynamicPositionObject<IButtonInterface> & IButtonInterface;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 1, y: 1 },\n        })\n        public gambleContainerScale: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointWithScale>({\n            defaults: { x: 0, y: 0, scale: 0 },\n        })\n        public selectTextOrnament: DynamicPositionObject<IPointWithScale> & IPointWithScale;\n\n        @DefaultValue<IGambleOverlaySettings>({\n            defaults: { visible: false, fill: 0x000000, alpha: 0.75 },\n        })\n        public gambleOverlay: DynamicPositionObject<IGambleOverlaySettings> & IGambleOverlaySettings;\n\n        @DefaultValue<ISize>({\n            defaults: { width: 280, height: 80 },\n            portrait: { width: 230 },\n        })\n        public moneyContainersSize: DynamicPositionObject<ISize> & ISize;\n\n        @DefaultValue<ISize>({\n            defaults: { width: 280, height: 33 },\n            portrait: { width: 230, height: 18 },\n        })\n        public moneyBounds: DynamicPositionObject<ISize> & ISize;\n\n        @DefaultValue<IGambleMoney>({\n            defaults: {\n                gambleMoney: {\n                    textAlign: TextAlign.CENTER,\n                    moneyFontSize: 22,\n                    centsFontSize: 22,\n                    currencyFontSize: 22,\n                },\n                gambleContainers: {\n                    textAlign: TextAlign.CENTER,\n                    moneyFontSize: 40,\n                    centsFontSize: 40,\n                    currencyFontSize: 20,\n                },\n            },\n        })\n        public moneyConfig: DynamicPositionObject<IGambleMoney> & IGambleMoney;\n\n        @DefaultValue<ISize>({\n            defaults: { width: 41, height: 57 },\n        })\n        public historyCardSize: DynamicPositionObject<ISize> & ISize;\n\n        @DefaultValue<IGambleButtonData>({\n            defaults: { x: 1219, y: 35, leftHandX: 0, scale: 1 },\n            landscape: { leftHandX: 9 },\n            portrait: { x: 121, y: 995 },\n            desktop: { x: 1222.5, y: 149.5 },\n        })\n        public buttonPosition: DynamicPositionObject<IGambleButtonData> & IGambleButtonData;\n\n        @DefaultValue<IBackgroundVisibility>({\n            defaults: { visible: 'landscape', invisible: 'portrait' },\n            portrait: { visible: 'portrait', invisible: 'landscape' },\n            desktop: { visible: 'landscape', invisible: 'portrait' },\n        })\n        public backgroundVisibility: DynamicPositionObject<IBackgroundVisibility> & IBackgroundVisibility;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 134, y: 63 },\n            portrait: { x: -17, y: 247 },\n            desktop: { x: 165, y: 67 },\n        })\n        public backgroundPosition: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<ISize>({\n            defaults: { width: 1092, height: 702 },\n            portrait: { width: 791, height: 709 },\n            desktop: { width: 1030, height: 580 },\n        })\n        public backgroundSize: DynamicPositionObject<ISize> & ISize;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 185, y: 132 },\n            portrait: { x: 3, y: 325 },\n            desktop: { x: 200, y: 115 },\n        })\n        public gambleAmountValue: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 0, y: 0 },\n        })\n        public gambleAmountText: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 0, y: 0 },\n        })\n        public gambleAmountTextScale: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 890, y: 132 },\n            portrait: { x: 533, y: 325 },\n            desktop: { x: 875, y: 115 },\n        })\n        public gambleToWinValue: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 0, y: 0 },\n        })\n        public gambleToWinMoneyPosition: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 140, y: 22 },\n            portrait: { x: 115, y: 22 },\n        })\n        public amountAndWinTextPositions: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 0, y: 0 },\n        })\n        public gambleToWinTextPosition: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 0, y: 40 },\n        })\n        public amountAndWinMoneyPositions: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IGambleBalanceAndWinText>({\n            defaults: { x: 184, y: 710, separator: ': ', visible: true },\n            portrait: { x: 30, y: 910 },\n            desktop: { visible: false },\n        })\n        public balanceText: DynamicPositionObject<IGambleBalanceAndWinText> & IGambleBalanceAndWinText;\n\n        @DefaultValue<IGambleBalanceAndWinText>({\n            defaults: { x: 1176, y: 710, separator: ': ', visible: true },\n            portrait: { x: 735, y: 910 },\n            desktop: { visible: false },\n        })\n        public winText: DynamicPositionObject<IGambleBalanceAndWinText> & IGambleBalanceAndWinText;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 680, y: 85 },\n            portrait: { x: 382, y: 280 },\n            desktop: { y: 77 },\n        })\n        public titleText: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IAutoScalable>({\n            defaults: { x: 680, y: 550, maxWidth: 0 },\n            portrait: { x: 382, y: 785, maxWidth: 750 },\n            landscape: { maxWidth: 950 },\n            desktop: { y: 530, maxWidth: 900 },\n        })\n        public chooseText: DynamicPositionObject<IAutoScalable> & IAutoScalable;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 680, y: 140 },\n            portrait: { x: 382, y: 340 },\n            desktop: { y: 137 },\n        })\n        public historyText: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 234, y: 288 },\n            portrait: { x: 35, y: 508 },\n            desktop: { x: 265, y: 300 },\n        })\n        public redButton: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 1, y: 1 },\n        })\n        public redButtonScale: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 950, y: 288 },\n            portrait: { x: 554, y: 508 },\n            desktop: { x: 919, y: 300 },\n        })\n        public blackButton: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 1, y: 1 },\n        })\n        public blackButtonScale: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 680, y: 660 },\n            portrait: { x: 382, y: 875 },\n            desktop: { y: 615 },\n        })\n        public gambleAttemptsLeft: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointWithScale>({\n            defaults: { x: 680, y: 377, scale: 1 },\n            portrait: { x: 382, y: 597 },\n        })\n        public animatedCards: DynamicPositionObject<IPointWithScale> & IPointWithScale;\n\n        @DefaultValue<ISize>({\n            defaults: { width: 183, height: 254 },\n        })\n        public gambleCardSize: DynamicPositionObject<ISize> & ISize;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 680, y: 377 },\n            portrait: { x: 382, y: 597 },\n        })\n        public winTextImage: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 555, y: 165 },\n            portrait: { x: 260, y: 365 },\n        })\n        public historyCardsStart: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 10, y: 0 },\n            portrait: { x: 10, y: 0 },\n        })\n        public historyCardsOffset: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IGambleTextStyles>({\n            defaults: {\n                redText: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 32,\n                    fontWeight: 'bold',\n                    fill: '#FFFFFF',\n                }),\n                blackText: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 32,\n                    fontWeight: 'bold',\n                    fill: '#FFFFFF',\n                }),\n                balanceText: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 18,\n                    fill: '#FFFFFF',\n                    padding: 5,\n                }),\n                winText: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 18,\n                    fill: '#FFFFFF',\n                    padding: 5,\n                }),\n                titleText: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 33,\n                    fontWeight: 'bold',\n                    fill: '#FFFFFF',\n                    padding: 5,\n                }),\n                historyText: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 18,\n                    fill: '#FFFFFF',\n                    padding: 5,\n                }),\n                titlesText: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 20,\n                    fontWeight: 'bold',\n                    fill: '#FFD200',\n                    padding: 5,\n                }),\n                gambleChooseText: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 22,\n                    fontWeight: 'bold',\n                    fill: '#FFFFFF',\n                    padding: 5,\n                }),\n                gamblesLeftValueText: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 20,\n                    fontWeight: 'bold',\n                    fill: '#FFD200',\n                    padding: 5,\n                }),\n                gamblesLeftText: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 20,\n                    padding: 3,\n                    fontWeight: 'bold',\n                    fill: '#FFFFFF',\n                }),\n                valuesText: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 32,\n                    fontWeight: 'bold',\n                    fill: '#FFFFFF',\n                }),\n            },\n            portrait: {\n                titlesText: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 17,\n                    fontWeight: 'bold',\n                    fill: '#FFD200',\n                    padding: 5,\n                }),\n                gambleChooseText: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 18,\n                    fontWeight: 'bold',\n                    fill: '#FFFFFF',\n                    padding: 5,\n                }),\n            },\n        })\n        public textStyles: DynamicPositionObject<IGambleTextStyles> & IGambleTextStyles;\n    }\n    return GambleFeatureConfigurationInternal;\n}\n","import { BackgroundMusic } from '@egt/background-sound';\nimport Core, { BaseController } from '@egt/core';\nimport {\n    BangupActionConsts,\n    BetResponse,\n    Features,\n    InitialSettings,\n    RootStore,\n    SlotComponents,\n    UIState,\n} from '@egt/slot';\nimport { Subject, fromEvent, merge } from 'rxjs';\nimport { filter, takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { Machine, assign, interpret } from 'xstate';\nimport { IGambleFeatureConfigurationDefault } from '../configuration/IGambleFeatureConfigurationDefault';\nimport GambleRequest from '../data/GambleRequest';\nimport GambleResponse from '../data/GambleResponse';\nimport GambleConsts from '../enums/GambleConsts';\nimport GambleState from '../enums/GambleState';\nimport GambleStoreDefault from '../stores/GambleStoreDefault';\nimport GambleViewDefault from '../views/GambleViewDefault';\n\n@injectable()\nexport default class GambleControllerDefault extends BaseController {\n    protected stateMachineService;\n    private eventsAdded: boolean = false;\n    private statehMachine;\n    private GambleClosed = new Subject();\n    private settingsOpened: boolean = false;\n    private hasMultilayeredBGSound: boolean = false;\n\n    /**\n     *\n     * @param rootStore\n     * @param view\n     * @param store\n     * @param uiView\n     * @param settings\n     */\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('GambleView') protected view: GambleViewDefault,\n        @inject('GambleStore') protected store: GambleStoreDefault,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('GambleFeatureConfiguration') protected featureConfig: IGambleFeatureConfigurationDefault,\n    ) {\n        super(view);\n        this.createStateMachine();\n        this.view.initialRenderrer();\n\n        Core.ON_SERVER_MESSAGE.pipe(takeUntil(this.DESTROY)).subscribe(this.onMessage.bind(this));\n        this.rootStore.domainStore.BET.pipe(takeUntil(this.DESTROY)).subscribe(this.updateHistory.bind(this));\n        this.rootStore.uiStore.COLLECT_CLICKED.chainSubscribe(Features.GAMBLE, this.collectWin.bind(this));\n        if (Core.configuration.mode !== 'mobile') {\n            this.rootStore.subjects.KEY_UP.pipe(takeUntil(this.DESTROY)).subscribe(this.onKeyReleased.bind(this));\n        }\n        this.rootStore.uiStore.STATE.pipe(takeUntil(this.DESTROY)).subscribe(this.onStateChanged.bind(this));\n        this.rootStore.subjects.FEATURE_FINISHED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onFeatureFinished.bind(this),\n        );\n        this.rootStore.subjects.SETTINGS_POPUP_CLOSED.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.settingsOpened = false;\n        });\n\n        this.rootStore.subjects.SETTINGS_POPUP_OPENED.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.settingsOpened = true;\n        });\n        this.rootStore.uiStore.gamblesLeft = this.settings.gambles;\n\n        this.view.gambleButton.CLICK.pipe(\n            filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n            takeUntil(this.DESTROY),\n        ).subscribe(this.onGambleClicked.bind(this));\n\n        this.view.collectButton.CLICK.pipe(\n            filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n            takeUntil(this.DESTROY),\n        ).subscribe(this.collectWin.bind(this));\n\n        if (Core.hasComponent(SlotComponents.MULTILAYERED_BG_SOUND)) {\n            this.hasMultilayeredBGSound = true;\n        }\n    }\n\n    public onGameStarted(): void {\n        if (this.settings.settings.game) {\n            const result = this.settings.settings.game.result;\n            if (result && result.type && result.type === 'GAMBLE') {\n                const gambleHistory = this.settings.settings.game.state.gambleHistory;\n                // const gambleResponse = new GambleResponse(this.settings.settings);\n                this.rootStore.uiStore.HISTORY.next(gambleHistory.reverse());\n                this.rootStore.uiStore.WIN.next({\n                    amount: this.settings.settings.game.result.totalWinAmount,\n                    action: BangupActionConsts.SET,\n                    feature: Features.GAMBLE,\n                });\n                this.rootStore.subjects.GAMBLE_OPENED.next(true);\n                this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_OUTSIDE_BETS_VISIBLE.next(false);\n                this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_BTN_VISIBLE.next(false);\n\n                this.rootStore.domainStore.SPIN_MODE.next(Features.GAMBLE);\n                this.rootStore.subjects.BEFORE_SPIN.next();\n                this.openGamble(false);\n                if (this.settings.settings.game.restore) {\n                    const reels =\n                        this.settings.settings.game.restore[this.settings.settings.game.result.restorePoints[0]]\n                            .spins[0].reels;\n                    this.rootStore.uiStore.drawNow = true;\n                    this.rootStore.uiStore.REAL_REELS.next(reels);\n                }\n            }\n        }\n    }\n\n    public destroy(): void {\n        if (this.GambleClosed) {\n            this.GambleClosed.complete();\n            // @ts-ignore\n            this.GambleClosed = null;\n        }\n\n        this.stateMachineService.stop();\n        this.stateMachineService = null;\n        this.statehMachine = null;\n        super.destroy();\n    }\n\n    // protected onCollectBtnClicked(): void {\n    //     this.rootStore.uiStore.STATE.next(UIState.DISABLED);\n    //     this.view.collectButton.enabled = false;\n    //     this.rootStore.uiStore.COLLECT_CLICKED.next();\n    // }\n\n    protected onFeatureFinished(feature: Features): void {\n        // https://jira.egt-digital.com/browse/ON-9254\n        // if check here because not sure what if another feature is finished\n        if (feature === Features.FREE_SPINS && !this.rootStore.domainStore.betResponse.bonus) {\n            this.view.gambleButton.visible = true;\n            this.view.gambleButton.enabled = false;\n            this.view.setBtnAnimVisible(false);\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'autoPlayButton',\n                actions: 'visible',\n                values: false,\n            });\n        }\n    }\n\n    protected gambleUIButtonsState(): void {\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'spinButton',\n            actions: ['visible', 'enabled'],\n            values: false,\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'spinSpeedButton',\n            actions: 'visible',\n            values: false,\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'instaSpinsButton',\n            actions: 'enabled',\n            values: false,\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'spinSpeedButtonDisabled',\n            actions: 'visible',\n            values: true,\n        });\n        if (this.settings.autoplay === false) {\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'autoPlayButton',\n                actions: ['visible', 'enabled'],\n                values: false,\n            });\n        } else {\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'autoPlayButton',\n                actions: ['visible', 'enabled'],\n                values: [true, false],\n            });\n        }\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'stopButton',\n            actions: ['visible', 'enabled'],\n            values: false,\n        });\n\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'denominationButton',\n            actions: ['visible', 'enabled'],\n            values: [true, false],\n        });\n\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'collectSmallButton',\n            actions: ['visible', 'enabled'],\n            values: false,\n        });\n\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'betPlusBtn',\n            actions: 'enabled',\n            values: false,\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'betMinusBtn',\n            actions: 'enabled',\n            values: false,\n        });\n\n        if (this.featureConfig.buttonsToHide.length !== 0) {\n            this.hideCustomButtons();\n        }\n    }\n\n    protected waitingForStateChangeUIButtonsState(): void {\n        if (this.settings.autoplay === false) {\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'autoPlayButton',\n                actions: ['visible', 'enabled'],\n                values: false,\n            });\n        } else {\n            this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                name: 'autoPlayButton',\n                actions: ['visible', 'enabled'],\n                values: [true, false],\n            });\n        }\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'denominationButton',\n            actions: ['visible', 'enabled'],\n            values: [true, false],\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'spinSpeedButton',\n            actions: 'visible',\n            values: false,\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'instaSpinsButton',\n            actions: 'enabled',\n            values: false,\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'spinSpeedButtonDisabled',\n            actions: 'visible',\n            values: true,\n        });\n        this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n            name: 'instaSpinsButton',\n            actions: 'visible',\n            values: true,\n        });\n        if (this.featureConfig.buttonsToHide.length !== 0) {\n            this.hideCustomButtons();\n        }\n    }\n\n    protected hideCustomButtons(): void {\n        this.featureConfig.buttonsToHide.forEach((btnName) => {\n            if (btnName === 'autoPlayButton' || btnName === 'denominationButton') {\n                this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                    name: btnName,\n                    actions: ['visible', 'enabled'],\n                    values: false,\n                });\n            } else if (btnName === 'betButtons') {\n                this.rootStore.uiStore.SHOW_HIDE_BET_BUTTONS.next(false);\n            } else {\n                this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                    name: btnName,\n                    actions: 'visible',\n                    values: false,\n                });\n            }\n        });\n    }\n\n    protected showCustomButtons(): void {\n        this.featureConfig.buttonsToShow.forEach((btnName) => {\n            if (btnName === 'betButtons') {\n                this.rootStore.uiStore.SHOW_HIDE_BET_BUTTONS.next(true);\n            } else {\n                this.rootStore.subjects.PROCCESS_UI_VIEW_COMPONENTS.next({\n                    name: btnName,\n                    actions: 'visible',\n                    values: true,\n                });\n            }\n        });\n    }\n\n    /**\n     *\n     */\n    protected onStateChanged(newState: UIState): void {\n        switch (newState) {\n            case UIState.WAITING_FOR_COLLECT:\n                //  case UIState.COLLECT_BEFORE_IDLE:\n                if (!this.rootStore.domainStore.betResponse?.bonus) {\n                    this.view.gambleButton.visible = true;\n                    this.view.gambleButton.enabled = this.rootStore.uiStore.gamblesLeft > 0;\n                }\n                this.view.setBtnAnimVisible(this.view.gambleButton.enabled);\n                if (this.view.isBtnVisible()) {\n                    this.view.playAnimation();\n                }\n                this.view.collectButton.visible = false;\n                break;\n            case UIState.GAMBLE:\n                this.gambleUIButtonsState();\n\n                this.view.collectButton.visible = true;\n                this.view.collectButton.enabled = true;\n                this.view.gambleButton.visible = false;\n                this.view.gambleButton.enabled = false;\n                this.view.stopAnimation();\n                break;\n            case UIState.LAST_GAMBLE_WIN:\n                this.view.collectButton.enabled = false;\n                break;\n            case UIState.SLIDING_BETS:\n            case UIState.DISABLED:\n                this.view.collectButton.enabled = false;\n                this.view.gambleButton.enabled = false;\n                this.view.setBtnAnimVisible(false);\n                this.view.stopAnimation();\n                break;\n            case UIState.WAITING_FOR_STATE_CHANGE:\n                this.waitingForStateChangeUIButtonsState();\n                this.view.collectButton.visible = true;\n                this.view.collectButton.enabled = false;\n                break;\n            default:\n                if (this.rootStore.domainStore.SPIN_MODE.value === Features.CAMPAIGN_MANAGER) {\n                    break;\n                }\n\n                this.view.gambleButton.visible = false;\n                this.view.gambleButton.enabled = false;\n                this.view.collectButton.visible = false;\n                this.view.collectButton.enabled = false;\n                this.view.stopAnimation();\n                break;\n        }\n    }\n\n    /**\n     *\n     * @param context\n     * @param event\n     */\n    protected showGambleView(context, _event): void {\n        this.store.state = GambleState.GAMBLE_IDLE;\n        if (!this.rootStore.subjects.ACTIVE_FEATURE.value.includes(Features.GAMBLE)) {\n            this.rootStore.subjects.FEATURE_STARTED.next(Features.GAMBLE);\n        }\n        this.view.show(context);\n\n        if (!this.eventsAdded) {\n            this.eventsAdded = true;\n            this.view.gambleRedButton.CLICK.pipe(\n                filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n                takeUntil(this.DESTROY),\n            ).subscribe(this.onGambleButtonClicked.bind(this, GambleConsts.RED));\n\n            this.view.gambleBlackButton.CLICK.pipe(\n                filter((_x) => !this.rootStore.subjects.KEY_DOWN.value),\n                takeUntil(this.DESTROY),\n            ).subscribe(this.onGambleButtonClicked.bind(this, GambleConsts.BLACK));\n\n            (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/features/slot/gamble/src/egt/modes/default/controllers/GambleControllerDefault.ts:375:13\",(this.view),\"pointerup\"]), fromEvent(this.view, 'pointerup'))\n                .pipe(takeUntil(this.DESTROY))\n                .subscribe(this.onGambleViewClick.bind(this));\n        }\n\n        this.rootStore.uiStore.STATE.next(UIState.GAMBLE);\n    }\n\n    /**\n     *\n     * @param context\n     * @param event\n     */\n    protected hideGamble(context, event): void {\n        // this.view.hide();\n        // this.GambleClosed.next();\n        this.store.state = GambleState.NONE;\n        this.rootStore.subjects.GAMBLE_OPENED.next(false);\n\n        this.rootStore.uiStore.CLEAR_LINES.next();\n        this.rootStore.domainStore.SPIN_MODE.next(Features.MANUAL_SPIN);\n        if (this.rootStore.subjects.MAX_WIN_LIMIT_HIT.value) {\n            this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_COLLECT);\n            // if MAX WIN IS HIT THE finishGamble is not called in any reason????\n            this.finishGamble(context, event);\n        } else {\n            if (context.changeStateOnExit) {\n                this.rootStore.uiStore.STATE.next(this.rootStore.domainStore.SERVER_STATE.value);\n            }\n        }\n        if (this.hasMultilayeredBGSound) {\n            const currentBackgroundSoundLayer: BackgroundMusic = this.rootStore.subjects.BG_SOUND_LAYER.value;\n            this.rootStore.uiStore.BACKGROUND_SOUND_PLAY.next({ sound: currentBackgroundSoundLayer, ms: 800 });\n        } else {\n            // in case of gamble win bgsound controller will play bg music (onCollectChanged)\n            // so we must skip playing it again to prevent overlapping\n            const isBgMusicOn = this.rootStore.uiStore.BACKGROUND_SOUND_PLAY.value.sound === 'backgroundMusic';\n            if (!isBgMusicOn) {\n                this.rootStore.uiStore.BACKGROUND_SOUND_PLAY.next({ sound: 'backgroundMusic', ms: 800 });\n            }\n        }\n        this.view.collectButton.enabled = false;\n    }\n\n    /**\n     *\n     */\n    protected collectWin(): void {\n        this.hideButtons({}, {});\n        if (this.rootStore.subjects.MAX_WIN_LIMIT_HIT.value) {\n            this.stateMachineService.send({ type: 'ON_RESTORE' });\n        } else {\n            this.rootStore.domainStore.collect();\n            this.rootStore.uiStore.COLLECT_CHANGED.next();\n            this.stateMachineService.send({ type: 'COLLECT' });\n        }\n    }\n    /**\n     *\n     * @param context\n     * @param event\n     */\n    protected hideButtons(_context, _event): void {\n        this.view.collectButton.enabled = false;\n        this.view.hideGambleButtons();\n    }\n\n    /**\n     *\n     */\n    private createStateMachine(): void {\n        const isWin = this.isWin.bind(this);\n        const isX2ButtonVisibleAndUINotBlocked = this.isX2ButtonVisibleAndUINotBlocked.bind(this);\n        const isX2ButtonVisibleAndUINotBlockedInKiosk = this.isX2ButtonVisibleAndUINotBlockedInKiosk.bind(this);\n        const isFirst = this.isFirst.bind(this);\n        const onGambleClicked = this.onGambleClicked.bind(this);\n        const onColorButtonShortCut = this.onColorButtonShortCut.bind(this);\n        const onCollect = this.collectWin.bind(this);\n        const isLastWin = this.isLastWin.bind(this);\n        const showGambleView = this.showGambleView.bind(this);\n        const onLastWin = this.onLastWin.bind(this);\n        const hideGamble = this.hideGamble.bind(this);\n        const onWin = this.onWin.bind(this);\n        const onLose = this.onLose.bind(this);\n        const updateFirstCardInHistory = this.updateFirstCardInHistory.bind(this);\n        const hideButtons = this.hideButtons.bind(this);\n        const modeChanged = this.modeChanged.bind(this);\n        const finishGamble = this.finishGamble.bind(this);\n        const updateState = assign(this.updateState.bind(this));\n\n        this.statehMachine = Machine(\n            {\n                id: 'gamble',\n                context: this.store,\n                initial: 'readyToStart',\n                states: {\n                    readyToStart: {\n                        on: {\n                            // Keyboard Shortcuts\n                            ArrowUp: { cond: 'isX2ButtonVisibleAndUINotBlocked', actions: ['onGambleClicked'] },\n                            Numpad8: { cond: 'isX2ButtonVisibleAndUINotBlocked', actions: ['onGambleClicked'] },\n                            // Enable gamble opening with left and right arrows clicked as per request for the VLT\n                            ArrowLeft: {\n                                cond: 'isX2ButtonVisibleAndUINotBlockedInKiosk',\n                                actions: ['onGambleClicked'],\n                            },\n                            Numpad4: { cond: 'isX2ButtonVisibleAndUINotBlockedInKiosk', actions: ['onGambleClicked'] },\n                            ArrowRight: {\n                                cond: 'isX2ButtonVisibleAndUINotBlockedInKiosk',\n                                actions: ['onGambleClicked'],\n                            },\n                            Numpad6: { cond: 'isX2ButtonVisibleAndUINotBlockedInKiosk', actions: ['onGambleClicked'] },\n                            // -------------------\n                            INITIALIZE: [{ target: 'idle', actions: ['updateState'] }],\n                        },\n                    },\n                    idle: {\n                        entry: ['showGambleView'],\n                        on: {\n                            // Keyboard Shortcuts\n                            ArrowDown: { actions: ['onCollect'] },\n                            Numpad2: { actions: ['onCollect'] },\n                            ArrowLeft: { actions: ['onColorButtonShortCut'] },\n                            Numpad4: { actions: ['onColorButtonShortCut'] },\n                            ArrowRight: { actions: ['onColorButtonShortCut'] },\n                            Numpad6: { actions: ['onColorButtonShortCut'] },\n                            // -------------------\n                            MODE_CHANGED: { actions: 'modeChanged' },\n                            SELECT_CARD: 'waitingForResponse',\n\n                            COLLECT: { target: 'readyToStart', actions: ['hideGamble'] },\n                            ON_RESTORE: { target: 'readyToStart', actions: ['hideGamble'] },\n                        },\n                    },\n                    win: {\n                        entry: ['onWin'],\n                        after: {\n                            GambleWait: [{ cond: isLastWin, actions: ['onLastWin'] }, { target: 'idle' }],\n                        },\n                        on: {\n                            ON_RESTORE: { target: 'readyToStart', actions: ['hideGamble'] },\n                        },\n                    },\n                    lose: {\n                        entry: ['onLose'],\n                        after: {\n                            1500: { actions: ['finishGamble'] },\n                        },\n                        on: {\n                            ON_RESTORE: { target: 'readyToStart', actions: ['hideGamble'] },\n                        },\n                    },\n                    waitingForResponse: {\n                        entry: ['hideButtons'],\n                        exit: ['updateState', 'updateFirstCardInHistory'],\n                        on: {\n                            GAMBLE_RESPONSE: [\n                                {\n                                    target: 'win',\n                                    cond: isWin,\n                                },\n                                {\n                                    target: 'lose',\n                                },\n                            ],\n                        },\n                    },\n                },\n            },\n            {\n                actions: {\n                    showGambleView,\n                    updateState,\n                    onGambleClicked,\n                    onColorButtonShortCut,\n                    hideButtons,\n                    onLose,\n                    hideGamble,\n                    onLastWin,\n                    onWin,\n                    onCollect,\n                    modeChanged,\n                    finishGamble,\n                    updateFirstCardInHistory,\n                },\n                guards: {\n                    isWin,\n                    isLastWin,\n                    isX2ButtonVisibleAndUINotBlocked,\n                    isX2ButtonVisibleAndUINotBlockedInKiosk,\n                    isFirst,\n                },\n                delays: {\n                    GambleWait: (_context, _event) => {\n                        return this.featureConfig.gambleWaitTime;\n                    },\n                },\n            },\n        );\n\n        this.stateMachineService = interpret(this.statehMachine, { devTools: Core.configuration.devTools }).start();\n    }\n\n    /**\n     *\n     */\n    private onGambleClicked(): void {\n        if (this.rootStore.subjects.SHOW_JP_STATS.value.type !== -1) {\n            return;\n        }\n        if (this.view.gambleButton.enabled && !this.settingsOpened) {\n            if (this.hasMultilayeredBGSound) {\n                const currentBackgroundSoundLayer: BackgroundMusic = this.rootStore.subjects.BG_SOUND_LAYER.value;\n                Core.sounds.fadeOutSound(currentBackgroundSoundLayer as string, 500, 0);\n            } else {\n                Core.sounds.stopAll(['backgroundMusic']);\n                this.rootStore.uiStore.BACKGROUND_SOUND_PLAY.next({ sound: undefined, ms: 0 });\n            }\n            Core.sounds.play('gambleOpenSound');\n            this.rootStore.uiStore.CLEAR_BANG_UP.next();\n            this.openGamble(true);\n            this.rootStore.subjects.BEFORE_SPIN.next();\n        }\n    }\n\n    /**\n     *\n     * @param context\n     * @param event\n     */\n    private onColorButtonShortCut(_context, event): void {\n        this.onGambleButtonClicked(\n            event.type === 'ArrowLeft' || event.type === 'Numpad4' ? GambleConsts.RED : GambleConsts.BLACK,\n        );\n    }\n\n    private onGambleViewClick(): void {\n        this.rootStore.subjects.MODAL_PRESSED.next();\n    }\n\n    /**\n     *\n     * @param choice\n     */\n    private onGambleButtonClicked(choice: GambleConsts): void {\n        this.rootStore.uiStore.STATE.next(UIState.WAITING_FOR_STATE_CHANGE);\n        this.stateMachineService.send({ type: 'SELECT_CARD', card: choice });\n        this.gamble(choice);\n    }\n\n    /**\n     *\n     * @param response\n     */\n    private onMessage(response: any): void {\n        if (response.event === 'gamble') {\n            this.onGambleChanged(new GambleResponse(response));\n        }\n    }\n\n    private onRestore(): void {\n        this.stateMachineService.send({ type: 'ON_RESTORE' });\n        this.rootStore.subjects.RESTORE.executorComplete();\n    }\n\n    /**\n     *\n     * @param context\n     * @param event\n     */\n    private isLastWin(context, _event): boolean {\n        return context.gamblesLeft === 0;\n    }\n\n    /**\n     *\n     * @param context\n     * @param event\n     */\n    private isWin(_context, event): boolean {\n        return event.context.winAmount !== 0;\n    }\n\n    /**\n     *\n     * @param context\n     * @param event\n     */\n    private isFirst(context, _event): boolean {\n        // WE USE THIS TO KNOW WEATHER TO WAIT OR NOT FOR RESTORE RESPONSE\n        // IF NO GAMBLE IS MADE WE DO NOT GET RESTORE FROM SERVER\n        return context.isFirst;\n    }\n\n    /**\n     *\n     * @param context\n     * @param event\n     */\n    private isX2ButtonVisibleAndUINotBlockedInKiosk(_context, _event): boolean {\n        return (\n            this.view.gambleButton.visible &&\n            this.view.gambleButton.enabled &&\n            !Core.UI_BLOCKER.value &&\n            !this.rootStore.uiStore.SHOW_SETTINGS.value &&\n            Core.configuration.mode === 'kiosk'\n        );\n    }\n    /**\n     *\n     * @param context\n     * @param event\n     */\n    private isX2ButtonVisibleAndUINotBlocked(_context, _event): boolean {\n        return (\n            this.view.gambleButton.visible &&\n            this.view.gambleButton.enabled &&\n            !Core.UI_BLOCKER.value &&\n            !this.rootStore.uiStore.SHOW_SETTINGS.value\n        );\n    }\n    /**\n     *\n     * @param context\n     * @param event\n     */\n    private updateState(context, event: any): any {\n        context = null;\n        // biome-ignore lint/suspicious/noAssignInExpressions: <explanation>\n        return (context = event.context);\n    }\n\n    /**\n     *\n     * @param context\n     * @param event\n     */\n    private onLose(context, _event): void {\n        Core.sounds.play('gambleLostSound');\n        this.rootStore.uiStore.WIN.next({\n            amount: 0,\n            action: BangupActionConsts.SET,\n            feature: Features.GAMBLE,\n        });\n        // this.view.updateValues(context);\n        this.view.updateWinValue(context);\n    }\n\n    /**\n     *\n     * @param context\n     * @param event\n     */\n    private onWin(context, event): void {\n        Core.sounds.play('gambleWonSound');\n        // this.rootStore.uiStore.STATE.next(UIState.GAMBLE_WIN);\n        this.rootStore.uiStore.WIN.next({\n            amount: event.context.winAmount,\n            action: BangupActionConsts.SET,\n            feature: Features.GAMBLE,\n        });\n        this.view.updateValues(context);\n        this.view.gambleWinTextAnimation();\n    }\n\n    /**\n     *\n     * @param context\n     * @param event\n     */\n    private updateFirstCardInHistory(context, _event): void {\n        this.view.updateFirstCardInHistory(context.history[0]);\n    }\n\n    /**\n     *\n     * @param context\n     * @param event\n     */\n    private modeChanged(context, _event): void {\n        this.view.updateValues(context);\n    }\n\n    /**\n     *\n     * @param context\n     * @param event\n     */\n    private onLastWin(context, _event): void {\n        this.rootStore.uiStore.STATE.next(UIState.LAST_GAMBLE_WIN);\n        this.rootStore.uiStore.WIN.next({\n            amount: context.winAmount,\n            action: BangupActionConsts.SET,\n            feature: Features.GAMBLE,\n        });\n        this.collectWin();\n        this.rootStore.uiStore.CLEAR_LINES.next();\n    }\n\n    /**\n     *\n     */\n    private openGamble(isFirst): void {\n        if (this.hasMultilayeredBGSound) {\n            this.rootStore.subjects.ENABLE_MULTILAYERED_BG_SOUND_COMPONENT.next(false);\n        }\n\n        this.rootStore.subjects.GAMBLE_OPENED.next(true);\n        this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_OUTSIDE_BETS_VISIBLE.next(false);\n        this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_BTN_VISIBLE.next(false);\n        this.rootStore.subjects.BUY_BONUS_AND_DOUBLE_CHANCE_VISIBLE.next(0);\n        this.rootStore.domainStore.SPIN_MODE.next(Features.GAMBLE);\n        const context = {\n            gamblesLeft: this.rootStore.uiStore.gamblesLeft,\n            winAmount: this.rootStore.uiStore.WIN.value.amount,\n            potentialGambleWin: this.rootStore.uiStore.WIN.value.amount * 2,\n            history: this.rootStore.uiStore.HISTORY.value,\n            balance: this.rootStore.uiStore.BALANCE.value,\n            changeStateOnExit: false,\n            isFirst,\n        };\n        this.stateMachineService.send({ type: 'INITIALIZE', context });\n        this.addFeatureEvents();\n    }\n\n    private addFeatureEvents(): void {\n        const SUB = merge(this.DESTROY, this.GambleClosed);\n        // this.GambleClosed.pipe(take(1), takeUntil(this.DESTROY)).subscribe(this.finishGamble.bind(this));\n        this.rootStore.domainStore.COLLECT_RESPONSE.pipe(takeUntil(SUB)).subscribe(this.finishGamble.bind(this));\n        Core.MONEY_MODE_IN_CREDITS.pipe(takeUntil(SUB)).subscribe(this.onMoneyModeChanged.bind(this));\n        this.rootStore.subjects.RESTORE.pipe(takeUntil(SUB)).subscribe(this.onRestore.bind(this));\n    }\n\n    /**\n     *\n     */\n    private onMoneyModeChanged(): void {\n        this.stateMachineService.send({ type: 'MODE_CHANGED' });\n    }\n\n    /**\n     *\n     * @param gambleResponse\n     */\n    private onGambleChanged(gambleResponse: GambleResponse): void {\n        const context = {\n            gamblesLeft: gambleResponse.gambles,\n            winAmount: gambleResponse.win,\n            potentialGambleWin: gambleResponse.win * 2,\n            history: gambleResponse.history,\n            balance: gambleResponse.balance,\n            changeStateOnExit: true,\n            isWonGamble: true,\n        };\n\n        this.stateMachineService.send({ type: 'GAMBLE_RESPONSE', context });\n        this.rootStore.uiStore.HISTORY.next(context.history);\n        this.rootStore.uiStore.gamblesLeft = context.gamblesLeft;\n        this.view.onCardChanged(gambleResponse.output);\n    }\n\n    /**\n     *\n     * @param _context\n     * @param _event\n     */\n    private finishGamble(_context, _event): void {\n        if (this.hasMultilayeredBGSound) {\n            this.rootStore.subjects.ENABLE_MULTILAYERED_BG_SOUND_COMPONENT.next(true);\n        }\n\n        this.view.hide();\n        this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_BTN_VISIBLE.next(true);\n        this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_OUTSIDE_BETS_VISIBLE.next(true);\n        // this.rootStore.subjects.BEFORE_SPIN.next();\n        this.rootStore.subjects.FEATURE_FINISHED.next(Features.GAMBLE);\n        this.rootStore.subjects.FEATURE_COMPLETE.next(Features.GAMBLE);\n        if (this.featureConfig.buttonsToShow.length !== 0) {\n            this.showCustomButtons();\n        }\n        this.GambleClosed.next();\n    }\n\n    /**\n     *\n     * @param response\n     */\n    private updateHistory(response: BetResponse): void {\n        if (response.gambleHistory) {\n            this.rootStore.uiStore.HISTORY.next(response.gambleHistory);\n        }\n    }\n    /**\n     *\n     * @param choice\n     */\n    private gamble(choice: GambleConsts): any {\n        const isCustom = this.rootStore.customResultStore\n            ? this.rootStore.customResultStore.isCustomGamble.value\n            : false;\n        const request: GambleRequest = new GambleRequest(choice, isCustom);\n        Core.sendMessage(request);\n    }\n\n    /**\n     *\n     * @param e\n     */\n    protected onKeyReleased(e: KeyboardEvent): void {\n        if (e === null) {\n            return;\n        }\n        this.stateMachineService.send({ type: e.code });\n\n        if ((e.code !== undefined && e.code === 'ArrowDown') || (e.keyCode !== undefined && e.keyCode === 40)) {\n            if (\n                this.view.collectButton.visible &&\n                this.view.collectButton.enabled &&\n                (this.rootStore.uiStore.STATE.value === UIState.COLLECT_BEFORE_IDLE ||\n                    this.rootStore.uiStore.STATE.value === UIState.WAITING_FOR_COLLECT)\n            ) {\n                this.collectWin();\n            }\n        }\n    }\n}\n","import { IRequest } from '@egt/core';\nimport GambleConsts from '../enums/GambleConsts';\n\nexport default class GambleRequest implements IRequest {\n    constructor(\n        private gambleChoice: GambleConsts,\n        private custom = false,\n    ) {}\n\n    public serialize(): any {\n        const event = {\n            event: 'gamble',\n            context: {\n                gambleChoice: this.gambleChoice,\n            },\n        };\n        if (this.custom) {\n            const cs = 'custom';\n            event.context[cs] = true;\n        }\n        return event;\n    }\n}\n","import { RestoreResponse } from '@egt/slot';\n\nexport default class GambleResponse {\n    protected _restore: boolean;\n    protected _restoreResponse: RestoreResponse;\n    protected _restoreResponses: any;\n    protected _restorePoint: string;\n    protected _restorePoints: string[];\n\n    private _balance: number;\n    private _win: number;\n    private _denomination: number;\n    private _currency: string;\n    private _state: string;\n    private _gambleWin: boolean;\n    private _output: number;\n    private _history: number[] = [];\n    private _gambles: number;\n\n    constructor(response: any) {\n        if (response.game.restore) {\n            this._restorePoints = response.game.result.restorePoints;\n            this._restorePoint = response.game.result.restorePoints[0];\n            this._restoreResponse = new RestoreResponse(response.game.restore[response.game.result.restorePoints[0]]);\n            this._restoreResponses = response.game.restore;\n            this._restore = true;\n        }\n\n        if (response.balance) {\n            this._balance = response.balance.balance;\n            this._currency = response.balance.currency;\n        }\n        this._denomination = response.game.state.bet.denomination;\n        this._history = response.game.state.gambleHistory !== undefined ? response.game.state.gambleHistory : [];\n        this._output = response.game.result.outcome;\n        this._win =\n            response.game?.state?.limitHit === true\n                ? response.game.state.totalWinAmount\n                : response.game.result.totalWin * this._denomination;\n        this._gambles = response.game.state.gambles;\n        this._gambleWin = response.state === 'win' ? true : false;\n        this._state = response.state;\n    }\n\n    get balance(): number {\n        return this._balance;\n    }\n\n    get win(): number {\n        return this._win;\n    }\n\n    get output(): number {\n        return this._output;\n    }\n\n    get history(): number[] {\n        return this._history.reverse();\n    }\n\n    get denomination(): number {\n        return this._denomination;\n    }\n\n    get currency(): string {\n        return this._currency;\n    }\n\n    get state(): string {\n        return this._state;\n    }\n\n    get hasGambleWin(): boolean {\n        return this._gambleWin;\n    }\n\n    get gambles(): number {\n        return this._gambles;\n    }\n\n    get restore(): boolean {\n        return this._restore;\n    }\n\n    get restoreResponse(): RestoreResponse {\n        return this._restoreResponse;\n    }\n\n    set restoreResponse(value: RestoreResponse) {\n        this._restoreResponse = value;\n    }\n\n    get restoreResponses(): any {\n        return this._restoreResponses;\n    }\n\n    get restorePoint(): string {\n        return this._restorePoint;\n    }\n\n    get restorePoints(): string[] {\n        return this._restorePoints;\n    }\n}\n","const enum GambleConsts {\n    RED = 'red',\n    BLACK = 'black',\n    NONE = '',\n}\nexport default GambleConsts;\n","const enum GambleState {\n    NONE = 'none',\n    GAMBLE_IDLE = 'idle',\n}\nexport default GambleState;\n","import { injectable } from 'tsyringe';\nimport GambleState from '../enums/GambleState';\nimport { BaseStore } from '@egt/core';\n\n@injectable()\nexport default class GambleStoreDefault extends BaseStore {\n    public state: GambleState = GambleState.NONE;\n    public gamblesLeft: number = 0;\n    public winAmount: number = 0;\n    public potentialGambleWin: number = 0;\n    public changeStateOnExit = false;\n    public history: number[] = [];\n    public balance: number = 0;\n    public isFirst: boolean = true;\n    constructor() {\n        // window.console.log('GambleStore');\n        super();\n        this.enableLogging();\n    }\n}\n","import Core, { IVideoPlayer, Timers } from '@egt/core';\nimport { Features, InitialSettings, RootStore } from '@egt/slot';\nimport { BluredText, Button, ButtonShapes, MoneyText, MoneyTextConfig, ViewContainer } from '@egt/ui-lib';\nimport { gsap } from 'gsap';\nimport { Container, Graphics, Text as PIXIText, Sprite, Texture } from 'pixi.js';\nimport { filter, takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\n\nimport { IGambleFeatureConfigurationDefault } from '../configuration/IGambleFeatureConfigurationDefault';\nimport GambleState from '../enums/GambleState';\nimport GambleStoreDefault from '../stores/GambleStoreDefault';\n\n@injectable()\nexport default class GambleViewDefault extends ViewContainer {\n    public switchDelay: number = 1;\n    public gambleButton: Button;\n    public gambleRedButton: Button;\n    public collectButton: Button;\n    public gambleBlackButton: Button;\n    public gambleAmountValue: ViewContainer;\n    public balanceText: BluredText;\n\n    protected animationAsset: Sprite;\n    protected elementsAdded: boolean = false;\n    protected animationTween: any;\n\n    protected historyCards: Sprite[] = [];\n    protected gambleBackgroundPortrait: Sprite;\n    protected gambleBackground: {\n        landscape: Sprite;\n        portrait: Sprite;\n    };\n    protected gambleAmountMoney: MoneyText;\n    protected gambleToWinMoney: MoneyText;\n    protected gambleAmountText: PIXIText;\n    protected gambleToWinText: PIXIText;\n\n    protected cardBlack: Sprite;\n    protected cardRed: Sprite;\n    protected cardFace0: Sprite;\n    protected cardFace1: Sprite;\n    protected cardFace2: Sprite;\n    protected cardFace3: Sprite;\n\n    protected balanceMoney: MoneyText;\n    protected winMoney: MoneyText;\n\n    protected cardSwitchInterval: gsap.core.Tween;\n    protected cardSwitchIntervalValue: number = 160;\n\n    private tween: gsap.core.Tween;\n    private gambleContainer: Sprite;\n    private gambleLeftTextContainer: Container;\n    private gambleToWinValue: ViewContainer;\n    private chooseText: PIXIText;\n    private winText: PIXIText;\n    private gamblesLeftText: PIXIText;\n    private gamblesLeftValue: BluredText;\n    private titleText: PIXIText;\n    private historyText: PIXIText;\n    private winTextImage: Sprite;\n    private selectTextOrnaments: { left: Sprite; right: Sprite };\n\n    private gambleOverlay: Graphics;\n    private videoPlayer: IVideoPlayer;\n\n    // private titles: Text[] = [];\n    // private values: MoneyText[] = [];\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('GambleStore') protected store: GambleStoreDefault,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('GambleFeatureConfiguration') protected featureConfig: IGambleFeatureConfigurationDefault,\n    ) {\n        super();\n\n        this.name = 'GambleView';\n        this.gambleContainer = new Sprite();\n        this.gambleContainer.name = 'GambleContainer';\n        this.gambleLeftTextContainer = new Container();\n        this.gambleLeftTextContainer.name = 'gambleLeftTextContainer';\n        this.gambleButton = new Button(\n            [\n                Core.assets.getAsset('svgGambleX2').texture,\n                Core.assets.getAsset('svgGambleX2').texture,\n                Core.assets.getAsset('svgGambleX2').texture,\n                Core.assets.getAsset('svgGambleX2Inactive').texture,\n            ],\n            undefined,\n            ButtonShapes.Circle,\n        );\n        this.gambleButton.name = 'gambleButton';\n        this.gambleButton.visible = false;\n        this.addChild(this.gambleButton);\n\n        this.animationAsset = new Sprite();\n        if (!this.featureConfig.useVideoForBtnAnimation.value) {\n            this.animationAsset.texture = Core.assets.getAsset('svgGambleFrameX2').texture;\n        }\n        this.animationAsset.anchor.set(0.5);\n        this.animationAsset.x = this.gambleButton.width / 2;\n        this.animationAsset.y = this.gambleButton.height / 2;\n        this.gambleButton.addChild(this.animationAsset);\n\n        this.collectButton = new Button(\n            Core.assets.getAssets(this.featureConfig.collectButtonPosition.textures),\n            undefined,\n            ButtonShapes.Circle,\n        );\n        this.collectButton.name = 'collectButton';\n        this.collectButton.pivot.set(this.collectButton.width / 2, this.collectButton.height / 2);\n\n        // this.rootStore.uiStore.STATE.pipe(takeUntil(this.DESTROY)).subscribe(this.onStateChanged.bind(this));\n    }\n\n    public playAnimation(): void {\n        if (this.featureConfig.useVideoForBtnAnimation.value) {\n            if (!this.videoPlayer) {\n                const videoConfig = {\n                    id: 'gambleBnt',\n                    fps: 30,\n                    loopIndex: 0,\n                    length: 24,\n                    loop: true,\n                };\n                const animationAsset = Core.assets.getAsset(videoConfig.id);\n                const hasSpritesheet = Array.isArray(animationAsset)\n                    ? animationAsset.some((asset) => Boolean(asset?.spritesheet))\n                    : Boolean(animationAsset?.spritesheet);\n\n                // The gamble view can be resolved before feature assets finish loading.\n                if (!hasSpritesheet) {\n                    return;\n                }\n\n                this.videoPlayer = Core.createVideoPlayer();\n                this.videoPlayer.config = videoConfig;\n                const videoTexture = Core.assets.getAnimationAssets(videoConfig.id, '');\n                this.videoPlayer.frames = Object.keys(videoTexture).map((personNamedIndex) => {\n                    return videoTexture[personNamedIndex];\n                });\n                this.videoPlayer.config = videoConfig;\n                this.videoPlayer.addInstance(this.animationAsset);\n                this.videoPlayer.play();\n            }\n        } else {\n            Object.keys(this.featureConfig.animationAssetInitialValues).forEach((key) => {\n                if (this.animationAsset[key]) {\n                    this.animationAsset[key] = this.featureConfig.animationAssetInitialValues[key];\n                }\n            });\n            if (this.featureConfig.gambleAnimationConfiguration.length === 2) {\n                this.animationTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/features/slot/gamble/src/egt/modes/default/views/GambleViewDefault.ts:154:39\",null]), gsap.fromTo(\n                    this.animationAsset,\n                    this.featureConfig.gambleAnimationConfiguration[0],\n                    this.featureConfig.gambleAnimationConfiguration[1],\n                ));\n            } else {\n                this.animationTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/features/slot/gamble/src/egt/modes/default/views/GambleViewDefault.ts:160:39\",null]), gsap.to(this.animationAsset, this.featureConfig.gambleAnimationConfiguration[0]));\n            }\n        }\n    }\n\n    public stopAnimation(): void {\n        if (this.animationTween) {\n            this.animationTween.totalProgress(0);\n            this.animationTween.kill();\n            this.animationTween = null;\n        }\n        if (this.tween) {\n            this.tween.totalProgress(1);\n            this.tween.kill();\n            this.tween = null!;\n        }\n    }\n\n    public destroy(): void {\n        this.stopAnimation();\n        super.destroy({ children: true, texture: true });\n\n        if (this.gambleOverlay) {\n            this.gambleOverlay.destroy();\n            // @ts-ignore\n            this.gambleOverlay = null;\n        }\n\n        this.selectTextOrnaments?.left?.destroy();\n        this.selectTextOrnaments?.right?.destroy();\n        // @ts-ignore\n        this.selectTextOrnaments = null;\n    }\n\n    public initialRenderrer(): void {\n        this.interactive = true;\n        // this.rootStore.uiStore.WIN.pipe(takeUntil(this.DESTROY)).subscribe(this.changeGambleAmounts.bind(this));\n        // this.rootStore.uiStore.HISTORY.pipe(takeUntil(this.DESTROY)).subscribe(this.updateHistory.bind(this));\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n        Core.LEFT_HAND_MODE.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n        if (Core.isReplayer) {\n            Core.REPLAYER_ACTION.pipe(\n                filter((p) => p.module === Features.GAMBLE),\n                takeUntil(this.DESTROY),\n            ).subscribe((params) => {\n                if (params.data === 'clearHistory') {\n                    for (let i = 1; i < this.historyCards.length; i++) {\n                        this.historyCards[i].visible = false;\n                    }\n                }\n            });\n        }\n\n        this.setOrientation();\n    }\n\n    public onCardChanged(cardValue: number): void {\n        if (this.store.state === GambleState.NONE) {\n            return;\n        }\n        this.stopCardAnimation();\n        switch (cardValue) {\n            case 0: // Black\n            case 1:\n            case 2:\n            case 3:\n                this['cardFace' + cardValue].visible = true;\n                this['cardFace' + cardValue].width = this.featureConfig.gambleCardSize.width;\n                this['cardFace' + cardValue].height = this.featureConfig.gambleCardSize.height;\n                this.hideCardBacks();\n                // this.updateHistory();\n                break;\n\n            default:\n                this.playCardAnimation();\n        }\n    }\n\n    public hideGambleButtons(): void {\n        this.gambleBlackButton.alpha = 0.7;\n        this.gambleBlackButton.enabled = false;\n        this.gambleRedButton.alpha = 0.7;\n        this.gambleRedButton.enabled = false;\n    }\n\n    public showGambleButtons(): void {\n        this.gambleBlackButton.alpha = 1;\n        this.gambleBlackButton.enabled = true;\n        this.gambleRedButton.alpha = 1;\n        this.gambleRedButton.enabled = true;\n    }\n\n    public show(context): void {\n        this.gambleContainer.visible = true;\n        this.addElements();\n\n        this.updateCollectBtnTextures();\n        this.showGambleButtons();\n        this.updateValues(context);\n        this.setOrientation();\n        this.resizeText();\n        this.playCardAnimation();\n    }\n\n    public setBtnAnimVisible(visible: boolean): void {\n        this.animationAsset.visible = visible;\n        if (this.featureConfig.useVideoForBtnAnimation.value && this.videoPlayer) {\n            if (visible) {\n                this.videoPlayer.play();\n            } else {\n                this.videoPlayer.stop();\n            }\n        }\n    }\n    public isBtnVisible(): boolean {\n        return this.animationAsset.visible;\n    }\n\n    private updateCollectBtnTextures(): void {\n        if (this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value) {\n            this.collectButton.setTextures(\n                Core.assets.getAssets(this.featureConfig.collectButtonPosition.texturesSpecial),\n            );\n        } else {\n            this.collectButton.setTextures(Core.assets.getAssets(this.featureConfig.collectButtonPosition.textures));\n        }\n    }\n\n    public hide(): void {\n        this.gambleContainer.visible = false;\n        this.stopCardAnimation();\n        this.stopGambleWinTextAnimation();\n    }\n\n    public updateValues(context): void {\n        // no change of potential win fields if last choice\n        if (context.gamblesLeft > 0) {\n            this.gambleAmountMoney.money = context.winAmount;\n            this.gambleToWinMoney.money = context.potentialGambleWin;\n        }\n        this.gambleAmountMoney.config.showCredits = Core.MONEY_MODE_IN_CREDITS.value;\n        this.gambleToWinMoney.config.showCredits = Core.MONEY_MODE_IN_CREDITS.value;\n        this.balanceMoney.config.showCredits = Core.MONEY_MODE_IN_CREDITS.value;\n        this.winMoney.config.showCredits = Core.MONEY_MODE_IN_CREDITS.value;\n        // force redraw of moneytext\n        this.gambleAmountMoney.config = this.gambleAmountMoney.config;\n        this.gambleToWinMoney.config = this.gambleToWinMoney.config;\n        this.balanceMoney.config = this.balanceMoney.config;\n        this.winMoney.config = this.winMoney.config;\n\n        this.balanceMoney.money = context.balance;\n        this.winMoney.money = context.winAmount;\n        this.gamblesLeftValue.text = context.gamblesLeft.toString();\n        this.balanceText.text =\n            Core.translator\n                .translate('GAMBLE.BALANCE')\n                .toUpperCase()\n                .replace(/: /g, this.featureConfig.balanceText.separator) + this.balanceMoney.moneyText;\n        this.winText.text =\n            Core.translator\n                .translate('GAMBLE.WIN')\n                .toUpperCase()\n                .replace(/: /g, this.featureConfig.balanceText.separator) + this.winMoney.moneyText;\n        this.updateHistoryCards(context.history);\n    }\n\n    public updateWinValue(context): void {\n        this.winMoney.money = context.winAmount;\n        this.winText.text =\n            Core.translator\n                .translate('GAMBLE.WIN')\n                .toUpperCase()\n                .replace(/: /g, this.featureConfig.balanceText.separator) + this.winMoney.moneyText;\n    }\n\n    public updateFirstCardInHistory(card: number): void {\n        if (this.elementsAdded) {\n            this.historyCards[0].texture = this.getCardTexture(card);\n            this.historyCards[0].width = this.featureConfig.historyCardSize.width;\n            this.historyCards[0].height = this.featureConfig.historyCardSize.height;\n        }\n    }\n\n    public updateHistoryCards(history: []): void {\n        this.historyCards[0].texture = this.cardRed.texture;\n        this.historyCards[0].width = this.featureConfig.historyCardSize.width;\n        this.historyCards[0].height = this.featureConfig.historyCardSize.height;\n        history.forEach((historyNumber, historyNumberIndex) => {\n            if (historyNumberIndex < this.historyCards.length - 1) {\n                this.historyCards[historyNumberIndex + 1].visible = true;\n                this.historyCards[historyNumberIndex + 1].texture = this.getCardTexture(historyNumber);\n                this.historyCards[historyNumberIndex + 1].width = this.featureConfig.historyCardSize.width;\n                this.historyCards[historyNumberIndex + 1].height = this.featureConfig.historyCardSize.height;\n            }\n        });\n    }\n\n    public gambleWinTextAnimation(): void {\n        this.stopGambleWinTextAnimation();\n\n        const halfGambleWaitTime = this.featureConfig.gambleWaitTime / 2 / 1000;\n        this.tween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/features/slot/gamble/src/egt/modes/default/views/GambleViewDefault.ts:361:22\",null]), gsap.to(this.winTextImage, { alpha: 1, duration: halfGambleWaitTime, repeat: 1, yoyo: true }));\n    }\n\n    // protected onStateChanged(): void {\n    //     switch (this.rootStore.uiStore.STATE.value) {\n    //         case UIState.COLLECT_BEFORE_IDLE:\n    //             this.collectButton.visible = true;\n    //             this.collectButton.enabled = true;\n    //             break;\n    //         case UIState.IDLE:\n    //         case UIState.BONUS_SUMMARY:\n    //         case UIState.WAITING_FOR_RESPONSE:\n    //         case UIState.WAITING_FOR_RESPONSE_IN_AUTOPLAY:\n    //         case UIState.WIN:\n    //         case UIState.WAITING_FOR_COLLECT:\n    //         case UIState.WAITING_FOR_COLLECT_IN_AUTOPLAY:\n    //         case UIState.WAITING_FOR_STATE_CHANGE:\n    //         case UIState.DISABLED:\n    //         case UIState.SLIDING_BETS:\n    //             this.collectButton.enabled = false;\n    //             break;\n    //     }\n    // }\n\n    protected addElements(): void {\n        if (this.elementsAdded) {\n            return;\n        }\n        this.gambleOverlay = new Graphics();\n        this.gambleOverlay.beginFill(this.featureConfig.gambleOverlay.fill);\n        this.gambleOverlay.drawRect(0, 0, Core.display.stage.width, Core.display.stage.height);\n        this.gambleOverlay.endFill();\n        this.gambleOverlay.alpha = this.featureConfig.gambleOverlay.alpha;\n        this.gambleOverlay.visible = this.featureConfig.gambleOverlay.visible;\n        this.gambleContainer.addChild(this.gambleOverlay);\n\n        const winTextAsset = Core.assets.getAsset('gambleWinTextTranslate');\n        if (winTextAsset) {\n            this.winTextImage = new Sprite(winTextAsset.texture);\n        } else {\n            this.winTextImage = new Sprite();\n        }\n        this.winTextImage.alpha = 0;\n        this.winTextImage.anchor.set(0.5, 0.5);\n        this.winTextImage.name = 'winTextImage';\n\n        this.gambleBackground = {\n            landscape: new Sprite(Core.assets.getTextureFromSpriteSheet('gamble', 'backgroundLandscape.png')),\n            portrait: new Sprite(Core.assets.getTextureFromSpriteSheet('gamble', 'backgroundPortrait.png')),\n        };\n        this.gambleBackground.landscape.name = 'backgroundLandscape';\n        this.gambleBackground.landscape.interactive = true;\n\n        this.gambleBackground.portrait.interactive = true;\n        this.gambleAmountValue = this.createMoneyContainer(\n            // * left info bar\n            'gambleAmount',\n            Core.translator.translate('GAMBLE.AMOUNT'),\n            0,\n            this.featureConfig.moneyContainersSize.width,\n            this.featureConfig.moneyContainersSize.height,\n        );\n        this.gambleBackground.portrait.name = 'backgroundPortrait';\n        this.gambleToWinValue = this.createMoneyContainer(\n            // * right info bar\n            'gambleToWin',\n            Core.translator.translate('GAMBLE.TO_WIN'),\n            0,\n            this.featureConfig.moneyContainersSize.width,\n            this.featureConfig.moneyContainersSize.height,\n        );\n\n        this.historyText = new PIXIText(\n            Core.translator.translate(this.featureConfig.historyTextKey).toUpperCase(),\n            this.featureConfig.textStyles.historyText,\n        );\n        this.historyText.name = 'historyText';\n        this.historyText.anchor.set(0.5, 0);\n\n        this.gamblesLeftText = new PIXIText(\n            Core.translator.translate('GAMBLE.ATTEMPTS'),\n            this.featureConfig.textStyles.gamblesLeftText,\n        );\n        this.gamblesLeftText.name = 'gamblesLeftText';\n        this.gamblesLeftValue = new BluredText(\n            '',\n            this.featureConfig.textStyles.gamblesLeftValueText,\n            undefined,\n            Core.isReplayer,\n            true,\n        );\n        this.gamblesLeftValue.name = 'gamblesLeftValue';\n        this.titleText = new PIXIText(\n            Core.translator.translate('GAMBLE.GAMBLE'),\n            this.featureConfig.textStyles.titleText,\n        );\n        this.titleText.name = 'titleText';\n        this.titleText.anchor.set(0.5, 0);\n\n        this.chooseText = new PIXIText(\n            Core.translator.translate('GAMBLE.CHOOSE').toUpperCase(),\n            this.featureConfig.textStyles.gambleChooseText,\n        );\n        this.chooseText.name = 'chooseText';\n        this.chooseText.anchor.set(0.5, 0);\n\n        this.balanceText = new BluredText(\n            Core.translator\n                .translate('GAMBLE.BALANCE')\n                .toUpperCase()\n                .replace(/: /g, this.featureConfig.balanceText.separator) + this.rootStore.uiStore.BALANCE.value,\n            this.featureConfig.textStyles.balanceText,\n            undefined,\n            Core.isReplayer,\n        );\n        this.balanceText.name = 'balanceText';\n        this.balanceText.visible = this.featureConfig.balanceText.visible;\n\n        this.winText = new PIXIText(\n            Core.translator\n                .translate('GAMBLE.WIN')\n                .toUpperCase()\n                .replace(/: /g, this.featureConfig.balanceText.separator) + this.rootStore.uiStore.WIN.value.amount,\n            this.featureConfig.textStyles.winText,\n        );\n        this.winText.name = 'winText';\n        this.winText.visible = this.featureConfig.winText.visible;\n        this.winText.anchor.set(1, 0);\n\n        this.cardBlack = new Sprite(Core.assets.getTextureFromSpriteSheet('gamble', 'cardBlack.png'));\n        this.cardBlack.name = 'cardBlack';\n        this.cardFace0 = new Sprite(Core.assets.getTextureFromSpriteSheet('gamble', 'ace2.png'));\n        this.cardFace1 = new Sprite(Core.assets.getTextureFromSpriteSheet('gamble', 'ace1.png'));\n        this.cardFace2 = new Sprite(Core.assets.getTextureFromSpriteSheet('gamble', 'ace0.png'));\n        this.cardFace3 = new Sprite(Core.assets.getTextureFromSpriteSheet('gamble', 'ace3.png'));\n        this.cardRed = new Sprite(Core.assets.getTextureFromSpriteSheet('gamble', 'cardRed.png'));\n        this.cardRed.name = 'cardRed';\n\n        [this.cardBlack, this.cardRed, this.cardFace0, this.cardFace1, this.cardFace2, this.cardFace3].forEach(\n            (cardSprite) => cardSprite.anchor.set(0.5, 0.5),\n        );\n\n        this.gambleBlackButton = new Button(\n            [\n                Core.assets.getTextureFromSpriteSheet('gamble', 'black.png'),\n                Core.assets.getTextureFromSpriteSheet('gamble', 'blackOn.png'),\n                Core.assets.getTextureFromSpriteSheet('gamble', 'black.png'),\n                Core.assets.getTextureFromSpriteSheet('gamble', 'black.png'),\n            ],\n            undefined,\n            ButtonShapes.Circle,\n        );\n        this.gambleBlackButton.name = 'gambleBlackButton';\n        this.gambleBlackButton.interactive = true;\n        this.gambleBlackButton.buttonMode = true;\n\n        this.gambleRedButton = new Button(\n            [\n                Core.assets.getTextureFromSpriteSheet('gamble', 'red.png'),\n                Core.assets.getTextureFromSpriteSheet('gamble', 'redOn.png'),\n                Core.assets.getTextureFromSpriteSheet('gamble', 'red.png'),\n                Core.assets.getTextureFromSpriteSheet('gamble', 'red.png'),\n            ],\n            undefined,\n            ButtonShapes.Circle,\n        );\n        this.gambleRedButton.name = 'gambleRedButton';\n        this.gambleRedButton.interactive = true;\n        this.gambleRedButton.buttonMode = true;\n\n        const redTxt: PIXIText = new PIXIText(\n            Core.translator.translate('GAMBLE.RED').toUpperCase(),\n            this.featureConfig.textStyles.redText,\n        );\n        redTxt.name = 'redTxt';\n        const blackTxt: PIXIText = new PIXIText(\n            Core.translator.translate('GAMBLE.BLACK').toUpperCase(),\n            this.featureConfig.textStyles.blackText,\n        );\n        blackTxt.name = 'blackTxt';\n        const gambleMoneyConfig: MoneyTextConfig = new MoneyTextConfig();\n        gambleMoneyConfig.units = this.rootStore.uiStore.units;\n\n        gambleMoneyConfig.debug = false;\n        gambleMoneyConfig.shouldFitInBounds = true;\n        gambleMoneyConfig.showCurrency = true;\n        gambleMoneyConfig.showCredits = false;\n        gambleMoneyConfig.currency = this.rootStore.uiStore.currency;\n        gambleMoneyConfig.denomination = Core.SELECTED_DENOMINATION.value;\n        gambleMoneyConfig.moneyFontSize = this.featureConfig.moneyConfig.gambleMoney.moneyFontSize;\n        gambleMoneyConfig.centsFontSize = this.featureConfig.moneyConfig.gambleMoney.centsFontSize;\n        gambleMoneyConfig.currencyFontSize = this.featureConfig.moneyConfig.gambleMoney.currencyFontSize;\n\n        this.balanceMoney = new MoneyText(gambleMoneyConfig, 0);\n        this.winMoney = new MoneyText(gambleMoneyConfig, 0);\n\n        this.balanceText.text =\n            Core.translator\n                .translate('GAMBLE.BALANCE')\n                .toUpperCase()\n                .replace(/: /g, this.featureConfig.balanceText.separator) + +this.balanceMoney.moneyText;\n\n        this.winText.text =\n            Core.translator.translate('GAMBLE.WIN').toUpperCase().replace(/: /g, this.featureConfig.winText.separator) +\n            +this.winMoney.moneyText;\n\n        let redScale = 1;\n        let blackScale = 1;\n\n        if (redTxt.width > this.gambleRedButton.width - this.featureConfig.buttonTextMargin) {\n            redScale = (this.gambleRedButton.width - this.featureConfig.buttonTextMargin) / redTxt.width;\n        }\n        if (blackTxt.width > this.gambleBlackButton.width - this.featureConfig.buttonTextMargin) {\n            blackScale = (this.gambleBlackButton.width - this.featureConfig.buttonTextMargin) / blackTxt.width;\n        }\n        const scale = redScale > blackScale ? blackScale : redScale;\n\n        redTxt.scale.set(scale);\n        blackTxt.scale.set(scale);\n\n        redTxt.x = 15 + Math.floor((this.gambleRedButton.width - redTxt.width - 30) / 2);\n        redTxt.y = Math.ceil((this.gambleRedButton.height - redTxt.height) / 2);\n        blackTxt.x = 15 + Math.floor((this.gambleRedButton.width - blackTxt.width - 30) / 2);\n        blackTxt.y = Math.ceil((this.gambleRedButton.height - blackTxt.height) / 2);\n\n        this.gambleRedButton.addChild(redTxt);\n        this.gambleBlackButton.addChild(blackTxt);\n        this.gambleContainer.addChild(this.gambleBackground.landscape);\n\n        this.gambleContainer.addChild(this.gambleBackground.portrait);\n        this.gambleContainer.addChild(this.historyText);\n        this.gambleContainer.addChild(this.chooseText);\n\n        this.gambleContainer.addChild(this.balanceText);\n        this.gambleContainer.addChild(this.winText);\n\n        this.gambleContainer.addChild(this.titleText);\n        this.gambleLeftTextContainer.addChild(this.gamblesLeftValue);\n        this.gambleLeftTextContainer.addChild(this.gamblesLeftText);\n\n        this.gambleContainer.addChild(this.cardFace0);\n        this.gambleContainer.addChild(this.cardFace1);\n        this.gambleContainer.addChild(this.cardFace2);\n        this.gambleContainer.addChild(this.cardFace3);\n        this.gambleContainer.addChild(this.cardRed);\n        this.gambleContainer.addChild(this.cardBlack);\n        this.gambleContainer.addChild(this.gambleAmountValue);\n        this.gambleContainer.addChild(this.gambleToWinValue);\n        this.gambleContainer.addChild(this.gambleBlackButton);\n        this.gambleContainer.addChild(this.gambleRedButton);\n        this.gambleContainer.addChild(this.winTextImage);\n\n        if (this.featureConfig.selectTextOrnamentAsset.length) {\n            this.selectTextOrnaments = {\n                left: new Sprite(\n                    Core.assets.getTextureFromSpriteSheet(\n                        this.featureConfig.selectTextOrnamentAsset[0],\n                        this.featureConfig.selectTextOrnamentAsset[1],\n                    ),\n                ),\n                right: new Sprite(\n                    Core.assets.getTextureFromSpriteSheet(\n                        this.featureConfig.selectTextOrnamentAsset[0],\n                        this.featureConfig.selectTextOrnamentAsset[1],\n                    ),\n                ),\n            };\n\n            this.selectTextOrnaments.left.name = 'leftOrnament';\n            this.selectTextOrnaments.right.name = 'rightOrnament';\n\n            this.selectTextOrnaments.left.scale.set(this.featureConfig.selectTextOrnament.scale);\n            this.selectTextOrnaments.right.scale.set(\n                this.featureConfig.selectTextOrnament.scale * -1,\n                this.featureConfig.selectTextOrnament.scale,\n            );\n\n            this.selectTextOrnaments.left.anchor.set(1, 0.5);\n            this.selectTextOrnaments.right.anchor.set(1, 0.5);\n\n            this.gambleContainer.addChild(this.selectTextOrnaments.left);\n            this.gambleContainer.addChild(this.selectTextOrnaments.right);\n        }\n\n        for (let i = 0; i < this.featureConfig.historyCardCounts; i++) {\n            const historyCard: Sprite = new Sprite(Core.assets.getTextureFromSpriteSheet('gamble', 'cardRed.png'));\n            historyCard.name = 'historyCard' + i;\n            if (i > 0) {\n                historyCard.visible = false;\n            }\n\n            historyCard.width = this.featureConfig.historyCardSize.width;\n            historyCard.height = this.featureConfig.historyCardSize.height;\n            this.historyCards.push(historyCard);\n            this.gambleContainer.addChild(historyCard);\n        }\n\n        this.setGambleButtonsTextures();\n        this.elementsAdded = true;\n        this.addChild(this.gambleContainer);\n        this.gambleLeftTextContainer.pivot.x = this.gambleLeftTextContainer.width / 2;\n        this.gambleLeftTextContainer.pivot.y = this.gambleLeftTextContainer.height / 2;\n        this.gambleLeftTextContainer.x = this.featureConfig.gambleAttemptsLeft.x;\n        this.gambleLeftTextContainer.y = this.featureConfig.gambleAttemptsLeft.y;\n        this.gambleContainer.addChild(this.gambleLeftTextContainer);\n\n        this.addChild(this.collectButton);\n        this.setOrientation();\n    }\n    protected resizeText(): void {\n        this.gambleLeftTextContainer.scale.set(1);\n        const bound: number = Core.ORIENTATION.value.isPortrait ? 500 : 800;\n\n        if (this.gambleLeftTextContainer.width > bound) {\n            const scale = bound / this.gambleLeftTextContainer.width;\n            this.gambleLeftTextContainer.scale.set(scale);\n        }\n    }\n\n    protected setOrientation(): void {\n        if (this.store.state !== GambleState.NONE) {\n            // if(this.gambleAmountMoney) {\n            this.gambleAmountMoney.textBounds = {\n                width: this.featureConfig.moneyBounds.width,\n                height: this.featureConfig.moneyBounds.height,\n            };\n            this.gambleToWinMoney.textBounds = {\n                width: this.featureConfig.moneyBounds.width,\n                height: this.featureConfig.moneyBounds.height,\n            };\n\n            this.updateBalanceAndWinText();\n\n            this.gambleAmountValue.y = this.featureConfig.gambleAmountValue.y;\n            this.gambleAmountValue.x = this.featureConfig.gambleAmountValue.x;\n            this.gambleToWinValue.x = this.featureConfig.gambleToWinValue.x;\n            this.gambleToWinValue.y = this.featureConfig.gambleToWinValue.y;\n\n            this.titleText.x = this.featureConfig.titleText.x;\n            this.titleText.y = this.featureConfig.titleText.y;\n            this.titleText.style = this.featureConfig.textStyles.titleText;\n\n            this.balanceText.x = this.featureConfig.balanceText.x;\n            this.balanceText.y = this.featureConfig.balanceText.y;\n            this.balanceText.visible = this.featureConfig.balanceText.visible;\n\n            this.chooseText.scale.set(1);\n            this.chooseText.style = this.featureConfig.textStyles.gambleChooseText;\n            this.chooseText.x = this.featureConfig.chooseText.x;\n            this.chooseText.y = this.featureConfig.chooseText.y;\n\n            if (this.chooseText.width > this.featureConfig.chooseText.maxWidth) {\n                this.chooseText.scale.set(this.featureConfig.chooseText.maxWidth / this.chooseText.width);\n            }\n\n            this.winText.x = this.featureConfig.winText.x;\n            this.winText.y = this.featureConfig.winText.y;\n            this.winText.visible = this.featureConfig.winText.visible;\n\n            this.historyText.x = this.featureConfig.historyText.x;\n            this.historyText.y = this.featureConfig.historyText.y;\n\n            this.gambleBackground[this.featureConfig.backgroundVisibility.invisible].visible = false;\n            this.gambleBackground[this.featureConfig.backgroundVisibility.visible].visible = true;\n\n            this.gambleBackground[this.featureConfig.backgroundVisibility.visible].x =\n                this.featureConfig.backgroundPosition.x;\n            this.gambleBackground[this.featureConfig.backgroundVisibility.visible].y =\n                this.featureConfig.backgroundPosition.y;\n\n            this.gambleBackground[this.featureConfig.backgroundVisibility.visible].width =\n                this.featureConfig.backgroundSize.width;\n            this.gambleBackground[this.featureConfig.backgroundVisibility.visible].height =\n                this.featureConfig.backgroundSize.height;\n\n            this.gambleRedButton.x = this.featureConfig.redButton.x;\n            this.gambleRedButton.y = this.featureConfig.redButton.y;\n            this.gambleRedButton.scale.set(this.featureConfig.redButtonScale.x, this.featureConfig.redButtonScale.y);\n\n            this.gambleBlackButton.x = this.featureConfig.blackButton.x;\n            this.gambleBlackButton.y = this.featureConfig.blackButton.y;\n            this.gambleBlackButton.scale.set(\n                this.featureConfig.blackButtonScale.x,\n                this.featureConfig.blackButtonScale.y,\n            );\n\n            this.gambleLeftTextContainer.x = this.featureConfig.gambleAttemptsLeft.x;\n            this.gambleLeftTextContainer.y = this.featureConfig.gambleAttemptsLeft.y;\n\n            this.gamblesLeftText.style = this.featureConfig.textStyles.gamblesLeftText;\n            this.gamblesLeftValue.style = this.featureConfig.textStyles.gamblesLeftValueText;\n\n            this.gamblesLeftValue.x = this.gamblesLeftText.width + this.featureConfig.gamblesLeftTextSpacing;\n\n            this.gambleLeftTextContainer.scale.set(1);\n            this.gambleLeftTextContainer.pivot.x = (this.gamblesLeftValue.x + this.gamblesLeftValue.width) / 2;\n            this.gambleLeftTextContainer.pivot.y = this.gambleLeftTextContainer.height / 2;\n\n            [this.cardBlack, this.cardRed, this.cardFace0, this.cardFace1, this.cardFace2, this.cardFace3].forEach(\n                (card: Sprite) => {\n                    card.x = this.featureConfig.animatedCards.x;\n                    card.y = this.featureConfig.animatedCards.y;\n                    card.scale.set(this.featureConfig.animatedCards.scale);\n                    card.width = this.featureConfig.gambleCardSize.width;\n                    card.height = this.featureConfig.gambleCardSize.height;\n                },\n            );\n\n            this.winTextImage.x = this.featureConfig.winTextImage.x;\n            this.winTextImage.y = this.featureConfig.winTextImage.y;\n\n            this.historyCards.forEach((historyCard, index) => {\n                historyCard.x =\n                    this.featureConfig.historyCardsStart.x +\n                    index * this.featureConfig.historyCardSize.width +\n                    this.featureConfig.historyCardsOffset.x * index;\n                historyCard.y =\n                    this.featureConfig.historyCardsStart.y + this.featureConfig.historyCardsOffset.y * index;\n                historyCard.width = this.featureConfig.historyCardSize.width;\n                historyCard.height = this.featureConfig.historyCardSize.height;\n            });\n\n            this.updateTitlesFontSize([this.gambleAmountText, this.gambleToWinText]);\n\n            if (this.gambleOverlay) {\n                this.gambleOverlay.width = Core.display.stage.width;\n                this.gambleOverlay.height = Core.display.stage.height;\n            }\n\n            if (this.selectTextOrnaments) {\n                this.selectTextOrnaments.left.y = this.selectTextOrnaments.right.y =\n                    this.featureConfig.selectTextOrnament.y;\n                this.selectTextOrnaments.left.x =\n                    this.chooseText.x - this.chooseText.width / 2 - this.featureConfig.selectTextOrnament.x;\n                this.selectTextOrnaments.right.x =\n                    this.chooseText.x + this.chooseText.width / 2 + this.featureConfig.selectTextOrnament.x;\n            }\n        }\n\n        this.collectButton.x = this.featureConfig.collectButtonPosition.x;\n        this.collectButton.y = this.featureConfig.collectButtonPosition.y;\n        this.collectButton.scale.set(this.featureConfig.collectButtonPosition.scale || 1);\n\n        this.gambleButton.x = this.featureConfig.buttonPosition.x;\n        this.gambleButton.y = this.featureConfig.buttonPosition.y;\n        this.gambleButton.scale.set(this.featureConfig.buttonPosition.scale);\n        this.resizeText();\n        this.rescaleAndPosition(this.featureConfig.moneyContainersSize.width);\n        this.rescaleAndRepositionGambleMainContainer();\n    }\n    protected updateBalanceAndWinText(): void {\n        this.balanceText.text =\n            Core.translator\n                .translate('GAMBLE.BALANCE')\n                .toUpperCase()\n                .replace(/: /g, this.featureConfig.balanceText.separator) + this.balanceMoney.moneyText;\n        this.winText.text =\n            Core.translator\n                .translate('GAMBLE.WIN')\n                .toUpperCase()\n                .replace(/: /g, this.featureConfig.balanceText.separator) + this.winMoney.moneyText;\n    }\n    protected rescaleAndRepositionGambleMainContainer(): void {\n        this.gambleContainer.x = this.featureConfig.gambleContainer.x;\n        this.gambleContainer.y = this.featureConfig.gambleContainer.y;\n        this.gambleContainer.scale.set(\n            this.featureConfig.gambleContainerScale.x,\n            this.featureConfig.gambleContainerScale.y,\n        );\n    }\n\n    protected updateTitlesFontSize(objects: PIXIText[]): void {\n        objects.forEach((obj) => {\n            obj.style = this.featureConfig.textStyles.titlesText;\n        });\n    }\n\n    protected rescaleAndPosition(width: number): void {\n        let scale = 1;\n        // const amountText: PIXIText = this.find('gambleAmountText');\n        // const amountToWinText: PIXIText = this.find('gambleToWinText');\n        if (this.gambleAmountText) {\n            this.gambleAmountText.scale.set(scale);\n            this.gambleToWinText.scale.set(scale);\n            let firstScale: number = 1;\n            if (this.gambleAmountText.width > width - 10) {\n                firstScale = (width - 10) / this.gambleAmountText.width;\n            }\n            let secondScale: number = 1;\n            if (this.gambleToWinText.width > width - 10) {\n                secondScale = (width - 10) / this.gambleToWinText.width;\n            }\n            scale = secondScale < firstScale ? secondScale : firstScale;\n            this.gambleAmountText.scale.set(scale);\n            this.gambleToWinText.scale.set(scale);\n\n            if (this.featureConfig.setDifferentGambleToWinTextPositions) {\n                this.gambleToWinText.x = this.featureConfig.gambleToWinTextPosition.x;\n            } else {\n                this.gambleToWinText.x = this.featureConfig.amountAndWinTextPositions.x;\n            }\n\n            this.gambleAmountText.x = this.featureConfig.amountAndWinTextPositions.x;\n            this.gambleAmountText.y = this.featureConfig.amountAndWinTextPositions.y;\n            this.gambleToWinText.y = this.featureConfig.amountAndWinTextPositions.y;\n\n            if (this.featureConfig.setDifferentGambleToWinMoneyPositions) {\n                this.gambleToWinMoney.x = this.featureConfig.gambleToWinMoneyPosition.x;\n            } else {\n                this.gambleToWinMoney.x = this.featureConfig.amountAndWinMoneyPositions.x;\n            }\n\n            this.gambleAmountMoney.y = this.featureConfig.amountAndWinMoneyPositions.y;\n            this.gambleAmountMoney.x = this.featureConfig.amountAndWinMoneyPositions.x;\n            this.gambleToWinMoney.y = this.featureConfig.amountAndWinMoneyPositions.y;\n        }\n    }\n\n    protected playCardAnimation(): void {\n        this.showCardBacks();\n        this.hideCardFaces();\n        this.stopCardAnimation();\n        this.stopGambleWinTextAnimation();\n        this.cardSwitchInterval = Timers.setInterval(() => {\n            Core.sounds.play('gambleCardClick');\n            this.cardBlack.visible = !this.cardBlack.visible;\n        }, this.cardSwitchIntervalValue);\n    }\n\n    protected stopCardAnimation(): void {\n        if (Timers.isActiveInterval(this.cardSwitchInterval)) {\n            Core.sounds.stop('gambleCardClick');\n            Timers.clearInterval(this.cardSwitchInterval);\n        }\n    }\n\n    protected stopGambleWinTextAnimation(): void {\n        if (this.tween) {\n            this.tween.totalProgress(0);\n            this.tween.kill();\n            this.tween = null!;\n        }\n    }\n\n    protected hideCardBacks(): void {\n        this.cardBlack.visible = false;\n        this.cardRed.visible = false;\n    }\n\n    protected showCardBacks(): void {\n        this.cardBlack.visible = true;\n        this.cardRed.visible = true;\n    }\n\n    protected hideCardFaces(): void {\n        this.cardFace0.visible = false;\n        this.cardFace1.visible = false;\n        this.cardFace2.visible = false;\n        this.cardFace3.visible = false;\n    }\n\n    protected getCardTexture(value: number): Texture {\n        return this['cardFace' + value].texture;\n    }\n\n    protected setGambleButtonsTextures(): void {\n        this.gambleBlackButton.setTextures([\n            Core.assets.getTextureFromSpriteSheet('gamble', 'black.png'),\n            Core.assets.getTextureFromSpriteSheet('gamble', 'blackOn.png'),\n            Core.assets.getTextureFromSpriteSheet('gamble', 'black.png'),\n            Core.assets.getTextureFromSpriteSheet('gamble', 'black.png'),\n        ]);\n\n        this.gambleRedButton.setTextures([\n            Core.assets.getTextureFromSpriteSheet('gamble', 'red.png'),\n            Core.assets.getTextureFromSpriteSheet('gamble', 'redOn.png'),\n            Core.assets.getTextureFromSpriteSheet('gamble', 'red.png'),\n            Core.assets.getTextureFromSpriteSheet('gamble', 'red.png'),\n        ]);\n    }\n\n    protected createMoneyContainer(\n        id: string,\n        text: string,\n        money: number,\n        width: number,\n        height: number,\n    ): ViewContainer {\n        const _debug: boolean = false;\n        const container: ViewContainer = new ViewContainer();\n        container.name = id + 'Container';\n        container.width = width;\n        container.height = height;\n\n        const moneyHeight: number = height / 3;\n\n        const moneyConfig: MoneyTextConfig = new MoneyTextConfig();\n        moneyConfig.units = this.rootStore.uiStore.units;\n        moneyConfig.align = this.featureConfig.moneyConfig.gambleContainers.textAlign;\n        moneyConfig.shouldFitInBounds = true;\n        moneyConfig.bounds.width = width;\n        moneyConfig.bounds.height = moneyHeight;\n        moneyConfig.showCurrency = true;\n        moneyConfig.showCredits = Core.MONEY_MODE_IN_CREDITS.value;\n        moneyConfig.currency = this.rootStore.uiStore.currency;\n        moneyConfig.denomination = this.rootStore.uiStore.denominationInMoney;\n        moneyConfig.moneyFontSize = this.featureConfig.moneyConfig.gambleContainers.moneyFontSize;\n        moneyConfig.centsFontSize = this.featureConfig.moneyConfig.gambleContainers.centsFontSize;\n        moneyConfig.currencyFontSize = this.featureConfig.moneyConfig.gambleContainers.currencyFontSize;\n\n        const moneyId: string = id + 'Money';\n        const textId: string = id + 'Text';\n\n        this[moneyId] = new MoneyText(moneyConfig, money, this.featureConfig.textStyles.valuesText);\n\n        this[moneyId].name = moneyId;\n        this[moneyId].y = this.featureConfig.amountAndWinMoneyPositions.y;\n\n        this[textId] = new PIXIText(text, this.featureConfig.textStyles.titlesText);\n        this[textId].name = textId;\n        this[textId].y = this.featureConfig.amountAndWinTextPositions.y;\n        this[textId].anchor.set(0.5, 0.5);\n\n        // this.titles.push(this[textId]);\n        // this.values.push(this[moneyId]);\n\n        container.addChild(this[moneyId]);\n        container.addChild(this[textId]);\n\n        return container;\n    }\n\n    // private updateWinAndBalance(): void {}\n}\n","import {\n    AssetPriority,\n    AssetsCollection,\n    BaseComponentConfiguration,\n    DefaultAssets,\n    DefaultValue,\n    DynamicPositionObject,\n} from '@egt/core';\nimport { TextAlign } from '@egt/ui-lib';\nimport { IPointData, ISize, TextStyle } from 'pixi.js';\nimport { IAutoScalable } from '../../default/configuration/IAutoScalable';\nimport { IBackgroundVisibility } from '../../default/configuration/IBackgroundVisibility';\nimport { IButtonInterface } from '../../default/configuration/IButtonInterface';\nimport { IGambleBalanceAndWinText } from '../../default/configuration/IGambleBalanceAndWinText';\nimport { IGambleButtonData } from '../../default/configuration/IGambleButtonData';\nimport { IBooleanData } from '../../default/configuration/IGambleFeatureConfigurationDefault';\nimport { IGambleMoney } from '../../default/configuration/IGambleMoneyConfig';\nimport { IGambleOverlaySettings } from '../../default/configuration/IGambleOverlaySettings';\nimport { IGambleTextStyles } from '../../default/configuration/IGambleTextStyles';\nimport { IPointWithScale } from '../../default/configuration/IPointWithScale';\nimport { IGambleFeatureConfigurationTurtle } from './IGambleFeatureConfigurationTurtle';\nexport default class GambleFeatureConfigurationTurtle extends BaseComponentConfiguration {}\nexport function GambleFeatureConfigurationFactoryTurtle(): any {\n    class GambleFeatureConfigurationTurtleInternal\n        extends GambleFeatureConfigurationTurtle\n        implements IGambleFeatureConfigurationTurtle\n    {\n        @DefaultAssets([\n            {\n                id: 'svgGambleX2',\n                url: '../assets/features/slot/gamble/modes/turtle/ui-svg/x2Button.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 135, height: 76 },\n                },\n            },\n            {\n                id: 'svgGambleX2Inactive',\n                url: '../assets/features/slot/gamble/modes/turtle/ui-svg/x2ButtonDisabled.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 135, height: 76 },\n                },\n            },\n            {\n                id: 'gambleBnt',\n                url: '../assets/features/slot/gamble/modes/turtle/gambleBtnAnimation.json',\n                priority: AssetPriority.HIGHEST,\n                type: 'texture',\n            },\n            {\n                id: 'svgCollect',\n                url: '../assets/features/slot/gamble/modes/turtle/ui-svg/collectButton.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 196, height: 196 },\n                    desktop: { width: 196, height: 196 },\n                },\n            },\n            {\n                id: 'svgCollectDisabled',\n                url: '../assets/features/slot/gamble/modes/turtle/ui-svg/collectButtonDisabled.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 196, height: 196 },\n                    desktop: { width: 196, height: 196 },\n                },\n            },\n        ])\n        public featureAssets: AssetsCollection;\n\n        public historyCardCounts: number = 5;\n\n        public moneyContainerTitleY: number = 10;\n        public historyTextKey: string = 'GAMBLE.HISTORY';\n        public selectTextOrnamentAsset: string[] = [];\n\n        public buttonsToHide: string[] = [\n            'autoPlayButton',\n            'betButtons',\n            'denominationButton',\n            'spinSpeedButton',\n            'spinSpeedButtonDisabled',\n            'instaSpinsButton',\n            'spinSpeedIndicator',\n        ];\n        public buttonsToShow = ['spinSpeedIndicator', 'betButtons'];\n        public animationAssetInitialValues: object = {};\n        public setDifferentGambleToWinTextPositions: boolean = false;\n        public setDifferentGambleToWinMoneyPositions: boolean = false;\n        public gambleWaitTime: number = 2000;\n        public gamblesLeftTextSpacing: number = 10;\n        public buttonTextMargin: number = 50;\n        public gambleAnimationConfiguration: object[] = [\n            { rotation: 0 },\n            {\n                duration: 200,\n                rotation: 359,\n                repeat: -1,\n                ease: 'None',\n            },\n        ];\n        @DefaultValue<IPointData>({\n            defaults: { x: 0, y: 0 },\n        })\n        public gambleContainer: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IBooleanData>({\n            defaults: {\n                value: true,\n            },\n        })\n        public useVideoForBtnAnimation: DynamicPositionObject<IBooleanData> & IBooleanData;\n\n        @DefaultValue<IButtonInterface>({\n            defaults: {\n                x: 382,\n                y: 1158,\n                width: 0,\n                height: 0,\n                alpha: 1,\n                leftHandX: 0,\n                leftHandY: 0,\n                scale: 1,\n                visible: true,\n                textures: ['svgCollect', 'svgCollect', 'svgCollect', 'svgCollectDisabled'],\n                texturesSpecial: [\n                    'svgCollectButtonSpecial',\n                    'svgCollectButtonSpecial',\n                    'svgCollectButtonSpecial',\n                    'svgCollectButtonDisabledSpecial',\n                ],\n            },\n            landscape: { x: 1272, y: 353, scale: 0.81632 },\n            desktop: { x: 1272, y: 353, scale: 0.81632 },\n        })\n        public collectButtonPosition: DynamicPositionObject<IButtonInterface> & IButtonInterface;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 1, y: 1 },\n        })\n        public gambleContainerScale: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointWithScale>({\n            defaults: { x: 0, y: 0, scale: 0 },\n        })\n        public selectTextOrnament: DynamicPositionObject<IPointWithScale> & IPointWithScale;\n\n        @DefaultValue<IGambleOverlaySettings>({\n            defaults: { visible: false, fill: 0x000000, alpha: 0.75 },\n        })\n        public gambleOverlay: DynamicPositionObject<IGambleOverlaySettings> & IGambleOverlaySettings;\n\n        @DefaultValue<ISize>({\n            defaults: { width: 280, height: 80 },\n            portrait: { width: 230 },\n        })\n        public moneyContainersSize: DynamicPositionObject<ISize> & ISize;\n\n        @DefaultValue<ISize>({\n            defaults: { width: 280, height: 33 },\n            portrait: { width: 230, height: 18 },\n        })\n        public moneyBounds: DynamicPositionObject<ISize> & ISize;\n\n        @DefaultValue<IGambleMoney>({\n            defaults: {\n                gambleMoney: {\n                    textAlign: TextAlign.CENTER,\n                    moneyFontSize: 22,\n                    centsFontSize: 22,\n                    currencyFontSize: 22,\n                },\n                gambleContainers: {\n                    textAlign: TextAlign.CENTER,\n                    moneyFontSize: 40,\n                    centsFontSize: 40,\n                    currencyFontSize: 20,\n                },\n            },\n        })\n        public moneyConfig: DynamicPositionObject<IGambleMoney> & IGambleMoney;\n\n        @DefaultValue<ISize>({\n            defaults: { width: 41, height: 57 },\n        })\n        public historyCardSize: DynamicPositionObject<ISize> & ISize;\n\n        @DefaultValue<IGambleButtonData>({\n            defaults: { x: 1204, y: 181, leftHandX: 0, scale: 1 },\n            landscape: { x: 1204, y: 181 },\n            portrait: { x: 138, y: 1166 },\n            desktop: { x: 1204, y: 181 },\n        })\n        public buttonPosition: DynamicPositionObject<IGambleButtonData> & IGambleButtonData;\n\n        @DefaultValue<IBackgroundVisibility>({\n            defaults: { visible: 'landscape', invisible: 'portrait' },\n            portrait: { visible: 'portrait', invisible: 'landscape' },\n            desktop: { visible: 'landscape', invisible: 'portrait' },\n        })\n        public backgroundVisibility: DynamicPositionObject<IBackgroundVisibility> & IBackgroundVisibility;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 134, y: 63 },\n            portrait: { x: -17, y: 247 },\n            desktop: { x: 165, y: 67 },\n        })\n        public backgroundPosition: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<ISize>({\n            defaults: { width: 1092, height: 702 },\n            portrait: { width: 791, height: 709 },\n            desktop: { width: 1030, height: 580 },\n        })\n        public backgroundSize: DynamicPositionObject<ISize> & ISize;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 185, y: 132 },\n            portrait: { x: 3, y: 325 },\n            desktop: { x: 200, y: 115 },\n        })\n        public gambleAmountValue: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 0, y: 0 },\n        })\n        public gambleAmountText: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 0, y: 0 },\n        })\n        public gambleAmountTextScale: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 890, y: 132 },\n            portrait: { x: 533, y: 325 },\n            desktop: { x: 875, y: 115 },\n        })\n        public gambleToWinValue: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 0, y: 0 },\n        })\n        public gambleToWinMoneyPosition: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 140, y: 22 },\n            portrait: { x: 115, y: 22 },\n        })\n        public amountAndWinTextPositions: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 0, y: 0 },\n        })\n        public gambleToWinTextPosition: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 0, y: 40 },\n        })\n        public amountAndWinMoneyPositions: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IGambleBalanceAndWinText>({\n            defaults: { x: 184, y: 710, separator: ': ', visible: true },\n            portrait: { x: 30, y: 910 },\n            desktop: { visible: false },\n        })\n        public balanceText: DynamicPositionObject<IGambleBalanceAndWinText> & IGambleBalanceAndWinText;\n\n        @DefaultValue<IGambleBalanceAndWinText>({\n            defaults: { x: 1176, y: 710, separator: ': ', visible: true },\n            portrait: { x: 735, y: 910 },\n            desktop: { visible: false },\n        })\n        public winText: DynamicPositionObject<IGambleBalanceAndWinText> & IGambleBalanceAndWinText;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 680, y: 85 },\n            portrait: { x: 382, y: 280 },\n            desktop: { y: 77 },\n        })\n        public titleText: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IAutoScalable>({\n            defaults: { x: 680, y: 550, maxWidth: 0 },\n            portrait: { x: 382, y: 785, maxWidth: 750 },\n            landscape: { maxWidth: 950 },\n            desktop: { y: 530, maxWidth: 900 },\n        })\n        public chooseText: DynamicPositionObject<IAutoScalable> & IAutoScalable;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 680, y: 140 },\n            portrait: { x: 382, y: 340 },\n            desktop: { y: 137 },\n        })\n        public historyText: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 234, y: 288 },\n            portrait: { x: 35, y: 508 },\n            desktop: { x: 265, y: 300 },\n        })\n        public redButton: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 1, y: 1 },\n        })\n        public redButtonScale: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 950, y: 288 },\n            portrait: { x: 554, y: 508 },\n            desktop: { x: 919, y: 300 },\n        })\n        public blackButton: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 1, y: 1 },\n        })\n        public blackButtonScale: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 680, y: 660 },\n            portrait: { x: 382, y: 875 },\n            desktop: { y: 615 },\n        })\n        public gambleAttemptsLeft: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointWithScale>({\n            defaults: { x: 680, y: 377, scale: 1 },\n            portrait: { x: 382, y: 597 },\n        })\n        public animatedCards: DynamicPositionObject<IPointWithScale> & IPointWithScale;\n\n        @DefaultValue<ISize>({\n            defaults: { width: 183, height: 254 },\n        })\n        public gambleCardSize: DynamicPositionObject<ISize> & ISize;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 680, y: 377 },\n            portrait: { x: 382, y: 597 },\n        })\n        public winTextImage: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 555, y: 165 },\n            portrait: { x: 260, y: 365 },\n        })\n        public historyCardsStart: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 10, y: 0 },\n            portrait: { x: 10, y: 0 },\n        })\n        public historyCardsOffset: DynamicPositionObject<IPointData> & IPointData;\n\n        @DefaultValue<IGambleTextStyles>({\n            defaults: {\n                redText: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 32,\n                    fontWeight: 'bold',\n                    fill: '#FFFFFF',\n                }),\n                blackText: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 32,\n                    fontWeight: 'bold',\n                    fill: '#FFFFFF',\n                }),\n                balanceText: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 18,\n                    fill: '#FFFFFF',\n                    padding: 5,\n                }),\n                winText: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 18,\n                    fill: '#FFFFFF',\n                    padding: 5,\n                }),\n                titleText: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 33,\n                    fontWeight: 'bold',\n                    fill: '#FFFFFF',\n                    padding: 5,\n                }),\n                historyText: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 18,\n                    fill: '#FFFFFF',\n                    padding: 5,\n                }),\n                titlesText: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 20,\n                    fontWeight: 'bold',\n                    fill: '#FFD200',\n                    padding: 5,\n                }),\n                gambleChooseText: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 22,\n                    fontWeight: 'bold',\n                    fill: '#FFFFFF',\n                    padding: 5,\n                }),\n                gamblesLeftValueText: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 20,\n                    fontWeight: 'bold',\n                    fill: '#FFD200',\n                    padding: 5,\n                }),\n                gamblesLeftText: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 20,\n                    padding: 3,\n                    fontWeight: 'bold',\n                    fill: '#FFFFFF',\n                }),\n                valuesText: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 32,\n                    fontWeight: 'bold',\n                    fill: '#FFFFFF',\n                }),\n            },\n            portrait: {\n                titlesText: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 17,\n                    fontWeight: 'bold',\n                    fill: '#FFD200',\n                    padding: 5,\n                }),\n                gambleChooseText: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 18,\n                    fontWeight: 'bold',\n                    fill: '#FFFFFF',\n                    padding: 5,\n                }),\n            },\n        })\n        public textStyles: DynamicPositionObject<IGambleTextStyles> & IGambleTextStyles;\n    }\n    return GambleFeatureConfigurationTurtleInternal;\n}\n","import { BaseFeature, IModeConfig, IModes } from '@egt/core';\nimport { Features, RootView, ZOrders } from '@egt/slot';\nimport { DependencyContainer, Lifecycle } from 'tsyringe';\nimport LinesModesConfigurations, { LinesModes } from './LinesModeFactory';\nimport { LinesFeatureConfigurationFactoryDefault } from './modes/default/configuration/LinesFeatureConfigurationDefault';\nimport LinesFeatureConfigurationDefault from './modes/default/configuration/LinesFeatureConfigurationDefault';\nimport { LinesFeatureConfigurationFactorySpineLinesSquares } from './modes/spineLinesSquares/configuration/LinesFeatureConfigurationSpineLinesSquares';\nimport { LinesFeatureConfigurationFactorySpineOldLines } from './modes/spineOldLines/configuration/LinesFeatureConfigurationSpineOldLines';\nimport { LinesFeatureConfigurationFactorySpineSquares } from './modes/spineSquares/configuration/LinesFeatureConfigurationSpineSquares';\nimport { LinesFeatureConfigurationFactorySpineWaysToPay } from './modes/spineWaysToPay/configuration/LinesFeatureConfigurationSpineWaysToPay';\nimport { LinesFeatureConfigurationFactoryOnlyFrames } from './modes/onlyFrames/configuration/LinesFeatureConfigurationOnlyFrames';\n\ntype LinesModeConfig = IModes & { store?: any };\n\nexport default class LinesFeature extends BaseFeature {\n    public LINES_VIEW: any;\n    public configurationName = 'LinesFeature';\n    public featureType: Features = Features.LINES;\n    private LINES_CONTROLLER: any;\n    private LINES_STORE: any;\n\n    private initialSettings: any;\n    private configuration: LinesFeatureConfigurationDefault;\n    private addLinesInReels: boolean;\n\n    constructor(\n        configOrModeConfig?: IModeConfig | ((base: any) => any),\n        classType?: any,\n        // addLinesInReels: boolean = false,\n    ) {\n        super();\n        // this.addLinesInReels = addLinesInReels;\n\n        const baseConfigs = {\n            [LinesModes.DEFAULT]: LinesFeatureConfigurationFactoryDefault,\n            [LinesModes.SPINE_LINES_SQUARES]: LinesFeatureConfigurationFactorySpineLinesSquares,\n            [LinesModes.SPINE_OLD_LINES]: LinesFeatureConfigurationFactorySpineOldLines,\n            [LinesModes.SPINE_SQUARES]: LinesFeatureConfigurationFactorySpineSquares,\n            [LinesModes.SPINE_WAYS_TO_PAY]: LinesFeatureConfigurationFactorySpineWaysToPay,\n            [LinesModes.ONLY_FRAMES]: LinesFeatureConfigurationFactoryOnlyFrames,\n        };\n\n        // Support the old (configFactory, classType, addLinesInReels) signature for backward compatibility\n        let modeConfig: IModeConfig = {};\n        if (typeof configOrModeConfig === 'function') {\n            modeConfig = {\n                modeType: LinesModes.DEFAULT,\n                configuration: { [LinesModes.DEFAULT]: configOrModeConfig },\n            };\n            if (classType) {\n                modeConfig.view = { [LinesModes.DEFAULT]: classType };\n            }\n        } else if (configOrModeConfig) {\n            modeConfig = configOrModeConfig;\n            // `mode` is accepted as an alias for `modeType`\n            if ((modeConfig as any).mode && !modeConfig.modeType) {\n                modeConfig.modeType = (modeConfig as any).mode;\n            }\n            // `addLinesInReels` may be provided on the mode-config object\n            if ((modeConfig as any).addLinesInReels !== undefined) {\n                this.addLinesInReels = (modeConfig as any).addLinesInReels;\n            }\n            if (classType && !modeConfig.view) {\n                modeConfig.view = { [modeConfig.modeType ?? LinesModes.DEFAULT]: classType };\n            }\n        }\n\n        this.modeFactory = this.initMode<LinesModesConfigurations>(modeConfig, {\n            defaultModeType: LinesModes.DEFAULT,\n            baseConfigs,\n            defaultFactory: LinesModesConfigurations,\n        });\n    }\n\n    public destroy(): void {\n        this.LINES_CONTROLLER.destroy();\n        // @ts-ignore\n        this.LINES_VIEW = null;\n        // @ts-ignore\n        this.LINES_CONTROLLER = null;\n        // @ts-ignore\n        this.LINES_STORE = null;\n        // @ts-ignore\n        this.dependencyContainer = null;\n        if (this.configuration) {\n            this.configuration.destroy();\n            // @ts-ignore\n            this.configuration = null;\n        }\n        // @ts-ignore\n        this.initialSettings = null;\n\n        super.destroy();\n    }\n\n    public onRegisterDependencies(dependencyContainer: DependencyContainer): void {\n        super.onRegisterDependencies(dependencyContainer);\n\n        this.dependencyContainer.register(\n            'LinesFeatureConfiguration',\n            { useClass: this.mode.configuration },\n            { lifecycle: Lifecycle.Singleton },\n        );\n\n        this.dependencyContainer.registerInstance('LinesStore', this.LINES_STORE);\n\n        if (!this.dependencyContainer.isRegistered('LinesView')) {\n            this.dependencyContainer.register(\n                'LinesView',\n                { useClass: this.mode.view },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n\n        if (!this.dependencyContainer.isRegistered('LinesController')) {\n            this.dependencyContainer.register(\n                'LinesController',\n                { useClass: this.mode.controller },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n    }\n\n    public onResolveDependencies(_dependencyContainer: DependencyContainer): void {\n        this.LINES_VIEW = this.dependencyContainer.resolve('LinesView');\n        this.LINES_STORE = this.dependencyContainer.resolve('LinesStore');\n        this.LINES_CONTROLLER = this.dependencyContainer.resolve('LinesController');\n    }\n\n    public onInit(): void {\n        this.LINES_CONTROLLER.onInit();\n    }\n\n    public onInitComplete(): void {\n        this.LINES_CONTROLLER.afterInitComplete();\n        this.LINES_VIEW.afterInitComplete();\n    }\n\n    public onInitialRender(rootView: RootView): void {\n        if (this.addLinesInReels) {\n            this.LINES_VIEW.zIndex = -100;\n            // @ts-ignore\n            this.dependencyContainer.resolve('ReelsOverlay').addChild(this.LINES_VIEW);\n        } else {\n            this.LINES_VIEW.zIndex = ZOrders.LINES_LEVEL;\n            rootView.addChild(this.LINES_VIEW);\n        }\n    }\n\n    public onGameStarted(): void {\n        this.LINES_CONTROLLER.onGameStarted(this.initialSettings);\n        this.configuration = this.dependencyContainer.resolve('LinesFeatureConfiguration');\n    }\n\n    public onGameSettings(settings: any): void {\n        this.initialSettings = settings;\n        const StoreClass = (this.mode as LinesModeConfig).store;\n        this.LINES_STORE = new StoreClass();\n    }\n}\n","import { BaseModesConfigurations, IForceSetConfig, IModes } from '@egt/core';\nimport { LinesFeatureConfigurationFactoryDefault } from './modes/default/configuration/LinesFeatureConfigurationDefault';\nimport LinesControllerDefault from './modes/default/controllers/LinesControllerDefault';\nimport LinesStoreDefault from './modes/default/store/LinesStoreDefault';\nimport SpineLinesViewDefault from './modes/default/views/SpineLinesViewDefault';\nimport LinesViewSpineLinesSquares from './modes/spineLinesSquares/views/LinesViewSpineLinesSquares';\nimport LinesViewSpineOldLines from './modes/spineOldLines/views/LinesViewSpineOldLines';\nimport LinesViewSpineSquares from './modes/spineSquares/views/LinesViewSpineSquares';\nimport LinesViewSpineWaysToPay from './modes/spineWaysToPay/views/LinesViewSpineWaysToPay';\nimport LinesViewOnlyFrames from './modes/onlyFrames/views/LinesViewOnlyFrames';\nimport { LinesFeatureConfigurationFactorySpineLinesSquares } from './modes/spineLinesSquares/configuration/LinesFeatureConfigurationSpineLinesSquares';\nimport { LinesFeatureConfigurationFactorySpineOldLines } from './modes/spineOldLines/configuration/LinesFeatureConfigurationSpineOldLines';\nimport { LinesFeatureConfigurationFactorySpineSquares } from './modes/spineSquares/configuration/LinesFeatureConfigurationSpineSquares';\nimport { LinesFeatureConfigurationFactorySpineWaysToPay } from './modes/spineWaysToPay/configuration/LinesFeatureConfigurationSpineWaysToPay';\nimport { LinesFeatureConfigurationFactoryOnlyFrames } from './modes/onlyFrames/configuration/LinesFeatureConfigurationOnlyFrames';\n\nexport default class LinesModesConfigurations extends BaseModesConfigurations<LinesModes> {\n    constructor(modeType: LinesModes, forceSetConfig?: IForceSetConfig) {\n        super(modeType, forceSetConfig);\n    }\n\n    protected createBaseModesConfig(modeType: LinesModes): IModes {\n        switch (modeType) {\n            case LinesModes.SPINE_LINES_SQUARES:\n                return {\n                    controller: LinesControllerDefault,\n                    view: LinesViewSpineLinesSquares,\n                    store: LinesStoreDefault,\n                    configuration: LinesFeatureConfigurationFactorySpineLinesSquares(),\n                } as IModes;\n            case LinesModes.SPINE_OLD_LINES:\n                return {\n                    controller: LinesControllerDefault,\n                    view: LinesViewSpineOldLines,\n                    store: LinesStoreDefault,\n                    configuration: LinesFeatureConfigurationFactorySpineOldLines(),\n                } as IModes;\n            case LinesModes.SPINE_SQUARES:\n                return {\n                    controller: LinesControllerDefault,\n                    view: LinesViewSpineSquares,\n                    store: LinesStoreDefault,\n                    configuration: LinesFeatureConfigurationFactorySpineSquares(),\n                } as IModes;\n            case LinesModes.SPINE_WAYS_TO_PAY:\n                return {\n                    controller: LinesControllerDefault,\n                    view: LinesViewSpineWaysToPay,\n                    store: LinesStoreDefault,\n                    configuration: LinesFeatureConfigurationFactorySpineWaysToPay(),\n                } as IModes;\n            case LinesModes.ONLY_FRAMES:\n                return {\n                    controller: LinesControllerDefault,\n                    view: LinesViewOnlyFrames,\n                    store: LinesStoreDefault,\n                    configuration: LinesFeatureConfigurationFactoryOnlyFrames(),\n                } as IModes;\n            default:\n                return {\n                    controller: LinesControllerDefault,\n                    view: SpineLinesViewDefault,\n                    store: LinesStoreDefault,\n                    configuration: LinesFeatureConfigurationFactoryDefault(),\n                } as IModes;\n        }\n    }\n}\n\nexport enum LinesModes {\n    DEFAULT = 'default',\n    SPINE_LINES_SQUARES = 'spineLinesSquares',\n    SPINE_OLD_LINES = 'spineOldLines',\n    SPINE_SQUARES = 'spineSquares',\n    SPINE_WAYS_TO_PAY = 'spineWaysToPay',\n    ONLY_FRAMES = 'onlyFrames',\n}\n","import LinesFeature from './LinesFeature';\nimport LinesModesConfigurations, { LinesModes } from './LinesModeFactory';\n\n// ---- default mode ----\nimport { ILinesFeatureConfigurationDefault } from './modes/default/configuration/ILinesFeatureConfigurationDefault';\nimport LinesFeatureConfigurationDefault, {\n    LinesFeatureConfigurationFactoryDefault,\n} from './modes/default/configuration/LinesFeatureConfigurationDefault';\nimport LinesControllerDefault from './modes/default/controllers/LinesControllerDefault';\nimport LineTypesDefault from './modes/default/enums/LineTypesDefault';\nimport { ILinesConfig, ILinesPosition } from './modes/default/interfaces/interfacesDefault';\nimport LinesStoreDefault from './modes/default/store/LinesStoreDefault';\nimport SpineLinesViewDefault from './modes/default/views/SpineLinesViewDefault';\n\n// ---- per-view modes (views only; controller/store/configuration reused from default) ----\nimport LinesViewSpineLinesSquares from './modes/spineLinesSquares/views/LinesViewSpineLinesSquares';\nimport LinesViewSpineOldLines from './modes/spineOldLines/views/LinesViewSpineOldLines';\nimport LinesViewSpineSquares from './modes/spineSquares/views/LinesViewSpineSquares';\nimport LinesViewSpineWaysToPay from './modes/spineWaysToPay/views/LinesViewSpineWaysToPay';\nimport LinesViewOnlyFrames from './modes/onlyFrames/views/LinesViewOnlyFrames';\nimport LinesFeatureConfigurationSpineLinesSquares, {\n    LinesFeatureConfigurationFactorySpineLinesSquares,\n} from './modes/spineLinesSquares/configuration/LinesFeatureConfigurationSpineLinesSquares';\nimport { ILinesFeatureConfigurationSpineLinesSquares } from './modes/spineLinesSquares/configuration/ILinesFeatureConfigurationSpineLinesSquares';\nimport LinesFeatureConfigurationSpineOldLines, {\n    LinesFeatureConfigurationFactorySpineOldLines,\n} from './modes/spineOldLines/configuration/LinesFeatureConfigurationSpineOldLines';\nimport { ILinesFeatureConfigurationSpineOldLines } from './modes/spineOldLines/configuration/ILinesFeatureConfigurationSpineOldLines';\nimport LinesFeatureConfigurationSpineSquares, {\n    LinesFeatureConfigurationFactorySpineSquares,\n} from './modes/spineSquares/configuration/LinesFeatureConfigurationSpineSquares';\nimport { ILinesFeatureConfigurationSpineSquares } from './modes/spineSquares/configuration/ILinesFeatureConfigurationSpineSquares';\nimport LinesFeatureConfigurationSpineWaysToPay, {\n    LinesFeatureConfigurationFactorySpineWaysToPay,\n} from './modes/spineWaysToPay/configuration/LinesFeatureConfigurationSpineWaysToPay';\nimport { ILinesFeatureConfigurationSpineWaysToPay } from './modes/spineWaysToPay/configuration/ILinesFeatureConfigurationSpineWaysToPay';\nimport LinesFeatureConfigurationOnlyFrames, {\n    LinesFeatureConfigurationFactoryOnlyFrames,\n} from './modes/onlyFrames/configuration/LinesFeatureConfigurationOnlyFrames';\nimport { ILinesFeatureConfigurationOnlyFrames } from './modes/onlyFrames/configuration/ILinesFeatureConfigurationOnlyFrames';\n\n// New-architecture named exports\nexport {\n    LinesModes,\n    LinesModesConfigurations,\n    // shared interfaces\n    ILinesConfig,\n    ILinesPosition,\n    // default mode\n    LineTypesDefault,\n    ILinesFeatureConfigurationDefault,\n    LinesFeatureConfigurationDefault,\n    LinesFeatureConfigurationFactoryDefault,\n    LinesControllerDefault,\n    LinesStoreDefault,\n    SpineLinesViewDefault,\n    // per-view modes\n    LinesViewSpineLinesSquares,\n    LinesViewSpineOldLines,\n    LinesViewSpineSquares,\n    LinesViewSpineWaysToPay,\n    LinesViewOnlyFrames,\n    // per-view mode configurations\n    ILinesFeatureConfigurationSpineLinesSquares,\n    LinesFeatureConfigurationSpineLinesSquares,\n    LinesFeatureConfigurationFactorySpineLinesSquares,\n    ILinesFeatureConfigurationSpineOldLines,\n    LinesFeatureConfigurationSpineOldLines,\n    LinesFeatureConfigurationFactorySpineOldLines,\n    ILinesFeatureConfigurationSpineSquares,\n    LinesFeatureConfigurationSpineSquares,\n    LinesFeatureConfigurationFactorySpineSquares,\n    ILinesFeatureConfigurationSpineWaysToPay,\n    LinesFeatureConfigurationSpineWaysToPay,\n    LinesFeatureConfigurationFactorySpineWaysToPay,\n    ILinesFeatureConfigurationOnlyFrames,\n    LinesFeatureConfigurationOnlyFrames,\n    LinesFeatureConfigurationFactoryOnlyFrames,\n};\n\nexport default LinesFeature;\n","import { BaseComponentConfiguration, DefaultValue, DynamicPositionObject } from '@egt/core';\nimport { ILinesConfig, ILinesPosition } from '../interfaces/interfacesDefault';\nimport { ILinesFeatureConfigurationDefault } from './ILinesFeatureConfigurationDefault';\n\nexport default class LinesFeatureConfigurationDefault extends BaseComponentConfiguration {}\n\nexport function LinesFeatureConfigurationFactoryDefault(): any {\n    class LinesFeatureConfigurationInternal\n        extends LinesFeatureConfigurationDefault\n        implements ILinesFeatureConfigurationDefault\n    {\n        @DefaultValue<ILinesPosition>({\n            defaults: {\n                x: -158,\n                y: -77,\n                scale: 1,\n            },\n            desktop: {\n                x: -180,\n            },\n        })\n        public linesPositions: DynamicPositionObject<ILinesPosition> & ILinesPosition;\n\n        @DefaultValue<ILinesConfig>({\n            defaults: {\n                hasDesktopLinesVersion: true,\n                lineShowDelayFast: 0.05,\n                lineShowDelayNormal: 0.01,\n                spineNormalSpeed: 1.2,\n                spineFastSpeed: 3,\n                allLinesSpeed: 0,\n                fastCycleEnabled: true,\n                showAllWinLinesTogether: true,\n                showAllWinSquaresTogether: false,\n                hasSquaresOnlyOnScatters: false,\n                showOnlySquares: false,\n                showAllLinesWithAlpha: false,\n                squaresShowDelay: 0.8,\n                linesColors: [\n                    0x8686ce, 0x00bbed, 0x009e7c, 0xe599c2, 0xfaab1c, 0xe61e25, 0x5693bc, 0x00a551, 0x804bbc, 0xabb5ba,\n                    0x0090be, 0x16a584, 0xed481d, 0xd30e8b, 0xf27544, 0x048761, 0xf9004d, 0x6cbd45, 0x34bcb3, 0xa03894,\n                    0xc99c39, 0xe54878, 0x0061a0, 0xbb81b8, 0x892476, 0xed615d, 0x527b37, 0xf06d8a, 0x007983, 0xbe2028,\n                ],\n                extraSquareSpeed: 6.5,\n                onlySquareSpeed: 4,\n                squaresAppearSpeed: 80,\n                //scatter or other special symbols when you DO NOT want frame animation, NB works only for symbols NOT part of a line;\n                symbolsWithoutSquares: [],\n                showAllWinLinesToTheEnd: false,\n            },\n        })\n        public linesConfig: DynamicPositionObject<ILinesConfig> & ILinesConfig;\n        public hasFreeSpin: boolean = false;\n        // false => new REELS_POSITION scaling; true => old orientation-based scaling\n        public useLegacyScaling: boolean = true;\n    }\n    return LinesFeatureConfigurationInternal;\n}\n","import Core, { BaseController, GameTypes, Timers } from '@egt/core';\nimport {\n    BetResponse,\n    Features,\n    ISlotConfiguration,\n    LineMode,\n    RootStore,\n    SlotComponents,\n    SpinAnalyzer,\n} from '@egt/slot';\nimport { BehaviorSubject, merge } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { Machine, assign, interpret } from 'xstate';\nimport { ILinesFeatureConfigurationDefault } from '../configuration/ILinesFeatureConfigurationDefault';\nimport LinesStoreDefault from '../store/LinesStoreDefault';\nimport SpineLinesViewDefault from '../views/SpineLinesViewDefault';\n\n@injectable()\nexport default class LinesControllerDefault extends BaseController {\n    public isInFastSycle = false;\n    protected winSound: string = '';\n    protected creditsSoundTimeout: any;\n    protected stateMachineService;\n    protected stateMachine;\n    protected allLinesDrawFinished: boolean = false;\n    constructor(\n        @inject('ISlotConfiguration') protected config: ISlotConfiguration,\n        @inject('LinesView') protected view: SpineLinesViewDefault,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('LinesStore') protected store: LinesStoreDefault,\n        @inject('SpinAnalyzer') protected spinAnalyzer: SpinAnalyzer,\n        @inject('LinesFeatureConfiguration') protected featureConfiguration: ILinesFeatureConfigurationDefault,\n    ) {\n        super(view);\n    }\n\n    public onInit(): void {\n        this.rootStore.subjects.LINES_CONFIG = new BehaviorSubject(this.featureConfiguration.linesConfig);\n    }\n\n    public afterInitComplete(): void {\n        this.setLinesConfig();\n        this.createStateMachine();\n        // this.view.x = this.rootStore.subjects.REELS_POSITION.value.reelX;\n        // this.view.y = this.rootStore.subjects.REELS_POSITION.value.reelY;\n    }\n\n    public destroy(): void {\n        this.stateMachineService.stop();\n        this.stateMachineService = null;\n        this.stateMachine = null;\n        super.destroy();\n    }\n\n    public setLinesConfig(): void {\n        this.store.lineShowDelayFast = this.featureConfiguration.linesConfig.lineShowDelayFast;\n        this.store.lineShowDelayNormal = this.featureConfiguration.linesConfig.lineShowDelayNormal;\n        this.store.spineNormalSpeed = this.featureConfiguration.linesConfig.spineNormalSpeed;\n        this.store.spineFastSpeed = this.featureConfiguration.linesConfig.spineFastSpeed;\n        this.store.allLinesSpeed = this.featureConfiguration.linesConfig.allLinesSpeed;\n        this.store.fastCycleEnabled = this.featureConfiguration.linesConfig.fastCycleEnabled;\n        this.store.showAllWinLinesTogether = this.featureConfiguration.linesConfig.showAllWinLinesTogether;\n        this.store.showOnlySquares = this.featureConfiguration.linesConfig.showOnlySquares;\n        this.store.showAllLinesWithAlpha = this.featureConfiguration.linesConfig.showAllLinesWithAlpha;\n        this.store.linesColors = this.featureConfiguration.linesConfig.linesColors;\n    }\n\n    public onGameStarted(_settings: any): void {\n        this.view.init(this.store);\n        this.rootStore.subjects.REELS_STOPPED.chainSubscribe(Features.LINES, () => {\n            this.stateMachineService.send('ON_REELS_STOPPED');\n            // this.rootStore.subjects.REELS_STOPPED.next(Features.LINES);\n            this.rootStore.subjects.REELS_STOPPED.executorComplete();\n            this.allLinesDrawFinished = false;\n            if (\n                this.rootStore.domainStore.betResponse?.entries?.length === 0 ||\n                (this.rootStore.domainStore.betResponse?.entries?.length > 0 &&\n                    !this.rootStore.isGreatWin &&\n                    !this.rootStore.isTotalGreatWin) ||\n                this.isWaysToPay()\n            ) {\n                this.allLinesDrawFinished = true;\n                this.rootStore.subjects.ALL_LINES_DRAWN_FINISHED.next();\n            }\n        });\n\n        const clearLinesMerge = merge(\n            this.rootStore.subjects.BEFORE_SPIN,\n            this.rootStore.subjects.BET_PROGRESS_BEFORE_SPIN,\n            this.rootStore.domainStore.COLLECT_RESPONSE,\n        );\n\n        clearLinesMerge.pipe(takeUntil(this.DESTROY)).subscribe(this.clearLines.bind(this));\n\n        this.rootStore.domainStore.BET.pipe(takeUntil(this.DESTROY)).subscribe(this.onBetChanged.bind(this));\n\n        this.rootStore.uiStore.CLEAR_LINES.pipe(takeUntil(this.DESTROY)).subscribe(this.clearWithoutSounds.bind(this));\n\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(() => this.stateMachineService?.send('ORIENTATION'));\n\n        // SHOW ONLY MESSAGE BAR WITHOUT VISUAL LINES\n        this.rootStore.uiStore.HIDE_LINES_FROM_STAGE.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.stateMachineService.send('ON_HIDE_LINES');\n        });\n\n        // SHOW LINES WITHOUT BET RESPONSE\n        this.rootStore.uiStore.FORCE_START_LINES.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.forceStartLines.bind(this),\n        );\n\n        this.rootStore.subjects.RESTORE.chainSubscribe(Features.LINES, () => {\n            // if is from Blitz Lines are already shown\n            if (this.rootStore.uiStore.lastResponseFromBlitzPlay) {\n                this.rootStore.subjects.RESTORE.executorComplete();\n                return;\n            }\n            this.stateMachineService.send('ON_START_RESTORE_LINES');\n        });\n\n        this.rootStore.subjects.LINES_PAUSED.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            if (!this.rootStore.subjects.LINES_PAUSED.value) {\n                this.stateMachineService.send('ON_UNPAUSE_LINES');\n            } else {\n                this.stateMachineService.send('ON_PAUSE_LINES');\n            }\n        });\n    }\n\n    protected createStateMachine(): void {\n        const mustShowAllLines = this.mustShowAllLines.bind(this);\n        const linesPaused = this.linesPaused.bind(this);\n        const haveLinesToShow = this.haveLinesToShow.bind(this);\n        const shouldRestore = this.shouldRestore.bind(this);\n        const showAllLines = this.showAllLines.bind(this);\n        const showSingleLine = this.showSingleLine.bind(this);\n        const playSound = this.playSound.bind(this);\n        const setDefault = this.setDefault.bind(this);\n        const allLinesFinished = this.allLinesFinished.bind(this);\n        const onRestore = this.onRestore.bind(this);\n        const hideLines = this.hideLines.bind(this);\n        const setOrientation = this.setOrientation.bind(this);\n        this.stateMachine = Machine(\n            {\n                id: 'LinesController',\n                context: this.store,\n                initial: 'readyToStart',\n                on: {\n                    CLEAR_LINES: { target: 'readyToStart', actions: assign({ isRestore: false }) },\n                    ON_PAUSE_LINES: { target: 'linesPaused' },\n                    ON_ERROR: { actions: 'onError' },\n                    ON_HIDE_LINES: { actions: 'hideLines' },\n                    ORIENTATION: { actions: 'setOrientation' },\n                    ON_START_RESTORE_LINES: [{ actions: 'onRestore', cond: shouldRestore, target: 'showSingleLine' }],\n                },\n                states: {\n                    readyToStart: {\n                        entry: ['setDefault'],\n                        on: {\n                            ON_REELS_STOPPED: [\n                                { cond: mustShowAllLines, target: 'showAllLines', actions: 'playSound' },\n                                { cond: haveLinesToShow, target: 'showSingleLine', actions: 'playSound' },\n                            ],\n                            ON_FORCE_START_LINES: [{ cond: haveLinesToShow, target: 'showSingleLine' }],\n                        },\n                    },\n                    showAllLines: {\n                        entry: ['showAllLines'],\n                        on: {\n                            WIN_LINES_FINISHED: { target: 'startSingleLines' },\n                        },\n                    },\n                    startSingleLines: {\n                        after: [\n                            {\n                                delay: 300,\n                                target: 'showSingleLine',\n                                actions: 'allLinesFinished',\n                            },\n                        ],\n                    },\n                    linesPaused: {\n                        entry: ['linesPaused'],\n                        on: {\n                            ON_UNPAUSE_LINES: {\n                                target: 'showSingleLine',\n                            },\n                        },\n                    },\n                    showSingleLine: {\n                        entry: ['showSingleLine'],\n                        on: {\n                            SHOW_LINE_FINISHED: {\n                                target: 'waitDrawNextLine',\n                            },\n                        },\n                    },\n                    waitDrawNextLine: {\n                        after: [\n                            {\n                                delay: (context, _event) => {\n                                    return context.lineToDraw.cells ? context.lineShowDelay * 1000 : 2000;\n                                },\n                                target: 'showSingleLine',\n                            },\n                        ],\n                    },\n                },\n            },\n            {\n                actions: {\n                    showAllLines,\n                    showSingleLine,\n                    playSound,\n                    setDefault,\n                    allLinesFinished,\n                    hideLines,\n                    linesPaused,\n                    onRestore,\n                    setOrientation,\n                },\n                guards: {\n                    mustShowAllLines,\n                    haveLinesToShow,\n                    shouldRestore,\n                },\n            },\n        );\n\n        this.stateMachineService = interpret(this.stateMachine, { devTools: Core.configuration.devTools }).start();\n        this.view.stateMachineService = this.stateMachineService;\n    }\n\n    //////////////////////////// STATE MACHINE ACTIONS ////////////////////////////////////\n\n    protected onRestore(context): void {\n        if (\n            this.rootStore.domainStore.betResponse &&\n            this.rootStore.domainStore.betResponse.restoreResponse &&\n            !this.rootStore.domainStore.betResponse.restoreResponse.alreadyRestored\n        ) {\n            this.rootStore.uiStore.LINES_TO_SHOW.next(\n                this.rootStore.uiStore.LINES_TO_SHOW.value.concat(\n                    this.rootStore.domainStore.betResponse.restoreResponse.entries\n                        .sort((a, b) => a.line - b.line)\n                        .slice(),\n                ),\n            );\n            this.setLineSymbols(this.rootStore.domainStore.betResponse.restoreResponse.reels);\n        }\n        context.isRestore = true;\n        this.rootStore.subjects.RESTORE.executorComplete();\n    }\n\n    protected setOrientation(context): void {\n        this.view.setOrientation(context);\n    }\n    protected showAllLines(context): void {\n        this.rootStore.uiStore.ACTIVE_LINE.next(-1);\n        if (this.featureConfiguration.linesConfig.showAllWinSquaresTogether) {\n            this.view.showAllWinFrames(context);\n        } else {\n            this.view.showWinLines(context);\n        }\n    }\n\n    protected setLineSymbols(reels: number[][]): void {\n        this.rootStore.uiStore.LINES_TO_SHOW.value.forEach((line) => {\n            if (line.mode !== LineMode.MESSAGE) {\n                line.symbols = [];\n                for (let i = 0; i < line.cells?.length - 1; i += 2) {\n                    line.symbols.push(reels[line.cells[i]][line.cells[i + 1] + 1]);\n                }\n            }\n        });\n    }\n\n    protected clearLines(): void {\n        this.clearWithoutSounds();\n        this.stopSounds();\n    }\n\n    //////////////////////////// STATE MACHINE ACTIONS ENDS////////////////////////////////////\n\n    //////////// STATE MACHINE GUARDS /////////////////\n    protected mustShowAllLines(context, _event): boolean {\n        return this.rootStore.uiStore.LINES_TO_SHOW.value.length > 1 && context.showAllWinLinesTogether;\n    }\n\n    protected showSingleLine(context, _event): void {\n        if (context.indexInLinesToShow >= this.rootStore.uiStore.LINES_TO_SHOW.value.length) {\n            this.setDefault(context);\n            if (!this.allLinesDrawFinished && !context.isRestore) {\n                this.allLinesDrawFinished = true;\n                this.rootStore.subjects.ALL_LINES_DRAWN_FINISHED.next();\n            }\n        }\n\n        context.indexInLinesToShow++;\n\n        context.lineToDraw = this.rootStore.uiStore.LINES_TO_SHOW.value[context.indexInLinesToShow - 1];\n        if (context.lineToDraw) {\n            this.rootStore.uiStore.ACTIVE_LINE.next(context.lineToDraw);\n            if (!context.lineToDraw.cells) {\n                this.view.clearSquares();\n                this.stateMachineService.send('SHOW_LINE_FINISHED');\n            } else {\n                this.view.showSingleLine(context);\n            }\n        }\n    }\n\n    protected setDefault(context): void {\n        context.indexInLinesToShow = 0;\n        context.isInFastCycle = this.view.isInFastSycle = false;\n        context.lineShowDelay = context.lineShowDelayNormal;\n        context.spineSpeed = context.spineNormalSpeed;\n    }\n\n    protected shouldNotStartMoneyAnimationSound(): boolean {\n        const allowCreditAnimationSoundBeforeExpandingRound = this.allowCreditAnimationSoundBeforeExpand();\n        // prevents creditAnimation sound from overlapping bigWin feat sounds\n\n        const shouldNotStart =\n            ((this.rootStore.isGreatWin || this.rootStore.isTotalGreatWin) &&\n                Core.hasFeature(Features.BIG_WIN) &&\n                !allowCreditAnimationSoundBeforeExpandingRound) ||\n            this.rootStore.domainStore.SPIN_MODE.value === Features.CAMPAIGN_MANAGER;\n        return shouldNotStart;\n    }\n\n    /**\n     * In games with Expand Feature we want the following sequence, for spins with BigWin:\n     * 1. Play the winSound for the first round of lines\n     * - if winSound < bangUp duration => play creditAnimationSound to fill the gap\n     * 2. Finish the bangUp => Do the Expand and finish it\n     * -  start the BigWin, without playing winSound and creditAnimationSound after the Expand\n     * @returns boolean\n     */\n    protected allowCreditAnimationSoundBeforeExpand(): boolean {\n        // Check if we have expanding feature in the BET, this includes all rounds (before and after the expand)\n        const hasExpandsInBetRounds = this.rootStore.domainStore.serverBetResponse.game?.result?.spins?.find(\n            (s) => s.mutations.length > 0,\n        );\n        // Checks if the expand is happening in the current round\n        const hasExpandInCurrentRound = this.rootStore.domainStore.betResponse.mutations?.length > 0;\n        // Checks if there is Expand BigWin and the BigWin Feature is supported\n        const isBigWin = this.rootStore.isGreatWinOnExpand && Core.hasFeature(Features.BIG_WIN);\n        // If the BigWin is not in the round of expanding, allow the creditAnimationSound to play\n        return hasExpandsInBetRounds && !hasExpandInCurrentRound && isBigWin;\n    }\n\n    protected shouldRestore(_context, _event): boolean {\n        return Boolean(this.rootStore.domainStore.betResponse?.restoreResponse);\n    }\n\n    private allLinesFinished(context): void {\n        if (!context.isRestore && !this.allLinesDrawFinished) {\n            this.allLinesDrawFinished = true;\n            this.rootStore.subjects.ALL_LINES_DRAWN_FINISHED.next();\n        }\n\n        if (!context.fastCycleEnabled) {\n            this.setDefault(context);\n        } else {\n            context.isInFastCycle = this.view.isInFastSycle = true;\n            context.spineSpeed = context.spineFastSpeed;\n            context.lineShowDelay = context.lineShowDelayFast;\n        }\n    }\n\n    private hideLines(context, _event): void {\n        context.linesHidden = this.rootStore.uiStore.HIDE_LINES_FROM_STAGE.value;\n        if (context.linesHidden) {\n            this.view.clearSquares();\n            this.view.clearLines();\n        }\n    }\n\n    protected linesPaused(context): void {\n        this.view.clearSquares();\n        this.view.clearLines();\n        context.indexInLinesToShow = 0;\n        this.rootStore.uiStore.ACTIVE_LINE.next(-1);\n    }\n\n    private haveLinesToShow(_context, _event): boolean {\n        return this.rootStore.uiStore.LINES_TO_SHOW.value.length > 0;\n    }\n\n    //////////// STATE MACHINE GUARDS ENDS /////////////////\n\n    protected playSound(): void {\n        if (this.rootStore.subjects.LINES_PAUSED.value) {\n            return;\n        }\n        // THIS SHOULD BE REMOVED AFTER INVESTIGATING PROLBLEM ON RESPIN ON LAST\n        // FREE SPIN WITH RECOVERY\n        if (this.rootStore.domainStore?.betResponse?.entries?.length > 0) {\n            this.winSound = this.spinAnalyzer.getHighestPayingSymbolSound(\n                this.rootStore.domainStore.betResponse.entries,\n            );\n        }\n\n        if (this.winSound && this.winSound !== '') {\n            // in ways games on big win hit bigWin animation triggers immediately\n            // so we have to prevent other sounds from playing to avoid overlapping\n            if (\n                (this.rootStore.isGreatWin || this.rootStore.isTotalGreatWin) &&\n                Core.hasFeature(Features.BIG_WIN) &&\n                this.isWaysToPay()\n            ) {\n                return;\n            }\n\n            const creditSound = this.getCreditAnimationSoundName();\n            const shouldSeek = Core.sounds.getBGSoundConfiguration()?.syncCreditSoundWithBgSound;\n\n            if (Core.hasComponent(SlotComponents.BACKGROUND_SOUND) && this.winSound === creditSound && shouldSeek) {\n                // If there is BG sound we need to sync the creditAnimationSound with it\n                const bgSound = Core.sounds.getCurrentlyPlayingBGSound();\n                // Get the current time of the bg sound so we can sync the credit animation sound later\n                const time = Core.sounds.getSoundCurrentTime(bgSound);\n\n                // Seek the CreditAnimationSound with the BG\n                Core.sounds.play(this.winSound, true, 200, time);\n            } else {\n                // Play winLine sound\n                Core.sounds.play(this.winSound);\n            }\n\n            if (\n                this.winSound ===\n                this.config.symbolsConfig[\n                    this.spinAnalyzer.getHighestPayingWinLine(this.rootStore.domainStore.betResponse.entries).symbol\n                ].fullLineSound\n            ) {\n                this.rootStore.subjects.FULL_LINE_SOUND_PLAYED.next(this.winSound);\n\n                const fullLineSound = this.winSound;\n                const fullLineSoundDuration = Core.sounds.getSoundDuration(\n                    Core.sounds.getSoundSprite(fullLineSound),\n                    fullLineSound,\n                );\n\n                if (([Features.AUTO_PLAY] as string[]).includes(this.rootStore.domainStore.SPIN_MODE.value)) {\n                    if (this.rootStore.subjects.FULL_LINE_SOUND_PLAYED.value !== '') {\n                        this.rootStore.subjects.FULL_LINE_SOUND_PLAYED.next('');\n                        this.spinAnalyzer.emptyFullLinesArray();\n                    }\n                } else {\n                    const timeout = Timers.setTimeout(() => {\n                        if (this.rootStore.subjects.FULL_LINE_SOUND_PLAYED.value !== '') {\n                            this.rootStore.subjects.FULL_LINE_SOUND_PLAYED.next('');\n                        }\n                        // execute this function so that the fullLines array gets emptied after calling getHighestPayingWinLine in the if condition above\n                        this.spinAnalyzer.emptyFullLinesArray();\n                        Timers.clearTimeout(timeout);\n                    }, fullLineSoundDuration);\n                }\n            }\n\n            this.rootStore.uiStore.winSoundPlaying = this.winSound;\n            // for each line of different symbols it is possible to start specific\n            // creditAnimationSound if available\n            this.rootStore.uiStore.creditLineSoundPlaying = '';\n            if (this.winSound === 'creditAnimationSound' || this.winSound === 'fsCreditAnimationSound') {\n                if (this.winSound.indexOf('fullLine') === -1) {\n                    const creditAnimationSoundLine =\n                        this.config.symbolsConfig[\n                            this.spinAnalyzer.getHighestPayingWinLine(this.rootStore.domainStore.betResponse.entries)\n                                .symbol\n                        ].creditAnimationSound;\n                    if (creditAnimationSoundLine) {\n                        this.rootStore.uiStore.creditLineSoundPlaying = creditAnimationSoundLine;\n                        Core.sounds.play(this.rootStore.uiStore.creditLineSoundPlaying);\n                    }\n                }\n            }\n\n            if (this.winSound !== creditSound) {\n                // Extract win sound configuration if possible\n                let soundConfig;\n                if (Core.hasComponent(SlotComponents.BACKGROUND_SOUND)) {\n                    // Get the delay duration for the winSound from the config\n                    const config =\n                        Core.sounds.getBGSoundConfiguration()[creditSound] ||\n                        Core.sounds.getBGSoundConfiguration().creditAnimationSound;\n                    // re-assign sound config\n                    soundConfig = config[this.winSound] ? config[this.winSound] : config.default;\n                }\n\n                // Take the winSound duration and use it for offset\n                const sound: string = this.winSound.indexOf('fullLine') !== -1 ? 'mainSounds' : 'winSounds';\n                const winSoundDuration: number = Core.sounds.getSoundDuration(sound, this.winSound);\n\n                // For some games we want custom duration for the creditsSoundsTimeout\n                const creditsSoundDelay = soundConfig?.delay || winSoundDuration;\n                Timers.clearTimeout(this.creditsSoundTimeout);\n                this.creditsSoundTimeout = Timers.setTimeout(\n                    this.startMoneyAnimationSound.bind(this),\n                    creditsSoundDelay,\n                );\n            }\n        }\n    }\n\n    protected startMoneyAnimationSound(): void {\n        if (\n            this.rootStore.uiStore.BANGUP_RUNNING.value &&\n            this.winSound &&\n            !Core.sounds.isPlaying(this.getCreditAnimationSoundName())\n        ) {\n            if (this.shouldNotStartMoneyAnimationSound()) {\n                return;\n            }\n\n            const creditSound = this.getCreditAnimationSoundName();\n\n            if (Core.hasComponent(SlotComponents.BACKGROUND_SOUND)) {\n                // If there is BG sound we need to sync the creditAnimationSound with it\n                const bgSound = Core.sounds.getCurrentlyPlayingBGSound();\n                const shouldSeek = Core.sounds.getBGSoundConfiguration()?.syncCreditSoundWithBgSound;\n\n                if (bgSound && shouldSeek) {\n                    // Get the current time of the bg sound so we can sync the credit animation sound later\n                    const time = Core.sounds.getSoundCurrentTime(bgSound);\n\n                    // Get the creditAnimationSound (fs or normal game) Config so we can properly fadeIn the sound or default\n                    const config =\n                        Core.sounds.getBGSoundConfiguration()[creditSound] ||\n                        Core.sounds.getBGSoundConfiguration().creditAnimationSound;\n                    const soundConfig = config[this.winSound] ? config[this.winSound] : config.default;\n\n                    // Play the creditSound sound with the desired fade in and seek time\n                    Core.sounds.play(creditSound, true, soundConfig.fadeIn.duration, time);\n                    if (shouldSeek) {\n                        // Signals that the winSound is over and the BG sound should fade in earlier, in sync with the credit sound\n                        this.rootStore.uiStore.SYNC_BACKGROUND_AND_CREDIT_SOUNDS.next(true);\n                    }\n                    this.rootStore.uiStore.winSoundPlaying = creditSound;\n                } else {\n                    // There are cases like winLine + Mystery, mystery will interrupt and stop the bg sound\n                    // So the if check will fail, but we still need to play the credit sound.\n                    Core.sounds.play(creditSound);\n                    this.rootStore.uiStore.winSoundPlaying = creditSound;\n                }\n            } else {\n                Core.sounds.play(creditSound);\n                this.rootStore.uiStore.winSoundPlaying = creditSound;\n            }\n        }\n    }\n\n    protected clearWithoutSounds(): void {\n        this.stateMachineService.send('CLEAR_LINES');\n        //  if (!this.config.cascadeGame) {\n        this.rootStore.uiStore.LINES_TO_SHOW.next([]);\n        // }\n        if (this.rootStore.uiStore.ACTIVE_LINE.value !== -1) {\n            this.rootStore.uiStore.ACTIVE_LINE.next(-1);\n        }\n        Timers.clearTimeout(this.creditsSoundTimeout);\n        this.view.clearSquares();\n        this.view.clearLines();\n        this.view.killAllLinesTween();\n    }\n\n    protected onBetChanged(betResponse: BetResponse): void {\n        if (betResponse.entries && betResponse.entries.length > 0) {\n            if (betResponse.entries[0].mode !== 'cascade' && betResponse.entries[0].mode !== 'overflow') {\n                this.rootStore.uiStore.LINES_TO_SHOW.next(betResponse.entries.sort((a, b) => a.line - b.line).slice());\n                this.setLineSymbols(betResponse.reels);\n            }\n        } else {\n            // if (!this.config.cascadeGame) {\n            this.rootStore.uiStore.LINES_TO_SHOW.next([]);\n            //  }\n        }\n    }\n\n    protected stopSounds(): void {\n        Core.sounds.stop(this.winSound);\n        Core.sounds.stop(this.spinAnalyzer.defaultWinSound);\n        this.winSound = '';\n        if (\n            this.rootStore.uiStore.winSoundPlaying !== 'creditAnimationSound' &&\n            this.rootStore.uiStore.winSoundPlaying !== 'fsCreditAnimationSound' &&\n            this.rootStore.uiStore.winSoundPlaying !== 'coinFeatureSound'\n        ) {\n            this.rootStore.uiStore.winSoundPlaying = '';\n        }\n    }\n    protected isWaysToPay(): boolean {\n        return this.config.gameType === GameTypes.WAYS_TO_PAY_SLOT;\n    }\n\n    protected forceStartLines(): void {\n        if (this.rootStore.uiStore.LINES_TO_SHOW.value.length) {\n            this.stateMachineService.send('ON_FORCE_START_LINES');\n        }\n    }\n\n    protected getCreditAnimationSoundName(): string {\n        const sound: string =\n            this.spinAnalyzer.inFreeSpins() && Core.sounds.hasSound('fsCreditAnimationSound')\n                ? 'fsCreditAnimationSound'\n                : 'creditAnimationSound';\n        return sound;\n    }\n}\n","const enum LineTypesDefault {\n    LINES_SQUARES_MASK = 'LINES_SQUARES_MASK',\n    LINES_SPINES = 'LINES_SPINES',\n    LINES_SPINES_SEPARATED = 'LINES_SPINES_SEPARATED',\n    LINES_ONLY_SQUARES = 'LINES_ONLY_SQUARES',\n}\nexport default LineTypesDefault;\n","import { Line } from '@egt/slot';\nimport { injectable } from 'tsyringe';\nimport LineTypesDefault from '../enums/LineTypesDefault';\nimport { BaseStore } from '@egt/core';\n\n@injectable()\nexport default class LinesStoreDefault extends BaseStore {\n    // Number of current line drawing\n    public indexInLinesToShow: number = 0;\n    // Delay between draw the next line in fast mode\n    public lineShowDelayFast: number = 10;\n    // Delay between draw the next line in  normal mode\n    public lineShowDelayNormal: number = 80;\n    // Delay between draw the next line curent playing\n    public lineShowDelay: number = 80;\n    // Delay between draw the next line when show only squares\n    public squaresShowDelay: number = 0.8;\n    // Current Speed of line spine animation\n    public spineSpeed: number = 1;\n    // Speed of line spine animation in normal mode\n    public spineNormalSpeed: number = 5;\n    // Speed of line spine animation in fast mode\n    public spineFastSpeed: number = 5;\n    // Hide lines, show only message bar\n    public linesHidden: boolean = true;\n    // Current line to draw\n    public lineToDraw: Line;\n    // Time to show all lines firs time\n    public allLinesSpeed: number = 3;\n    // Wheather or not to show fast lines first time\n    public fastCycleEnabled: boolean = false;\n    // Show all winning lines at the beggining\n    public showAllWinLinesTogether: boolean = true;\n    // Show only squares without lines\n    public showOnlySquares: boolean = false;\n    // If currently fast lines are running\n    public isInFastCycle: boolean = false;\n    // Type of lines\n    public lineType: LineTypesDefault = LineTypesDefault.LINES_SPINES;\n    // To show all lines with alpha even if designers draw it appear from left to right\n    public showAllLinesWithAlpha: boolean = false;\n\n    public isRestore: boolean = false;\n\n    public linesColors: any[] | undefined;\n\n    // public extraSquareSpeed: number = 6.5;\n\n    // public squaresAppearSpeed: number = 50;\n}\n","import Core, { IVideoPlayer, Timers } from '@egt/core';\nimport { ReelsModes } from '@egt/reels';\nimport { ISlotConfiguration, Line, LineMode, RootStore, SlotComponents } from '@egt/slot';\nimport { ViewContainer } from '@egt/ui-lib';\nimport { gsap } from 'gsap';\nimport { Container, DisplayObject, Sprite, utils } from 'pixi.js';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { ILinesFeatureConfigurationDefault } from '../configuration/ILinesFeatureConfigurationDefault';\nimport LineTypesDefault from '../enums/LineTypesDefault';\n\n@injectable()\nexport default class SpineLinesViewDefault extends ViewContainer {\n    public linesScale = 1;\n    public stateMachineService;\n    public isInFastSycle;\n    public lineAnim: any;\n    public vp: IVideoPlayer;\n    public squares: any[] = [];\n    public lines: DisplayObject[] = [];\n    public squareOffset = 6;\n    public squaresAppearSpeed = 100;\n    public stopDelayWhenLess = 10;\n    public extraSquareSpeed = 1; // they can make the spine of new lines-squares with the needed speed instead of this\n    protected timeScale: number = 1;\n    protected frameTimeout: any = [];\n    protected lineAnimationsLayer: Container = new Container();\n    protected animationsLayer: Container = new Container();\n    protected lineCompleteEvent: any;\n    protected nonProportional: boolean = false;\n    protected linesContainer: Sprite;\n    protected allLinesTween: any;\n\n    constructor(\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('LinesFeatureConfiguration') protected featureConfiguration: ILinesFeatureConfigurationDefault,\n    ) {\n        super();\n    }\n\n    public afterInitComplete(): void {\n        this.linesContainer = new Sprite();\n        this.addChild(this.linesContainer);\n        this.linesContainer.x = this.getLinesContainerXPosition();\n        this.linesContainer.y = this.getLinesContainerYPosition();\n        this.linesContainer.scale.set(this.getReelsOverlayScale());\n        this.linesContainer.addChild(this.animationsLayer);\n        this.animationsLayer.addChild(this.lineAnimationsLayer);\n        this.animationsLayer.name = 'animationsLayer';\n        this.refreshLineAnimationsLayerScale();\n        if (Core.hasComponent(SlotComponents.NON_PROPORTIONAL_REELS)) {\n            this.nonProportional = true;\n        }\n        this.lineCompleteEvent = {\n            complete: () => {\n                this.lineAnim.state.removeListener(this.lineCompleteEvent);\n                this.stateMachineService.send('SHOW_LINE_FINISHED');\n            },\n        };\n    }\n\n    public init(context): void {\n        context.lineType = LineTypesDefault.LINES_SPINES;\n        this.createVideoPlayer(context);\n    }\n\n    private showLineSquares(lineEntry, context, uniqueCells: Set<string>): void {\n        if (!lineEntry?.cells) return;\n        const cellContext = {\n            ...context,\n            lineToDraw: lineEntry,\n        };\n        for (let i = 0; i < lineEntry.cells.length; i += 2) {\n            const row = lineEntry.cells[i];\n            const col = lineEntry.cells[i + 1];\n            const key = `${row}_${col}`;\n            if (!uniqueCells.has(key)) {\n                uniqueCells.add(key);\n                this.createSquareAnimation(row, col, lineEntry.cells.length, cellContext);\n            }\n        }\n    }\n\n    // SHOW ALL WIN FRAMES/SQUARES ACROSS ALL LINES AT ONCE\n    public showAllWinFrames(context): void {\n        if (context.linesHidden) {\n            this.stateMachineService.send('WIN_LINES_FINISHED');\n            return;\n        }\n\n        this.clearSquares();\n        this.animationsLayer.alpha = 1;\n\n        const linesToShow = this.rootStore.uiStore.LINES_TO_SHOW.value;\n        const uniqueCells = new Set<string>();\n        linesToShow.forEach((lineEntry) => {\n            this.showLineSquares(lineEntry, context, uniqueCells);\n        });\n\n        const duration = context.allLinesSpeed > 0 ? context.allLinesSpeed * 1000 : 1000;\n        Timers.setTimeout(() => {\n            this.stateMachineService.send('WIN_LINES_FINISHED');\n        }, duration);\n    }\n\n    // SHOW ALL WIN LINES TOGETHER\n    public showWinLines(context, colorize = false): void {\n        if (context.linesHidden) {\n            this.stateMachineService.send('WIN_LINES_FINISHED');\n            return;\n        }\n        if (\n            colorize &&\n            (!Array.isArray(context.linesColors) || context.linesColors.length < this.slotConfiguration.numberOfLines)\n        ) {\n            colorize = false;\n        }\n        this.createLineSpine();\n        const speed = context.allLinesSpeed;\n        this.animationsLayer.alpha = 1;\n        const animState = this.getAnimationState();\n\n        this.lineAnim.state.setAnimation(0, ((window as any).__SLN=(animState[0]), ((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"spine:packages/features/slot/lines/src/egt/modes/default/views/SpineLinesViewDefault.ts:124:9\",(window as any).__SLN]), (window as any).__SLN), false);\n\n        const lineDuration: number = Number(this.lineAnim.state.tracks[0].animationEnd.toFixed(2));\n\n        const shapes: any = [];\n\n        for (let index = 1; index <= this.slotConfiguration.numberOfLines; index++) {\n            const slot: any = this.lineAnim.skeleton.findSlot('line' + index);\n\n            slot.color.a = 0;\n            if (colorize) {\n                const rgbColor = utils.hex2rgb(context.linesColors[index - 1]);\n                slot.color.r = rgbColor[0];\n                slot.color.g = rgbColor[1];\n                slot.color.b = rgbColor[2];\n            }\n            if (this.rootStore.uiStore.LINES_TO_SHOW.value.find((x) => x.line === index - 1) !== undefined) {\n                shapes.push(slot.color);\n            }\n        }\n\n        if (this.featureConfiguration.linesConfig.showAllWinLinesToTheEnd) {\n            this.timeScale = this.lineAnim.state.timeScale = context.allLinesSpeed;\n            shapes.forEach((shape) => {\n                shape.a = 1;\n            });\n            Timers.setTimeout(() => {\n                this.stateMachineService.send('WIN_LINES_FINISHED');\n            }, lineDuration * 1000);\n            return;\n        }\n        // if there are only several lines the speed is looking already too slow\n        const shapesLength = shapes.length < this.stopDelayWhenLess ? this.stopDelayWhenLess : shapes.length;\n        let lineAnimDuration = (3 * speed) / (3 + shapesLength);\n        let stagger = lineAnimDuration / 3;\n        const allAnimationDuration = lineAnimDuration + stagger * shapesLength;\n\n        this.timeScale = this.lineAnim.state.timeScale = lineDuration / allAnimationDuration;\n\n        if (speed === 0) {\n            stagger = 0.9 / shapes.length; // 0.02;\n            lineAnimDuration = 0.5;\n            this.timeScale = this.lineAnim.state.timeScale = lineDuration / stagger;\n        }\n        this.allLinesTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/features/slot/lines/src/egt/modes/default/views/SpineLinesViewDefault.ts:168:30\",null]), gsap.to(shapes, {\n            duration: lineAnimDuration,\n            a: 1,\n            ease: 'none',\n            stagger: stagger / 3, // stagger is smaller because the animation must be at half when show all\n            onComplete: () => {\n                this.killAllLinesTween();\n                this.stateMachineService.send('WIN_LINES_FINISHED');\n            },\n        }));\n        if (context.showAllLinesWithAlpha) {\n            this.lineAnim.update(lineDuration / 1.5);\n            this.lineAnim.state.timeScale = 0;\n        }\n    }\n\n    public killAllLinesTween(): void {\n        if (this.allLinesTween) {\n            this.allLinesTween.kill();\n            this.allLinesTween = null;\n        }\n    }\n\n    // SHOW SINGLE LINE\n    public showSingleLine(context): void {\n        if (this.slotConfiguration.numberOfLines === 0) {\n            this.onCellsChanged(context, true);\n            return;\n        }\n        if (!this.lineAnim) {\n            this.createLineSpine();\n        }\n        this.lineAnim.update(0);\n        this.animationsLayer.alpha = 1;\n\n        // SHOW ONLY FRAMES\n        if (isNaN(context.lineToDraw._line)) {\n            this.onCellsChanged(context, true);\n            return;\n        }\n\n        if (\n            Line.isLine(context.lineToDraw) &&\n            (context.lineToDraw.mode === LineMode.LINE || context.lineToDraw.mode === LineMode.EXPAND)\n        ) {\n            const animState: string[] = this.getAnimationState();\n\n            let animation: string = this.lineAnim.skeleton.data.animations.some((anim) => anim.name === animState[1])\n                ? animState[1]\n                : animState[0];\n\n            if (this.checkForRightToLeft(context.lineToDraw)) {\n                animation += 'Right';\n            }\n            this.lineAnim.state.setAnimation(0, ((window as any).__SLN=(animation), ((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"spine:packages/features/slot/lines/src/egt/modes/default/views/SpineLinesViewDefault.ts:222:13\",(window as any).__SLN]), (window as any).__SLN), false);\n            this.timeScale = this.lineAnim.state.timeScale = context.spineSpeed;\n            for (let i = 1; i <= this.slotConfiguration.numberOfLines; i++) {\n                const slot: any = this.lineAnim.skeleton.findSlot('line' + i);\n                slot.color.a = 0;\n            }\n            const slotShow: any = this.lineAnim.skeleton.findSlot('line' + Number(context.lineToDraw.line + 1));\n            slotShow.color.a = Number(!context.linesHidden);\n\n            this.lineAnim.state.addListener(this.lineCompleteEvent);\n            this.onCellsChanged(context);\n        }\n    }\n\n    // CLEAR ALL SQUARES/ FRAMES\n    public clearSquares(): void {\n        if (this.vp) {\n            this.vp.stop();\n        }\n        for (const square of this.squares) {\n            this.animationsLayer.removeChild(square);\n        }\n        for (const squareTime of this.frameTimeout) {\n            Timers.clearTimeout(squareTime);\n        }\n        this.squares = [];\n        this.frameTimeout = [];\n    }\n\n    // CLEAR ALL LINES\n    public clearLines(): void {\n        if (this.lineAnim) {\n            this.lineAnimationsLayer.removeChild(this.lineAnim);\n            this.lineAnim.destroy();\n            this.lineAnim = null;\n        }\n    }\n\n    // SET ORIENTATION\n    public setOrientation(context): void {\n        this.linesContainer.x = this.getLinesContainerXPosition();\n        this.linesContainer.y = this.getLinesContainerYPosition();\n        this.linesContainer.scale.set(this.getReelsOverlayScale());\n        this.refreshLineAnimationsLayerScale();\n        if (this.nonProportional || this.featureConfiguration.hasFreeSpin) {\n            this.setSquaresPosition();\n            this.refreshLineAnimationPosition(context);\n        }\n    }\n\n    // CREATE SPINE SQUARE ANIMATION\n    protected createSquareSpine(row: number, col: number, context, onlySquares = false): void {\n        const symbolFrame = Core.spineAnimations.createSpineAnimations('spineSquares');\n        symbolFrame.name = 'frame_' + row + '_' + col;\n        this.animationsLayer.addChild(symbolFrame);\n        this.squares.push(symbolFrame);\n\n        const xOffset: number = this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value === 4 ? 0 : this.squareOffset;\n\n        symbolFrame.x =\n            this.rootStore.subjects.REELS_POSITION.value.reelWidth / 2 +\n            (this.rootStore.subjects.REELS_POSITION.value.reelWidth +\n                this.rootStore.subjects.REELS_POSITION.value.reelSpacing) *\n                row +\n            xOffset;\n        symbolFrame.y =\n            this.rootStore.subjects.REELS_POSITION.value.symbolHeight / 2 +\n            this.rootStore.subjects.REELS_POSITION.value.symbolHeight * col;\n        symbolFrame.scale.set(this.getSymbolElementScale());\n        symbolFrame.state.timeScale = this.timeScale * this.extraSquareSpeed;\n        this.extraSquareSpeed = onlySquares\n            ? this.featureConfiguration.linesConfig.onlySquareSpeed\n            : this.extraSquareSpeed;\n\n        if (onlySquares) {\n            //SPECIAL SYMBOL ANIM WITHOUT FRAMES\n            if (this.featureConfiguration.linesConfig.symbolsWithoutSquares?.includes(context.lineToDraw.symbol)) {\n                //Due to the complexity of the flow, responsible as well for msg bar, and to avoid regression bugs,\n                //the squares are set to alpha 0, not to block the flow;\n                symbolFrame.alpha = 0;\n            }\n            const onCompleteEvent = {\n                complete: () => {\n                    if (!context.isInFastCycle) {\n                        context.lineShowDelay = this.featureConfiguration.linesConfig.squaresShowDelay; // delay for only squares\n                    }\n                    symbolFrame.state.removeListener(onCompleteEvent);\n                    this.stateMachineService.send('SHOW_LINE_FINISHED');\n                    context.lineShowDelay = context.isInFastCycle\n                        ? context.lineShowDelayFast\n                        : context.lineShowDelayNormal;\n                },\n            };\n\n            symbolFrame.state.addListener(onCompleteEvent);\n        }\n        symbolFrame.state.setAnimation(0, ((window as any).__SLN=('frameAnimation' + this.animType), ((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"spine:packages/features/slot/lines/src/egt/modes/default/views/SpineLinesViewDefault.ts:318:9\",(window as any).__SLN]), (window as any).__SLN), false);\n    }\n\n    // CREATE SEQUENCE SQUARE ANIMATION\n    protected createSquareAnim(row: number, col: number, _context, _onlySquares = false): void {\n        const frame: Sprite = new Sprite();\n        frame.anchor.set(0.5);\n        frame.x =\n            (this.rootStore.subjects.REELS_POSITION.value.symbolWidth / 2) * (row + 1) +\n            (this.rootStore.subjects.REELS_POSITION.value.reelSpacing +\n                this.rootStore.subjects.REELS_POSITION.value.symbolWidth / 2) *\n                row;\n        frame.y =\n            (this.rootStore.subjects.REELS_POSITION.value.symbolHeight / 2) * (col + 1) +\n            (this.rootStore.subjects.REELS_POSITION.value.symbolHeight / 2) * col;\n        frame.scale.set(this.getSymbolElementScale());\n\n        this.animationsLayer.addChildAt(frame, 0);\n\n        this.squares.push(frame);\n        this.vp.config.fps = this.slotConfiguration.videoConfigs[0].fps * this.timeScale;\n        this.vp.addInstance(frame);\n        this.vp.play();\n    }\n\n    // CALCULATE SQUARES TO SHOW\n    protected onCellsChanged(context, onlySquares = false, forceSquares = false): void {\n        this.clearSquares();\n\n        const activeLine = context.lineToDraw;\n        if (\n            context.linesHidden ||\n            (!forceSquares &&\n                context.lineType !== LineTypesDefault.LINES_SQUARES_MASK &&\n                context.isInFastCycle &&\n                activeLine.mode !== LineMode.SCATTER) || // CHECK IF GAMES WITH SQUARES IN FAST MODE\n            !this.showSquares(activeLine)\n        ) {\n            return;\n        }\n\n        for (let i = 0; i < activeLine.cells.length; i += 2) {\n            const timer = Timers.setTimeout(\n                () => {\n                    const row = activeLine.cells[i];\n                    const col = activeLine.cells[i + 1];\n\n                    this.createSquareAnimation(row, col, activeLine.cells.length, context, onlySquares);\n                },\n                (this.squaresAppearSpeed * i) / this.timeScale,\n            );\n\n            this.frameTimeout.push(timer);\n        }\n    }\n\n    // GET SQUARE ANIMATION STATE\n    protected get animType(): string {\n        let mode = Core.isDesktopMode ? 'Desktop' : 'Landscape';\n        if (this.nonProportional && Core.ORIENTATION.value.isPortrait) {\n            mode = 'Portrait';\n        }\n        return mode;\n    }\n\n    // GET LINE SPINE ANIMATION STATE\n    protected getAnimationState(): string[] {\n        let animStr: string[] = ['winLinesLandscape', 'singleLineLandscape'];\n        if (Core.isDesktopMode && this.featureConfiguration.linesConfig.hasDesktopLinesVersion) {\n            animStr = ['winLinesDesktop', 'singleLineDesktop'];\n        } else if (this.nonProportional && Core.ORIENTATION.value.isPortrait) {\n            animStr = ['winLinesPortrait', 'singleLinePortrait'];\n        }\n        return animStr;\n    }\n\n    protected setSquaresPosition(): void {\n        const xOffset: number = this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value === 4 ? 0 : this.squareOffset;\n\n        this.squares.forEach((square) => {\n            const nameArr = square.name.split('_');\n            const row = nameArr[1];\n            const col = nameArr[2];\n\n            square.x =\n                this.rootStore.subjects.REELS_POSITION.value.reelWidth / 2 +\n                (this.rootStore.subjects.REELS_POSITION.value.reelWidth +\n                    this.rootStore.subjects.REELS_POSITION.value.reelSpacing) *\n                    row +\n                xOffset;\n            square.y =\n                this.rootStore.subjects.REELS_POSITION.value.symbolHeight / 2 +\n                this.rootStore.subjects.REELS_POSITION.value.symbolHeight * col;\n            square.scale.set(this.getSymbolElementScale());\n            const duration = square.state.tracks[0].trackTime;\n            square.state.setAnimation(0, ((window as any).__SLN=('frameAnimation' + this.animType), ((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"spine:packages/features/slot/lines/src/egt/modes/default/views/SpineLinesViewDefault.ts:413:13\",(window as any).__SLN]), (window as any).__SLN), false);\n            square.update(duration);\n        });\n    }\n\n    // Single switch between OLD (orientation-based) and NEW (REELS_POSITION-based) scaling.\n    protected get useLegacyScaling(): boolean {\n        return (\n            this.featureConfiguration.useLegacyScaling &&\n            !Core.hasComponent(SlotComponents.REELS, ReelsModes.DESKTOP_FOR_LANDSCAPE)\n        );\n    }\n\n    protected getLinesContainerXPosition(): number {\n        if (this.useLegacyScaling) {\n            return this.rootStore.subjects.REELS_POSITION.value.reelX;\n        }\n        return this.rootStore.subjects.REELS_POSITION.value.reelX * this.getReelsOverlayScale();\n    }\n\n    protected getLinesContainerYPosition(): number {\n        if (this.useLegacyScaling) {\n            return this.rootStore.subjects.REELS_POSITION.value.reelY;\n        }\n        return this.rootStore.subjects.REELS_POSITION.value.reelY * this.getReelsOverlayScale();\n    }\n\n    protected getReelsOverlayScale(): number {\n        if (this.useLegacyScaling) {\n            return Core.ORIENTATION.value.isLandscape ? 1 : this.rootStore.subjects.PORTRAIT_SCALE.value;\n        }\n        return this.rootStore.subjects.REELS_POSITION.value.scale;\n    }\n\n    protected getSymbolElementScale(): number {\n        if (this.useLegacyScaling || (this.slotConfiguration.desktopScale !== 1 && Core.isDesktopMode)) {\n            return 1;\n        }\n        return this.rootStore.subjects.REELS_POSITION.value.symbolScale;\n    }\n\n    protected refreshLineAnimationsLayerScale(): void {\n        this.lineAnimationsLayer.scale.set(this.getSymbolElementScale());\n    }\n\n    protected refreshLineAnimationPosition(context): void {\n        if (!this.lineAnim) {\n            return;\n        }\n\n        this.lineAnim.x = this.featureConfiguration.linesPositions.x * this.linesScale;\n        this.lineAnim.y = this.featureConfiguration.linesPositions.y * this.linesScale;\n\n        const duration = this.lineAnim.state.tracks[0]?.trackTime ?? 0;\n        const animState: string[] = this.getAnimationState();\n        let animation: string = this.lineAnim.skeleton.data.animations.some((anim) => anim.name === animState[1])\n            ? animState[1]\n            : animState[0];\n\n        if (\n            context?.lineToDraw &&\n            context.lineToDraw.mode !== LineMode.MESSAGE &&\n            this.checkForRightToLeft(context.lineToDraw)\n        ) {\n            animation += 'Right';\n        }\n\n        this.lineAnim.state.setAnimation(0, ((window as any).__SLN=(animation), ((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"spine:packages/features/slot/lines/src/egt/modes/default/views/SpineLinesViewDefault.ts:480:9\",(window as any).__SLN]), (window as any).__SLN), false);\n        this.lineAnim.update(duration);\n    }\n\n    protected createLineSpine(): void {\n        this.lineAnim = Core.spineAnimations.createSpineAnimations('spineLines');\n        this.lineAnim.scale.set(this.linesScale);\n\n        this.lineAnimationsLayer.addChild(this.lineAnim);\n        this.lineAnim.x = this.featureConfiguration.linesPositions.x * this.linesScale;\n        this.lineAnim.y = this.featureConfiguration.linesPositions.y * this.linesScale;\n        this.lineAnim.state.timeScale = this.timeScale;\n        for (let index = 1; index <= this.slotConfiguration.numberOfLines; index++) {\n            const slot: any = this.lineAnim.skeleton.findSlot('line' + index);\n            slot.color.a = 0;\n        }\n    }\n\n    // CONDITION TO SHOW SQUARES\n    protected showSquares(activeLine): boolean {\n        // REMOVE (activeLine.mode === LineMode.MESSAGE && activeLine.cells) AFTER DISCUSSION\n        // IF WE CAN REMOVE THE SQUARES DURING FREESPIN.PAY MESSAGE\n\n        return (\n            !this.featureConfiguration.linesConfig.hasSquaresOnlyOnScatters ||\n            activeLine.mode === LineMode.SCATTER ||\n            (activeLine.mode === LineMode.MESSAGE && activeLine.cells)\n        );\n    }\n\n    // CREATE SQUARES ANIMATION\n    protected createSquareAnimation(\n        row: number,\n        col: number,\n        allRows: number,\n        context: any,\n        onlySquares = false,\n    ): void {\n        const spineAnim = Core.assets.getAsset('spineSquares');\n        const haveSquareSiquence = Core.assets.getAsset('squareFrames');\n        if (spineAnim) {\n            this.createSquareSpine(row, col, context, onlySquares);\n        } else if (haveSquareSiquence) {\n            this.createSquareAnim(row, col, context, onlySquares);\n        } else if (row * 2 === allRows && !this.checkForRightToLeft(context.lineToDraw)) {\n            Timers.setTimeout(() => {\n                this.stateMachineService.send('SHOW_LINE_FINISHED');\n            }, 500);\n        }\n    }\n\n    // CREATE LINE ANIMATION\n\n    // CREATE SQUARES VIDEO PLAYER IF THERE MUST BE ONE\n    private createVideoPlayer(_context): void {\n        const spineAnim = Core.assets.getAsset('spineSquares');\n        const haveSquareSiquence = Core.assets.getAsset('squareFrames');\n        if (!spineAnim && haveSquareSiquence) {\n            const symbolTextures = Core.assets.getAnimationAssets('squareFrames', 'winFrame');\n\n            const videoConfig = {\n                id: 'squareFrames',\n                fps: symbolTextures.length / 2,\n                width: this.rootStore.subjects.REELS_POSITION.value.symbolWidth,\n                height: this.rootStore.subjects.REELS_POSITION.value.symbolHeight,\n                length: symbolTextures.length,\n                loop: false,\n            };\n            this.vp = Core.createVideoPlayer();\n            this.vp.config = videoConfig;\n            this.vp.frames = Object.keys(symbolTextures).map((personNamedIndex) => {\n                return symbolTextures[personNamedIndex];\n            });\n            this.vp.VIDEO_COMPLETE.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n                this.stateMachineService.send('SHOW_LINE_FINISHED');\n            });\n        }\n    }\n\n    // CHECK FOR RIGHT TO LEFT LINES\n    protected checkForRightToLeft(line: Line): boolean {\n        let isReversed: boolean = false;\n\n        if (line?.cells[0] === this.rootStore.subjects.NUMBER_OF_REELS.value - 1) {\n            isReversed = true;\n        }\n\n        return isReversed;\n    }\n}\n","import { BaseComponentConfiguration, DefaultValue, DynamicPositionObject } from '@egt/core';\nimport { ILinesConfig, ILinesPosition } from '../../default/interfaces/interfacesDefault';\nimport { ILinesFeatureConfigurationOnlyFrames } from './ILinesFeatureConfigurationOnlyFrames';\n\nexport default class LinesFeatureConfigurationOnlyFrames extends BaseComponentConfiguration {}\n\nexport function LinesFeatureConfigurationFactoryOnlyFrames(): any {\n    class LinesFeatureConfigurationInternal\n        extends LinesFeatureConfigurationOnlyFrames\n        implements ILinesFeatureConfigurationOnlyFrames\n    {\n        @DefaultValue<ILinesPosition>({\n            defaults: {\n                x: -158,\n                y: -77,\n                scale: 1,\n            },\n            desktop: {\n                x: -180,\n            },\n        })\n        public linesPositions: DynamicPositionObject<ILinesPosition> & ILinesPosition;\n\n        @DefaultValue<ILinesConfig>({\n            defaults: {\n                hasDesktopLinesVersion: true,\n                lineShowDelayFast: 0.05,\n                lineShowDelayNormal: 0.01,\n                spineNormalSpeed: 1.2,\n                spineFastSpeed: 3,\n                allLinesSpeed: 0,\n                fastCycleEnabled: true,\n                showAllWinLinesTogether: true,\n                hasSquaresOnlyOnScatters: false,\n                showOnlySquares: false,\n                showAllLinesWithAlpha: false,\n                linesColors: [\n                    0x8686ce, 0x00bbed, 0x009e7c, 0xe599c2, 0xfaab1c, 0xe61e25, 0x5693bc, 0x00a551, 0x804bbc, 0xabb5ba,\n                    0x0090be, 0x16a584, 0xed481d, 0xd30e8b, 0xf27544, 0x048761, 0xf9004d, 0x6cbd45, 0x34bcb3, 0xa03894,\n                    0xc99c39, 0xe54878, 0x0061a0, 0xbb81b8, 0x892476, 0xed615d, 0x527b37, 0xf06d8a, 0x007983, 0xbe2028,\n                ],\n                extraSquareSpeed: 6.5,\n                onlySquareSpeed: 4,\n                squaresAppearSpeed: 80,\n                //scatter or other special symbols when you DO NOT want frame animation, NB works only for symbols NOT part of a line;\n                symbolsWithoutSquares: [],\n                showAllWinLinesToTheEnd: false,\n                showAllWinSquaresTogether: false,\n                squaresShowDelay: 0.8,\n            },\n        })\n        public linesConfig: DynamicPositionObject<ILinesConfig> & ILinesConfig;\n        public hasFreeSpin: boolean = false;\n        public useLegacyScaling: boolean = true;\n    }\n    return LinesFeatureConfigurationInternal;\n}\n","import Core, { Timers } from '@egt/core';\nimport { ISlotConfiguration, RootStore, SpinAnalyzer } from '@egt/slot';\nimport 'pixi-spine';\nimport { Sprite } from 'pixi.js';\nimport { inject, injectable } from 'tsyringe';\nimport LineTypesDefault from '../../default/enums/LineTypesDefault';\nimport SpineLinesViewDefault from '../../default/views/SpineLinesViewDefault';\nimport { ILinesFeatureConfigurationOnlyFrames } from '../configuration/ILinesFeatureConfigurationOnlyFrames';\n\n@injectable()\nexport default class LinesViewOnlyFrames extends SpineLinesViewDefault {\n    public linesCleared: boolean = true;\n    public fastCycleEnabled: boolean = true;\n    public showAllWinLinesTogether: boolean = false;\n    public showAllWinLinesDelay: number = 0;\n    public showLineDuration = 1.1 * 1000;\n\n    constructor(\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('SpinAnalyzer') protected spinAnalyzer: SpinAnalyzer,\n        @inject('LinesFeatureConfiguration') protected featureConfiguration: ILinesFeatureConfigurationOnlyFrames,\n    ) {\n        super(slotConfiguration, rootStore, featureConfiguration);\n        //  this.rootStore.uiStore.ACTIVE_LINE.pipe(takeUntil(this.DESTROY)).subscribe(this.onActiveLineChanged.bind(this));\n    }\n\n    public afterInitComplete(): void {\n        super.afterInitComplete();\n    }\n\n    public init(context): void {\n        super.init(context);\n        context.lineType = LineTypesDefault.LINES_ONLY_SQUARES;\n    }\n\n    public showWinLines(_context): void {\n        // this.showLineDuration = context.spineNormalSpeed * 1000;\n        this.stateMachineService.send('WIN_LINES_FINISHED');\n    }\n\n    public showSingleLine(context): void {\n        this.onCellsChanged(context, true);\n    }\n\n    public clearLines(_clearWhenSwitchLines?: boolean): void {\n        //\n    }\n\n    public destroy(): void {\n        this.clearSquares();\n        super.destroy.apply(this, arguments);\n    }\n\n    public clearSquares(): void {\n        this.clearTimeout();\n        if (this.vp) {\n            this.vp.stop();\n            Core.destroyVideoPlayer(this.vp);\n            // @ts-ignore\n            this.vp = null;\n        }\n        for (const square of this.squares) {\n            this.linesContainer.removeChild(square);\n        }\n        this.squares = [];\n    }\n    public showHideAllLines(_val): void {\n        //\n    }\n\n    protected createSquareAnim(row: number, col: number): void {\n        const symbolTextures = Core.assets.getAnimationAssets('win-frame', 'winFrame');\n        const videoConfig = {\n            id: 'win-frame',\n            fps: 20,\n            width: 192,\n            height: 149,\n            length: symbolTextures.length,\n            loop: true,\n        };\n\n        let vpCreated = false;\n        if (!this.vp) {\n            this.vp = Core.createVideoPlayer();\n            this.vp.config = videoConfig;\n            this.vp.frames = Object.keys(symbolTextures).map((personNamedIndex) => {\n                return symbolTextures[personNamedIndex];\n            });\n            vpCreated = true;\n        }\n\n        const frame: Sprite = new Sprite();\n        frame.anchor.set(0.5);\n        frame.scale.set(this.featureConfiguration.linesPositions.scale);\n        const _offset: number = 8;\n        frame.x =\n            (this.rootStore.subjects.REELS_POSITION.value.symbolWidth / 2) * (row + 1) +\n            (this.rootStore.subjects.REELS_POSITION.value.reelSpacing +\n                this.rootStore.subjects.REELS_POSITION.value.symbolWidth / 2) *\n                row;\n        frame.y =\n            (this.rootStore.subjects.REELS_POSITION.value.symbolHeight / 2) * (col + 1) +\n            (this.rootStore.subjects.REELS_POSITION.value.symbolHeight / 2) * col;\n        this.linesContainer.addChild(frame);\n        this.squares.push(frame);\n\n        this.vp.addInstance(frame);\n        if (vpCreated) {\n            this.vp.play();\n        }\n        this.vp.play();\n        const timer = Timers.setTimeout(() => {\n            this.stateMachineService.send('SHOW_LINE_FINISHED');\n        }, this.showLineDuration);\n        this.frameTimeout.push(timer);\n    }\n\n    protected onCellsChanged(context, _onlySquares = false): void {\n        this.clearSquares();\n        const activeLine = context.lineToDraw;\n        for (let i = 0; i < activeLine.cells.length; i += 2) {\n            const row = activeLine.cells[i];\n            const col = activeLine.cells[i + 1];\n\n            this.createSquareAnim(row, col);\n        }\n    }\n\n    protected clearTimeout() {\n        this.frameTimeout.forEach((timeOut) => {\n            Timers.clearTimeout(timeOut);\n        });\n        this.frameTimeout.length = 0;\n    }\n}\n","import { BaseComponentConfiguration, DefaultValue, DynamicPositionObject } from '@egt/core';\nimport { ILinesConfig, ILinesPosition } from '../../default/interfaces/interfacesDefault';\nimport { ILinesFeatureConfigurationSpineLinesSquares } from './ILinesFeatureConfigurationSpineLinesSquares';\n\nexport default class LinesFeatureConfigurationSpineLinesSquares extends BaseComponentConfiguration {}\n\nexport function LinesFeatureConfigurationFactorySpineLinesSquares(): any {\n    class LinesFeatureConfigurationInternal\n        extends LinesFeatureConfigurationSpineLinesSquares\n        implements ILinesFeatureConfigurationSpineLinesSquares\n    {\n        @DefaultValue<ILinesPosition>({\n            defaults: {\n                x: -158,\n                y: -77,\n                scale: 1,\n            },\n            desktop: {\n                x: -180,\n            },\n        })\n        public linesPositions: DynamicPositionObject<ILinesPosition> & ILinesPosition;\n\n        @DefaultValue<ILinesConfig>({\n            defaults: {\n                hasDesktopLinesVersion: true,\n                lineShowDelayFast: 0.05,\n                lineShowDelayNormal: 0.01,\n                spineNormalSpeed: 1.2,\n                spineFastSpeed: 3,\n                allLinesSpeed: 0,\n                fastCycleEnabled: true,\n                showAllWinLinesTogether: true,\n                showAllWinSquaresTogether: false,\n                hasSquaresOnlyOnScatters: false,\n                showOnlySquares: false,\n                showAllLinesWithAlpha: false,\n                squaresShowDelay: 0.8,\n                linesColors: [\n                    0x8686ce, 0x00bbed, 0x009e7c, 0xe599c2, 0xfaab1c, 0xe61e25, 0x5693bc, 0x00a551, 0x804bbc, 0xabb5ba,\n                    0x0090be, 0x16a584, 0xed481d, 0xd30e8b, 0xf27544, 0x048761, 0xf9004d, 0x6cbd45, 0x34bcb3, 0xa03894,\n                    0xc99c39, 0xe54878, 0x0061a0, 0xbb81b8, 0x892476, 0xed615d, 0x527b37, 0xf06d8a, 0x007983, 0xbe2028,\n                ],\n                extraSquareSpeed: 6.5,\n                onlySquareSpeed: 4,\n                squaresAppearSpeed: 80,\n                //scatter or other special symbols when you DO NOT want frame animation, NB works only for symbols NOT part of a line;\n                symbolsWithoutSquares: [],\n                showAllWinLinesToTheEnd: false,\n            },\n        })\n        public linesConfig: DynamicPositionObject<ILinesConfig> & ILinesConfig;\n        public hasFreeSpin: boolean = false;\n        public useLegacyScaling: boolean = true;\n    }\n    return LinesFeatureConfigurationInternal;\n}\n","import { ISlotConfiguration, Line, LineMode, RootStore } from '@egt/slot';\nimport { gsap } from 'gsap';\nimport { Container, Graphics, Sprite, utils } from 'pixi.js';\nimport { inject, injectable } from 'tsyringe';\nimport LineTypesDefault from '../../default/enums/LineTypesDefault';\nimport SpineLinesViewDefault from '../../default/views/SpineLinesViewDefault';\nimport { ILinesFeatureConfigurationSpineLinesSquares } from '../configuration/ILinesFeatureConfigurationSpineLinesSquares';\n@injectable()\nexport default class LinesViewSpineLinesSquares extends SpineLinesViewDefault {\n    protected linesMask: Container;\n    protected lineMasks: Sprite[][] = [];\n    private hideLinesAnim;\n    private scatterColors: Map<number, number> = new Map<number, number>();\n\n    constructor(\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('LinesFeatureConfiguration')\n        protected featureConfiguration: ILinesFeatureConfigurationSpineLinesSquares,\n    ) {\n        super(slotConfiguration, rootStore, featureConfiguration);\n    }\n\n    public afterInitComplete(): void {\n        super.afterInitComplete();\n        let colorIndex = 0;\n        this.slotConfiguration.symbols.forEach((sym) => {\n            if (sym.isScatter()) {\n                this.scatterColors.set(sym.index(), this.featureConfiguration.linesConfig.linesColors?.[colorIndex]);\n                colorIndex++;\n            }\n        });\n        this.squareOffset = 0;\n        this.extraSquareSpeed = this.featureConfiguration.linesConfig.extraSquareSpeed;\n        this.squaresAppearSpeed = this.featureConfiguration.linesConfig.squaresAppearSpeed;\n        this.stopDelayWhenLess = 2;\n\n        this.linesMask = new Container();\n        this.redrawMask();\n\n        this.linesContainer.addChild(this.linesMask);\n        this.linesMask.visible = false;\n\n        this.lineCompleteEvent = {\n            complete: () => {\n                this.lineAnim.state.removeListener(this.lineCompleteEvent);\n                this.hideLinesAnim = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/features/slot/lines/src/egt/modes/spineLinesSquares/views/LinesViewSpineLinesSquares.ts:47:38\",null]), gsap.timeline({\n                    onComplete: () => {\n                        this.stateMachineService.send('SHOW_LINE_FINISHED');\n                        this.hideLinesAnim.kill();\n                        this.hideLinesAnim = null;\n                    },\n                }));\n                const delay = this.isInFastSycle ? 0.22 : 0;\n                this.hideLinesAnim.to(this.animationsLayer, {\n                    duration: 0.1,\n                    alpha: 0,\n                    delay,\n                    ease: 'power1.inOut',\n                });\n            },\n        };\n    }\n\n    public init(context): void {\n        super.init(context);\n        context.lineType = LineTypesDefault.LINES_SQUARES_MASK;\n    }\n\n    public showWinLines(context): void {\n        super.showWinLines(context, true);\n        this.lineAnimationsLayer.mask = null;\n        this.linesMask.visible = false;\n    }\n\n    public showSingleLine(context): void {\n        super.showSingleLine(context);\n        if (Line.isLine(context.lineToDraw) && context.lineToDraw.mode !== LineMode.LINE) {\n            return;\n        }\n        if (!this.lineAnim) {\n            return;\n        }\n\n        const slotShow: any = this.lineAnim.skeleton.findSlot('line' + Number(context.lineToDraw.line + 1));\n\n        const colorize =\n            Array.isArray(context.linesColors) && context.linesColors.length === this.slotConfiguration.numberOfLines;\n        if (colorize) {\n            const rgbColor = utils.hex2rgb(context.linesColors[context.lineToDraw.line]);\n            slotShow.color.r = rgbColor[0];\n            slotShow.color.g = rgbColor[1];\n            slotShow.color.b = rgbColor[2];\n        }\n    }\n\n    public setOrientation(context): void {\n        super.setOrientation(context);\n\n        // OLD behavior: only non-proportional reels redraw the mask, no square rescaling.\n        if (this.useLegacyScaling) {\n            if (this.nonProportional) {\n                this.redrawMask();\n                if (context.lineToDraw && context.lineToDraw.mode !== LineMode.MESSAGE) {\n                    this.applyCurrentLineMask(context.lineToDraw);\n                }\n            }\n            return;\n        }\n\n        this.redrawMask();\n        this.refreshSquaresOnOrientation();\n\n        if (\n            context.lineToDraw &&\n            context.lineToDraw.mode !== LineMode.MESSAGE &&\n            this.rootStore.uiStore.ACTIVE_LINE.value !== -1\n        ) {\n            this.applyCurrentLineMask(context.lineToDraw);\n        }\n    }\n\n    protected refreshSquaresOnOrientation(): void {\n        if (!this.squares.length) {\n            return;\n        }\n\n        this.setSquaresPosition();\n    }\n\n    protected onCellsChanged(context, onlySquares = false): void {\n        if (onlySquares) {\n            this.clearLines();\n        }\n        const activeLine = context.lineToDraw;\n        const tempDelay = this.squaresAppearSpeed;\n        this.squaresAppearSpeed = onlySquares ? 0 : tempDelay;\n        super.onCellsChanged(context, onlySquares, true);\n        this.squaresAppearSpeed = tempDelay;\n        this.timeScale = onlySquares ? 1 / 2 : 1 / 5;\n        this.lineAnimationsLayer.mask = null;\n        this.linesMask.visible = false;\n        for (let s = 0; s < this.rootStore.subjects.NUMBER_OF_REELS.value; s++) {\n            for (let l = 0; l < this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value; l++) {\n                this.lineMasks[s][l].visible = true;\n                this.lineMasks[s][l].alpha = 1;\n            }\n        }\n        for (let i = 0; i < activeLine.cells.length; i += 2) {\n            const row = activeLine.cells[i];\n            const col = activeLine.cells[i + 1];\n            this.lineMasks[row][col].visible = false;\n        }\n\n        this.lineAnimationsLayer.mask = this.linesMask;\n        this.linesMask.visible = true;\n    }\n\n    protected createSquareSpine(row: number, col: number, context, onlySquares = false): void {\n        super.createSquareSpine(row, col, context, onlySquares);\n        const fname = 'frame_' + row + '_' + col;\n        const square: any = this.animationsLayer.getChildByName(fname);\n        const colorize =\n            Array.isArray(context.linesColors) && context.linesColors.length === this.slotConfiguration.numberOfLines;\n        if (colorize) {\n            const scatterColor = this.scatterColors.get(context.lineToDraw?.symbol) || context.linesColors[0];\n            const rgbColor = utils.hex2rgb(context.linesColors[context.lineToDraw.line] || scatterColor);\n            square.tintRgb = rgbColor;\n        }\n    }\n\n    private redrawMask(): void {\n        this.linesMask.removeChildren();\n        this.lineMasks = [];\n        for (let s = 0; s < this.rootStore.subjects.NUMBER_OF_REELS.value; s++) {\n            this.lineMasks[s] = [];\n            for (let l = 0; l < this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value; l++) {\n                const reelmask = new Sprite();\n                const graphics = new Graphics();\n\n                graphics.beginFill(0xffff00);\n                // draw a rectangle\n                graphics.drawRect(\n                    (this.rootStore.subjects.REELS_POSITION.value.reelSpacing +\n                        this.rootStore.subjects.REELS_POSITION.value.reelWidth) *\n                        s -\n                        3,\n                    l * this.rootStore.subjects.REELS_POSITION.value.symbolHeight - 3,\n                    this.rootStore.subjects.REELS_POSITION.value.reelWidth + 6,\n                    this.rootStore.subjects.REELS_POSITION.value.symbolHeight + 6,\n                );\n                graphics.endFill();\n                reelmask.addChild(graphics);\n                this.lineMasks[s].push(reelmask);\n\n                const between = new Graphics();\n                between.beginFill(0xff0000);\n                // draw a rectangle\n                between.drawRect(\n                    (this.rootStore.subjects.REELS_POSITION.value.reelSpacing +\n                        this.rootStore.subjects.REELS_POSITION.value.reelWidth) *\n                        s -\n                        this.rootStore.subjects.REELS_POSITION.value.reelSpacing -\n                        3,\n                    l * this.rootStore.subjects.REELS_POSITION.value.symbolHeight - 3,\n                    this.rootStore.subjects.REELS_POSITION.value.reelSpacing + 6,\n                    this.rootStore.subjects.REELS_POSITION.value.symbolHeight + 6,\n                );\n                between.endFill();\n                this.linesMask.addChild(between);\n                this.linesMask.addChild(reelmask);\n            }\n        }\n    }\n\n    private applyCurrentLineMask(activeLine): void {\n        this.lineAnimationsLayer.mask = null;\n        this.linesMask.visible = false;\n\n        for (let s = 0; s < this.rootStore.subjects.NUMBER_OF_REELS.value; s++) {\n            for (let l = 0; l < this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value; l++) {\n                this.lineMasks[s][l].visible = true;\n                this.lineMasks[s][l].alpha = 1;\n            }\n        }\n\n        for (let i = 0; i < activeLine?.cells.length; i += 2) {\n            const row = activeLine.cells[i];\n            const col = activeLine.cells[i + 1];\n\n            if (this.rootStore.uiStore.ACTIVE_LINE.value !== -1) {\n                this.lineMasks[row][col].visible = false;\n            }\n        }\n\n        this.lineAnimationsLayer.mask = this.linesMask;\n        this.linesMask.visible = true;\n    }\n\n    private checkDiagonalSquares(s, l): void {\n        if (\n            (s < this.rootStore.subjects.NUMBER_OF_REELS.value - 1 &&\n                l < this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value - 1 &&\n                !this.lineMasks[s + 1][l].visible &&\n                !this.lineMasks[s][l + 1].visible) ||\n            (s > 0 &&\n                l < this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value - 1 &&\n                !this.lineMasks[s - 1][l].visible &&\n                !this.lineMasks[s][l + 1].visible) ||\n            (s > 0 && l > 0 && !this.lineMasks[s - 1][l].visible && !this.lineMasks[s][l - 1].visible) ||\n            (s < this.rootStore.subjects.NUMBER_OF_REELS.value - 1 &&\n                l > 0 &&\n                !this.lineMasks[s + 1][l].visible &&\n                !this.lineMasks[s][l - 1].visible)\n        ) {\n            this.lineMasks[s][l].visible = false;\n        }\n    }\n}\n","import { BaseComponentConfiguration, DefaultValue, DynamicPositionObject } from '@egt/core';\nimport { ILinesConfig, ILinesPosition } from '../../default/interfaces/interfacesDefault';\nimport { ILinesFeatureConfigurationSpineOldLines } from './ILinesFeatureConfigurationSpineOldLines';\n\nexport default class LinesFeatureConfigurationSpineOldLines extends BaseComponentConfiguration {}\n\nexport function LinesFeatureConfigurationFactorySpineOldLines(): any {\n    class LinesFeatureConfigurationInternal\n        extends LinesFeatureConfigurationSpineOldLines\n        implements ILinesFeatureConfigurationSpineOldLines\n    {\n        @DefaultValue<ILinesPosition>({\n            defaults: {\n                x: -158,\n                y: -77,\n                scale: 1,\n            },\n            desktop: {\n                x: -180,\n            },\n        })\n        public linesPositions: DynamicPositionObject<ILinesPosition> & ILinesPosition;\n\n        @DefaultValue<ILinesConfig>({\n            defaults: {\n                hasDesktopLinesVersion: true,\n                lineShowDelayFast: 0.05,\n                lineShowDelayNormal: 0.01,\n                spineNormalSpeed: 1.2,\n                spineFastSpeed: 3,\n                allLinesSpeed: 0,\n                fastCycleEnabled: true,\n                showAllWinLinesTogether: true,\n                hasSquaresOnlyOnScatters: false,\n                showOnlySquares: false,\n                showAllLinesWithAlpha: false,\n                linesColors: [\n                    0x8686ce, 0x00bbed, 0x009e7c, 0xe599c2, 0xfaab1c, 0xe61e25, 0x5693bc, 0x00a551, 0x804bbc, 0xabb5ba,\n                    0x0090be, 0x16a584, 0xed481d, 0xd30e8b, 0xf27544, 0x048761, 0xf9004d, 0x6cbd45, 0x34bcb3, 0xa03894,\n                    0xc99c39, 0xe54878, 0x0061a0, 0xbb81b8, 0x892476, 0xed615d, 0x527b37, 0xf06d8a, 0x007983, 0xbe2028,\n                ],\n                extraSquareSpeed: 6.5,\n                onlySquareSpeed: 4,\n                squaresAppearSpeed: 80,\n                //scatter or other special symbols when you DO NOT want frame animation, NB works only for symbols NOT part of a line;\n                symbolsWithoutSquares: [],\n                showAllWinLinesToTheEnd: false,\n            },\n        })\n        public linesConfig: DynamicPositionObject<ILinesConfig> & ILinesConfig;\n        public hasFreeSpin: boolean = false;\n        public useLegacyScaling: boolean = false;\n    }\n    return LinesFeatureConfigurationInternal;\n}\n","import Core from '@egt/core';\nimport { ISlotConfiguration, RootStore } from '@egt/slot';\nimport { Spine } from 'pixi-spine';\nimport { inject, injectable } from 'tsyringe';\n\nimport LineTypesDefault from '../../default/enums/LineTypesDefault';\nimport SpineLinesViewDefault from '../../default/views/SpineLinesViewDefault';\nimport { ILinesFeatureConfigurationSpineOldLines } from '../configuration/ILinesFeatureConfigurationSpineOldLines';\n\n@injectable()\nexport default class LinesViewSpineOldLines extends SpineLinesViewDefault {\n    public stateMachineService;\n    public linesScale = this.featureConfiguration.linesPositions.scale;\n\n    constructor(\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('LinesFeatureConfiguration') protected featureConfiguration: ILinesFeatureConfigurationSpineOldLines,\n    ) {\n        super(slotConfiguration, rootStore, featureConfiguration);\n    }\n\n    public afterInitComplete(): void {\n        super.afterInitComplete();\n    }\n    public init(context): void {\n        super.init(context);\n        context.lineType = LineTypesDefault.LINES_SPINES_SEPARATED;\n    }\n\n    public showWinLines(context): void {\n        if (context.linesHidden) {\n            this.stateMachineService.send('WIN_LINES_FINISHED');\n            return;\n        }\n        let isFirst = true;\n        for (let index = 0; index <= this.slotConfiguration.numberOfLines; index++) {\n            if (this.rootStore.uiStore.LINES_TO_SHOW.value.find((x) => x.line === index) !== undefined) {\n                const lineAnim = Core.spineAnimations.createSpineAnimations('spineLines');\n                this.lineAnimationsLayer.addChild(lineAnim);\n                lineAnim.x = this.featureConfiguration.linesPositions.x;\n                lineAnim.y = this.featureConfiguration.linesPositions.y;\n                lineAnim.state.setAnimation(0, ((window as any).__SLN=('lineAnimation' + this.animType + Number(index + 1)), ((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"spine:packages/features/slot/lines/src/egt/modes/spineOldLines/views/LinesViewSpineOldLines.ts:43:17\",(window as any).__SLN]), (window as any).__SLN), false);\n                if (isFirst) {\n                    const onCompleteEvent = {\n                        complete: () => {\n                            lineAnim.state.removeListener(onCompleteEvent);\n                            this.stateMachineService.send('WIN_LINES_FINISHED');\n                        },\n                    };\n\n                    lineAnim.state.addListener(onCompleteEvent);\n                    isFirst = false;\n                }\n                this.lines.push(lineAnim);\n            }\n        }\n    }\n\n    public showSingleLine(context): void | Spine {\n        this.clearLines();\n        if (isNaN(context.lineToDraw._line)) {\n            this.onCellsChanged(context, true);\n            return;\n        }\n        this.lineAnim = Core.spineAnimations.createSpineAnimations('spineLines');\n        this.lineAnimationsLayer.addChild(this.lineAnim);\n        this.lineAnim.x = this.featureConfiguration.linesPositions.x;\n        this.lineAnim.y = this.featureConfiguration.linesPositions.y;\n        this.timeScale = this.lineAnim.state.timeScale = context.spineSpeed;\n\n        this.lineAnim.state.setAnimation(\n            0,\n            ((window as any).__SLN=('lineAnimation' + this.animType + Number(context.lineToDraw._line + 1)), ((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"spine:packages/features/slot/lines/src/egt/modes/spineOldLines/views/LinesViewSpineOldLines.ts:72:9\",(window as any).__SLN]), (window as any).__SLN),\n            false,\n        );\n        const onCompleteEvent = {\n            complete: () => {\n                this.lineAnim.state.removeListener(onCompleteEvent);\n                this.stateMachineService.send('SHOW_LINE_FINISHED');\n            },\n        };\n        this.lineAnim.visible = !context.linesHidden;\n        this.lineAnim.state.addListener(onCompleteEvent);\n        this.onCellsChanged(context);\n        this.lines.push(this.lineAnim);\n        //////////////// squares //////////////////\n    }\n\n    public clearLines(): void {\n        for (const line of this.lines) {\n            this.lineAnimationsLayer.removeChild(line);\n        }\n        this.lines = [];\n    }\n}\n","import { BaseComponentConfiguration, DefaultValue, DynamicPositionObject } from '@egt/core';\nimport { ILinesConfig, ILinesPosition } from '../../default/interfaces/interfacesDefault';\nimport { ILinesFeatureConfigurationSpineSquares } from './ILinesFeatureConfigurationSpineSquares';\n\nexport default class LinesFeatureConfigurationSpineSquares extends BaseComponentConfiguration {}\n\nexport function LinesFeatureConfigurationFactorySpineSquares(): any {\n    class LinesFeatureConfigurationInternal\n        extends LinesFeatureConfigurationSpineSquares\n        implements ILinesFeatureConfigurationSpineSquares\n    {\n        @DefaultValue<ILinesPosition>({\n            defaults: {\n                x: -158,\n                y: -77,\n                scale: 1,\n            },\n            desktop: {\n                x: -180,\n            },\n        })\n        public linesPositions: DynamicPositionObject<ILinesPosition> & ILinesPosition;\n\n        @DefaultValue<ILinesConfig>({\n            defaults: {\n                hasDesktopLinesVersion: true,\n                lineShowDelayFast: 0.05,\n                lineShowDelayNormal: 0.01,\n                spineNormalSpeed: 1.2,\n                spineFastSpeed: 3,\n                allLinesSpeed: 0,\n                fastCycleEnabled: true,\n                showAllWinLinesTogether: true,\n                hasSquaresOnlyOnScatters: false,\n                showOnlySquares: false,\n                showAllLinesWithAlpha: false,\n                linesColors: [\n                    0x8686ce, 0x00bbed, 0x009e7c, 0xe599c2, 0xfaab1c, 0xe61e25, 0x5693bc, 0x00a551, 0x804bbc, 0xabb5ba,\n                    0x0090be, 0x16a584, 0xed481d, 0xd30e8b, 0xf27544, 0x048761, 0xf9004d, 0x6cbd45, 0x34bcb3, 0xa03894,\n                    0xc99c39, 0xe54878, 0x0061a0, 0xbb81b8, 0x892476, 0xed615d, 0x527b37, 0xf06d8a, 0x007983, 0xbe2028,\n                ],\n                extraSquareSpeed: 6.5,\n                onlySquareSpeed: 4,\n                squaresAppearSpeed: 80,\n                //scatter or other special symbols when you DO NOT want frame animation, NB works only for symbols NOT part of a line;\n                symbolsWithoutSquares: [],\n                showAllWinLinesToTheEnd: false,\n            },\n        })\n        public linesConfig: DynamicPositionObject<ILinesConfig> & ILinesConfig;\n        public hasFreeSpin: boolean = false;\n        public useLegacyScaling: boolean = false;\n    }\n    return LinesFeatureConfigurationInternal;\n}\n","import Core, { Timers } from '@egt/core';\nimport { ISlotConfiguration, RootStore } from '@egt/slot';\nimport { gsap } from 'gsap';\nimport { inject, injectable } from 'tsyringe';\nimport LineTypesDefault from '../../default/enums/LineTypesDefault';\nimport LinesStoreDefault from '../../default/store/LinesStoreDefault';\nimport SpineLinesViewDefault from '../../default/views/SpineLinesViewDefault';\nimport { ILinesFeatureConfigurationSpineSquares } from '../configuration/ILinesFeatureConfigurationSpineSquares';\n@injectable()\nexport default class LinesViewSpineSquares extends SpineLinesViewDefault {\n    // timeout before start next square in the line.\n    // if change here change also in in JWSlotFreeSpinController\n    // TODO: JWSLOT only fast lines\n    // protected readonly timeOutPeriod = 170;\n    protected readonly timeOutPeriod = 120;\n    protected readonly timeOutPeriodFast = 120;\n    constructor(\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('LinesStore') protected store: LinesStoreDefault,\n        @inject('LinesFeatureConfiguration') protected featureConfiguration: ILinesFeatureConfigurationSpineSquares,\n    ) {\n        super(slotConfiguration, rootStore, featureConfiguration);\n    }\n\n    public afterInitComplete(): void {\n        super.afterInitComplete();\n        this.squareOffset = 5;\n        this.store.squaresShowDelay = this.featureConfiguration.linesConfig.lineShowDelayNormal;\n    }\n\n    public init(context): void {\n        super.init(context);\n        context.lineType = LineTypesDefault.LINES_SQUARES_MASK;\n        context.lineShowDelay = 2;\n    }\n\n    public showWinLines(context): void {\n        context.isInFastCycle = context.fastCycleEnabled;\n        if (this.featureConfiguration.linesConfig.showAllWinLinesTogether) {\n            // show lighted animation and after time start squares line by libne\n            (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/features/slot/lines/src/egt/modes/spineSquares/views/LinesViewSpineSquares.ts:42:13\",null]), gsap.timeline({\n                duration: context.allLinesSpeed, // this.slotConfiguration.linesConfiguration.lineShowDelayFast, // 1.5,\n                onComplete: () => {\n                    this.stateMachineService.send('WIN_LINES_FINISHED');\n                },\n            }));\n        } else {\n            this.stateMachineService.send('WIN_LINES_FINISHED');\n        }\n    }\n\n    public showSingleLine(context): void {\n        if (!context.lineToDraw.cells) {\n            this.clearSquares();\n        } else {\n            this.drawLineSquares(context);\n        }\n    }\n\n    protected drawLineSquares(context): void {\n        // clear current\n        this.squares.forEach((spine) => {\n            spine.state.clearListeners();\n            spine = null;\n        });\n        this.frameTimeout.forEach((timeOut) => {\n            Timers.clearTimeout(timeOut);\n        });\n        this.clearSquares();\n\n        const activeLine = context.lineToDraw;\n        this.extraSquareSpeed = 0.5;\n        // for (let i = 0; i < activeLine.cells.length; i += 2) {\n        //     const timeOut = (context.isInFastCycle ? this.timeOutPeriodFast : this.timeOutPeriod) * i;\n        //     const timer = Timers.setTimeout(() => {\n        //         const row = activeLine.cells[i];\n        //         const col = activeLine.cells[i + 1];\n        //         this.createSquareCellSpine(row, col, i / 2 + 1, activeLine.cells.length / 2, context);\n        //     }, timeOut);\n\n        //     this.frameTimeout.push(timer);\n        // }\n        for (let i = 0; i < this.rootStore.subjects.NUMBER_OF_REELS.value * 2; i += 2) {\n            const timeOut = (context.isInFastCycle ? this.timeOutPeriodFast : this.timeOutPeriod) * i;\n            const timer = Timers.setTimeout(() => {\n                let row = activeLine.cells[activeLine.cells.length - 2];\n                let col = activeLine.cells[activeLine.cells.length - 1];\n                if (i <= activeLine.cells.length) {\n                    row = activeLine.cells[i];\n                    col = activeLine.cells[i + 1];\n                }\n                this.createSquareCellSpine(row, col, i / 2 + 1, activeLine.cells.length / 2, context);\n            }, timeOut);\n\n            this.frameTimeout.push(timer);\n        }\n    }\n\n    // CREATE SPINE SQUARE ANIMATION\n    protected createSquareCellSpine(row: number, col: number, cellIndex: number, cellLength: number, context): void {\n        const symbolFrame = Core.spineAnimations.createSpineAnimations('spineSquares');\n        if (cellIndex > cellLength) {\n            symbolFrame.visible = false;\n        }\n        symbolFrame.name = 'frame_' + row + '_' + col;\n        this.animationsLayer.addChild(symbolFrame);\n        this.squares.push(symbolFrame);\n\n        const xOffset: number = this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value === 4 ? 0 : this.squareOffset;\n\n        symbolFrame.x =\n            this.rootStore.subjects.REELS_POSITION.value.reelWidth / 2 +\n            (this.rootStore.subjects.REELS_POSITION.value.reelWidth +\n                this.rootStore.subjects.REELS_POSITION.value.reelSpacing) *\n                row +\n            xOffset;\n        symbolFrame.y =\n            this.rootStore.subjects.REELS_POSITION.value.symbolHeight / 2 +\n            this.rootStore.subjects.REELS_POSITION.value.symbolHeight * col;\n        symbolFrame.state.timeScale = context.isInFastCycle ? context.spineFastSpeed : context.spineNormalSpeed;\n\n        const onCompleteEvent = {\n            complete: () => {\n                if (!context.isInFastCycle) {\n                    context.lineShowDelay = context.squaresShowDelay; // delay for only squares\n                }\n                symbolFrame.state.removeListener(onCompleteEvent);\n                // context.lineShowDelay = context.isInFastCycle ? context.lineShowDelayFast : context.lineShowDelayNormal;\n                if (cellIndex >= this.rootStore.subjects.NUMBER_OF_REELS.value) {\n                    if (context.indexInLinesToShow >= this.rootStore.uiStore.LINES_TO_SHOW.value.length) {\n                        context.isInFastCycle = false;\n                    }\n                    context.lineShowDelay = context.isInFastCycle\n                        ? context.lineShowDelayFast\n                        : context.lineShowDelayNormal;\n                    this.stateMachineService.send('SHOW_LINE_FINISHED');\n                }\n            },\n        };\n\n        symbolFrame.state.addListener(onCompleteEvent);\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"spine:packages/features/slot/lines/src/egt/modes/spineSquares/views/LinesViewSpineSquares.ts:143:9\",\"frameAnimationLandscape\"]), symbolFrame.state.setAnimation(0, 'frameAnimationLandscape', false));\n    }\n}\n","import { BaseComponentConfiguration, DefaultValue, DynamicPositionObject } from '@egt/core';\nimport { ILinesConfig, ILinesPosition } from '../../default/interfaces/interfacesDefault';\nimport { ILinesFeatureConfigurationSpineWaysToPay } from './ILinesFeatureConfigurationSpineWaysToPay';\n\nexport default class LinesFeatureConfigurationSpineWaysToPay extends BaseComponentConfiguration {}\n\nexport function LinesFeatureConfigurationFactorySpineWaysToPay(): any {\n    class LinesFeatureConfigurationInternal\n        extends LinesFeatureConfigurationSpineWaysToPay\n        implements ILinesFeatureConfigurationSpineWaysToPay\n    {\n        @DefaultValue<ILinesPosition>({\n            defaults: {\n                x: -158,\n                y: -77,\n                scale: 1,\n            },\n            desktop: {\n                x: -180,\n            },\n        })\n        public linesPositions: DynamicPositionObject<ILinesPosition> & ILinesPosition;\n\n        @DefaultValue<ILinesConfig>({\n            defaults: {\n                hasDesktopLinesVersion: true,\n                lineShowDelayFast: 0.05,\n                lineShowDelayNormal: 0.01,\n                spineNormalSpeed: 1.2,\n                spineFastSpeed: 3,\n                allLinesSpeed: 0,\n                fastCycleEnabled: true,\n                showAllWinLinesTogether: true,\n                hasSquaresOnlyOnScatters: false,\n                showOnlySquares: false,\n                showAllLinesWithAlpha: false,\n                linesColors: [\n                    0x8686ce, 0x00bbed, 0x009e7c, 0xe599c2, 0xfaab1c, 0xe61e25, 0x5693bc, 0x00a551, 0x804bbc, 0xabb5ba,\n                    0x0090be, 0x16a584, 0xed481d, 0xd30e8b, 0xf27544, 0x048761, 0xf9004d, 0x6cbd45, 0x34bcb3, 0xa03894,\n                    0xc99c39, 0xe54878, 0x0061a0, 0xbb81b8, 0x892476, 0xed615d, 0x527b37, 0xf06d8a, 0x007983, 0xbe2028,\n                ],\n                extraSquareSpeed: 6.5,\n                onlySquareSpeed: 4,\n                squaresAppearSpeed: 80,\n                //scatter or other special symbols when you DO NOT want frame animation, NB works only for symbols NOT part of a line;\n                symbolsWithoutSquares: [],\n                showAllWinLinesToTheEnd: false,\n            },\n        })\n        public linesConfig: DynamicPositionObject<ILinesConfig> & ILinesConfig;\n        public hasFreeSpin: boolean = false;\n        public useLegacyScaling: boolean = false;\n    }\n    return LinesFeatureConfigurationInternal;\n}\n","import { ISlotConfiguration, RootStore } from '@egt/slot';\nimport { Container, Sprite, utils } from 'pixi.js';\nimport { inject, injectable } from 'tsyringe';\nimport LineTypesDefault from '../../default/enums/LineTypesDefault';\nimport SpineLinesViewDefault from '../../default/views/SpineLinesViewDefault';\nimport { ILinesFeatureConfigurationSpineWaysToPay } from '../configuration/ILinesFeatureConfigurationSpineWaysToPay';\n@injectable()\nexport default class LinesViewSpineWaysToPay extends SpineLinesViewDefault {\n    private linesMask: Container;\n    private lineMasks: Sprite[][] = [];\n    private hideLinesAnim;\n\n    constructor(\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('LinesFeatureConfiguration') protected featureConfiguration: ILinesFeatureConfigurationSpineWaysToPay,\n    ) {\n        super(slotConfiguration, rootStore, featureConfiguration);\n    }\n    public afterInitComplete(): void {\n        super.afterInitComplete();\n        this.squareOffset = 0;\n        this.extraSquareSpeed = 6.5;\n        this.squaresAppearSpeed = 80;\n        this.stopDelayWhenLess = 2;\n    }\n\n    public init(context): void {\n        super.init(context);\n        context.lineType = LineTypesDefault.LINES_SQUARES_MASK;\n    }\n\n    protected onCellsChanged(context, onlySquares = false): void {\n        if (onlySquares) {\n            this.clearLines();\n        }\n        const tempDelay = this.squaresAppearSpeed;\n        this.squaresAppearSpeed = onlySquares ? 0 : tempDelay;\n        super.onCellsChanged(context, onlySquares, true);\n        this.squaresAppearSpeed = tempDelay;\n        this.timeScale = onlySquares ? 1 / 2 : 1 / 5;\n    }\n\n    public showWinLines(context): void {\n        super.showWinLines(context, true);\n        this.lineAnimationsLayer.mask = null;\n    }\n\n    protected createSquareSpine(row: number, col: number, context, onlySquares = false): void {\n        super.createSquareSpine(row, col, context, onlySquares);\n        const fname = 'frame_' + row + '_' + col;\n        const square: any = this.animationsLayer.getChildByName(fname);\n        const colorize =\n            Array.isArray(context.linesColors) && context.linesColors.length >= context.lineToDraw.symbol + 1;\n        if (colorize) {\n            const scatterColor = context.linesColors[context.lineToDraw.symbol];\n            const rgbColor = utils.hex2rgb(scatterColor);\n            square.tintRgb = rgbColor;\n        }\n    }\n}\n","import { AssetPriority, BaseFeature, IModeConfig, IModes } from '@egt/core';\nimport { Features, RootView, ZOrders } from '@egt/slot';\nimport { DependencyContainer, Lifecycle } from 'tsyringe';\nimport VideosModesConfigurations, { VideosModes } from './VideosModeFactory';\nimport { VideosFeatureConfigurationFactoryDefault } from './modes/default/configuration/VideosFeatureConfigurationDefault';\nimport { VideosFeatureConfigurationFactorySpine } from './modes/spine/configuration/VideosFeatureConfigurationSpine';\n\nexport default class VideosFeature extends BaseFeature {\n    public view: any;\n    public configurationName = 'VideosFeature';\n    public featureType: Features = Features.VIDEOS;\n    public configuration: any;\n    private controller: any;\n    private initialSettings: any;\n\n    constructor(configOrModeConfig?: IModeConfig | ((base: any) => any), classType?: any) {\n        super();\n\n        // baseConfigs MUST list EVERY mode, else BaseModeFactory throws at runtime.\n        const baseConfigs = {\n            [VideosModes.DEFAULT]: VideosFeatureConfigurationFactoryDefault,\n            [VideosModes.SPINE]: VideosFeatureConfigurationFactorySpine,\n        };\n\n        // Support the old (configFactory, classType) signature for backward compatibility\n        let modeConfig: IModeConfig = {};\n        if (typeof configOrModeConfig === 'function') {\n            modeConfig = {\n                modeType: VideosModes.DEFAULT,\n                configuration: { [VideosModes.DEFAULT]: configOrModeConfig },\n            };\n            if (classType) {\n                modeConfig.view = { [VideosModes.DEFAULT]: classType };\n            }\n        } else if (configOrModeConfig) {\n            modeConfig = configOrModeConfig;\n            // `mode` is accepted as an alias for `modeType`\n            if ((modeConfig as any).mode && !modeConfig.modeType) {\n                modeConfig.modeType = (modeConfig as any).mode;\n            }\n            if (classType && !modeConfig.view) {\n                modeConfig.view = { [modeConfig.modeType ?? VideosModes.DEFAULT]: classType };\n            }\n        }\n\n        this.modeFactory = this.initMode<VideosModesConfigurations>(modeConfig, {\n            defaultModeType: VideosModes.DEFAULT,\n            baseConfigs,\n            defaultFactory: VideosModesConfigurations,\n        });\n    }\n\n    // initial state\n    public onGameSettings(gameSettings: any): void {\n        this.initialSettings = gameSettings;\n    }\n\n    public onRegisterDependencies(dependencyContainer: DependencyContainer): void {\n        super.onRegisterDependencies(dependencyContainer);\n        if (!this.dependencyContainer.isRegistered('VideosController')) {\n            this.dependencyContainer.register(\n                'VideosController',\n                { useClass: this.mode.controller },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n        if (!this.dependencyContainer.isRegistered('VideosView')) {\n            this.dependencyContainer.register(\n                'VideosView',\n                { useClass: this.mode.view },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n        this.dependencyContainer.register(\n            'VideosFeatureConfiguration',\n            { useClass: this.mode.configuration },\n            { lifecycle: Lifecycle.Singleton },\n        );\n        // SPINE_VIDEOS mode ships its own store (default mode has none).\n        if ((this.mode as IModes & { store?: any }).store) {\n            this.dependencyContainer.register(\n                'VideoStore',\n                { useClass: (this.mode as IModes & { store?: any }).store },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n    }\n\n    public destroy(): void {\n        // controller/configuration may be undefined if destroy runs before they are resolved,\n        // and not every mode implements destroy() — guard both to keep teardown mode-agnostic.\n        this.controller?.destroy?.();\n        // @ts-ignore\n        this.controller = null;\n\n        this.configuration?.destroy?.();\n        // @ts-ignore\n        this.configuration = null;\n\n        // CASCADE view has no destroy(); guard so teardown stays mode-agnostic.\n        this.view?.destroy?.();\n        // @ts-ignore\n        this.view = null;\n        // @ts-ignore\n        this.initialSettings = null;\n\n        super.destroy();\n    }\n\n    public onPriorityGroupLoaded(group: any): void {\n        // refreshVideos exists only on default/spine views; CASCADE & CASCADE_WAYS views don't implement it.\n        if (group.priority === AssetPriority.NORMAL) {\n            this.view?.refreshVideos?.();\n        }\n    }\n\n    public onAfterGameConfigurationCreated(): void {\n        super.onAfterGameConfigurationCreated();\n        this.configuration = this.dependencyContainer.resolve('VideosFeatureConfiguration');\n    }\n\n    public onResolveDependencies(_dependencyContainer: DependencyContainer): void {\n        this.view = this.dependencyContainer.resolve('VideosView');\n        this.controller = this.dependencyContainer.resolve('VideosController');\n        this.controller.afterResolvedDependencies?.(this.dependencyContainer);\n        this.view.afterResolvedDependencies?.(this.dependencyContainer);\n    }\n\n    public onInitComplete(): void {\n        // SPINE_VIDEOS controller positions its view here; default controller has no afterInitComplete.\n        this.controller.afterInitComplete?.();\n        this.view.afterInit?.();\n    }\n\n    public onInitialRender(rootView: RootView): void {\n        this.view.zIndex = ZOrders.VIDEOS_LEVEL;\n        rootView.addChild(this.view);\n    }\n\n    public onGameStarted(): void {\n        this.controller.onGameStarted(this.initialSettings);\n    }\n}\n","import { BaseModesConfigurations, IForceSetConfig, IModes } from '@egt/core';\nimport { VideosFeatureConfigurationFactoryCascadeWays } from './modes/cascade-ways/configuration/VideosFeatureConfigurationCascadeWays';\nimport VideosControllerCascadeWays from './modes/cascade-ways/controllers/VideosControllerCascadeWays';\nimport VideosViewCascadeWays from './modes/cascade-ways/views/VideosViewCascadeWays';\nimport { VideosFeatureConfigurationFactoryCascade } from './modes/cascade/configuration/VideosFeatureConfigurationCascade';\nimport VideosControllerCascade from './modes/cascade/controllers/VideosControllerCascade';\nimport VideosViewCascade from './modes/cascade/views/VideosViewCascade';\nimport { VideosFeatureConfigurationFactoryDefault } from './modes/default/configuration/VideosFeatureConfigurationDefault';\nimport VideosControllerDefault from './modes/default/controllers/VideosControllerDefault';\nimport VideosViewDefault from './modes/default/views/VideosViewDefault';\nimport { VideosFeatureConfigurationFactorySpine } from './modes/spine/configuration/VideosFeatureConfigurationSpine';\nimport VideosControllerSpine from './modes/spine/controllers/VideosControllerSpine';\nimport VideoStoreSpine from './modes/spine/store/VideoStoreSpine';\nimport VideosViewSpine from './modes/spine/views/VideosViewSpine';\n\nexport default class VideosModesConfigurations extends BaseModesConfigurations<VideosModes> {\n    constructor(modeType: VideosModes, forceSetConfig?: IForceSetConfig) {\n        super(modeType, forceSetConfig);\n    }\n\n    protected createBaseModesConfig(modeType: VideosModes): IModes {\n        switch (modeType) {\n            case VideosModes.SPINE:\n                return {\n                    controller: VideosControllerSpine,\n                    view: VideosViewSpine,\n                    store: VideoStoreSpine,\n                    configuration: VideosFeatureConfigurationFactorySpine(),\n                } as IModes;\n            case VideosModes.CASCADE:\n                return {\n                    controller: VideosControllerCascade,\n                    view: VideosViewCascade,\n                    configuration: VideosFeatureConfigurationFactoryCascade(),\n                } as IModes;\n            case VideosModes.CASCADE_WAYS:\n                return {\n                    controller: VideosControllerCascadeWays,\n                    view: VideosViewCascadeWays,\n                    configuration: VideosFeatureConfigurationFactoryCascadeWays(),\n                } as IModes;\n            default:\n                return {\n                    controller: VideosControllerDefault,\n                    view: VideosViewDefault,\n                    configuration: VideosFeatureConfigurationFactoryDefault(),\n                } as IModes;\n        }\n    }\n}\n\nexport enum VideosModes {\n    DEFAULT = 'default',\n    SPINE = 'spine',\n    CASCADE = 'cascade',\n    CASCADE_WAYS = 'cascade_ways',\n}\n","import VideosFeature from './VideosFeature';\nimport VideosModesConfigurations, { VideosModes } from './VideosModeFactory';\n\n// ---- default mode ----\nimport { IVideosFeatureConfigurationDefault } from './modes/default/configuration/IVideosFeatureConfigurationDefault';\nimport VideosFeatureConfigurationDefault, {\n    VideosFeatureConfigurationFactoryDefault,\n} from './modes/default/configuration/VideosFeatureConfigurationDefault';\nimport VideosControllerDefault from './modes/default/controllers/VideosControllerDefault';\nimport VideosViewDefault from './modes/default/views/VideosViewDefault';\n\n// ---- spine mode ----\nimport VideosControllerSpine from './modes/spine/controllers/VideosControllerSpine';\nimport VideosViewSpine from './modes/spine/views/VideosViewSpine';\nimport VideoStoreSpine from './modes/spine/store/VideoStoreSpine';\nimport VideosViewCascade from './modes/cascade/views/VideosViewCascade';\nimport VideosControllerCascade from './modes/cascade/controllers/VideosControllerCascade';\nimport { VideosContextCascade } from './modes/cascade/data/VideosContextCascade';\nimport EntryCascade from './modes/cascade/data/EntryCascade';\nimport EntryWays from './modes/cascade-ways/data/EntryWays';\n\nexport {\n    VideosModes,\n    VideosModesConfigurations,\n    // default mode\n    IVideosFeatureConfigurationDefault,\n    VideosFeatureConfigurationDefault,\n    VideosFeatureConfigurationFactoryDefault,\n    VideosControllerDefault,\n    VideosViewDefault,\n    // spine mode\n    VideosControllerSpine,\n    VideosViewSpine,\n    VideoStoreSpine,\n    // cascade mode\n    VideosControllerCascade,\n    VideosViewCascade,\n    VideosContextCascade,\n    EntryCascade,\n    // cascade ways\n    EntryWays,\n};\n\nexport default VideosFeature;\n","import { BaseComponentConfiguration } from '@egt/core';\nimport { IVideosFeatureConfigurationCascadeWays } from './IVideosFeatureConfigurationCascadeWays';\n\nexport default class VideosFeatureConfigurationCascadeWays extends BaseComponentConfiguration {}\n\nexport function VideosFeatureConfigurationFactoryCascadeWays(): typeof VideosFeatureConfigurationCascadeWays {\n    class InternalClass\n        extends VideosFeatureConfigurationCascadeWays\n        implements IVideosFeatureConfigurationCascadeWays\n    {\n        public originalSymbolsCount: number = 12;\n    }\n    return InternalClass;\n}\n","import { CascadeSubjects, ICascadeSlotConfiguration } from '@egt/cascade-slot';\nimport Core, { BaseController, Timers } from '@egt/core';\nimport { BetResponse, ISpin, RootStore } from '@egt/slot';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { Machine, interpret } from 'xstate';\nimport { VideosContextCascadeWays } from '../data/VideosContextCascadeWays';\nimport VideosViewCascadeWays from '../views/VideosViewCascadeWays';\nimport EntryWays from '../data/EntryWays';\n\n@injectable()\nexport default class VideosControllerCascadeWays extends BaseController {\n    private stateMachineService;\n    private stateMachine;\n    private cascadeSound: number = 0;\n\n    constructor(\n        @inject('VideosView') protected view: VideosViewCascadeWays,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('CascadeSubjects') protected cascadeSubjects: CascadeSubjects,\n        @inject('ISlotConfiguration') protected slotConfiguration: ICascadeSlotConfiguration,\n    ) {\n        super(view);\n    }\n\n    public onGameStarted(_settings: any): void {\n        this.createStateMachine();\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n        this.rootStore.subjects.BEFORE_SPIN.pipe(takeUntil(this.DESTROY)).subscribe(this.onCascadeComplete.bind(this));\n        this.cascadeSubjects.REMOVE_ON_ANIMATIONS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.removeOnAnimations.bind(this),\n        );\n        this.cascadeSubjects.NEW_CASCADE.pipe(takeUntil(this.DESTROY)).subscribe(this.onPlayVideos.bind(this));\n        this.cascadeSubjects.SHOW_ON_SYMBOL_VIDEOS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onPlaySymbolOnVideos.bind(this),\n        );\n        this.cascadeSubjects.NO_CASCADE_VIDEOS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onPlaySpecialVideos.bind(this),\n        );\n        this.cascadeSubjects.SHOW_ALL_SYMBOLS.pipe(takeUntil(this.DESTROY)).subscribe(this.onShowAllSymbols.bind(this));\n        this.view.sortableChildren = true;\n        this.cascadeSubjects.PLAY_SPECIAL_VIDEOS_EXTERNALLY.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onStartSpecialVideosExternally.bind(this),\n        );\n    }\n\n    public destroy(): void {\n        if (this.stateMachineService) {\n            this.stateMachineService.stop();\n            this.stateMachineService = null;\n        }\n        this.onCascadeComplete();\n        this.view.destroyVideos();\n        super.destroy();\n    }\n\n    private setOrientation(): void {\n        this.view.x = this.rootStore.subjects.REELS_POSITION.value.reelX;\n        this.view.y = this.rootStore.subjects.REELS_POSITION.value.reelY;\n        this.view.orientationChanged();\n    }\n\n    private createStateMachine(): void {\n        const actionPlayVideos = this.actionPlayVideos.bind(this);\n        const actionPlayExpandVideos = this.actionPlayExpandVideos.bind(this);\n        const actionPlayVideoAgain = this.actionPlayVideoAgain.bind(this);\n        const actionPlaySpecialVideoAgain = this.actionPlaySpecialVideoAgain.bind(this);\n        const actionVideoExploded = this.actionVideoExploded.bind(this);\n        const actionMainVideoHidden = this.actionMainVideoHidden.bind(this);\n        const actionComplete = this.actionComplete.bind(this);\n        const actionResetVideoPlayerConfig = this.actionResetVideoPlayerConfig.bind(this);\n\n        const specialVideoShouldLoop = this.specialVideoShouldLoop.bind(this);\n        const actionStartSpecialVideosExternally = this.actionStartSpecialVideosExternally.bind(this);\n        const actionSpecialSymbolAnimCompleteWhenStartExternally =\n            this.actionSpecialSymbolAnimCompleteWhenStartExternally.bind(this);\n        const playSpecialVideosAgainExternally = this.playSpecialVideosAgainExternally.bind(this);\n        // const shouldPlayVideoAgain = this.shouldPlayVideoAgain.bind(this);\n\n        this.stateMachine = Machine(\n            {\n                id: 'CascadeWaysVideoController',\n                context: new VideosContextCascadeWays(),\n                initial: 'readyToStart',\n                states: {\n                    readyToStart: {\n                        on: {\n                            PLAY_VIDEOS: { target: 'playVideos' },\n                            PLAY_VIDEOS_AND_EXPAND: { target: 'playVideosAndExpand' },\n                            PLAY_SPECIAL_VIDEOS: { target: 'playSpecialVideo' },\n                            PLAY_SPECIAL_VIDEOS_EXTERNALLY: { target: 'playSpecialVideosFromExternalFeature' },\n                        },\n                    },\n                    playVideos: {\n                        entry: ['actionPlayVideos'],\n                        on: {\n                            MAIN_VIDEO_COMPLETE: { actions: 'actionPlayVideoAgain' },\n                            HIDING_MAIN_SYMBOL: { target: 'videoExploded' },\n                        },\n                    },\n                    playVideosAndExpand: {\n                        entry: ['actionPlayVideos', 'actionPlayExpandVideos'],\n                        on: {\n                            MAIN_VIDEO_COMPLETE: { actions: 'actionPlayVideoAgain' },\n                            EXPAND_VIDEOS_COMPLETE: { target: 'videoExploded' },\n                        },\n                    },\n                    playSpecialVideo: {\n                        entry: ['actionPlayVideos'],\n                        on: {\n                            SPECIAL_VIDEOS_COMPLETE: [\n                                { actions: 'actionPlaySpecialVideoAgain', cond: specialVideoShouldLoop },\n                                { actions: 'actionComplete', target: 'waitingToStartFeature' },\n                            ],\n                        },\n                    },\n                    playSpecialVideosFromExternalFeature: {\n                        entry: ['actionStartSpecialVideosExternally'],\n                        on: {\n                            SPECIAL_SYMBOL_ANIM_COMPLETE_WHEN_START_EXTERNALLY: [\n                                { actions: 'playSpecialVideosAgainExternally', cond: specialVideoShouldLoop },\n                                {\n                                    actions: 'actionSpecialSymbolAnimCompleteWhenStartExternally',\n                                    target: 'readyToStart',\n                                },\n                            ],\n                        },\n                    },\n                    waitingToStartFeature: {\n                        on: {\n                            RESET_VIDEO_PLAYER_CONFIG: [\n                                { actions: 'actionResetVideoPlayerConfig', target: 'readyToStart' },\n                            ],\n                        },\n                    },\n                    videoExploded: {\n                        entry: ['actionVideoExploded'],\n                        on: {\n                            MAIN_VIDEO_COMPLETE: { actions: 'actionPlayVideoAgain' },\n                            CASCADE_COMPLETE: {\n                                actions: ['actionComplete', 'actionMainVideoHidden'],\n                                target: 'readyToStart',\n                            },\n                        },\n                    },\n                },\n            },\n            {\n                actions: {\n                    actionPlayVideos,\n                    actionPlayVideoAgain,\n                    actionPlayExpandVideos,\n                    actionPlaySpecialVideoAgain,\n                    playSpecialVideosAgainExternally,\n                    actionVideoExploded,\n                    actionMainVideoHidden,\n                    actionComplete,\n                    actionResetVideoPlayerConfig,\n                    actionStartSpecialVideosExternally,\n                    actionSpecialSymbolAnimCompleteWhenStartExternally,\n                },\n                guards: {\n                    specialVideoShouldLoop,\n                },\n            },\n        );\n\n        this.stateMachineService = interpret(this.stateMachine, { devTools: Core.configuration.devTools }).start();\n        this.view.stateMachineService = this.stateMachineService;\n    }\n\n    private onCascadeComplete(): void {\n        this.cascadeSound = 0;\n        this.view.destroyVideos();\n    }\n\n    private removeOnAnimations(onAnimation: { reel; cell }): void {\n        this.view.removeOnVideosAnimationsIfNotFinished(onAnimation);\n    }\n\n    private onPlayVideos(cascadeStep: number): void {\n        const mutations = this.rootStore.domainStore.betResponse.result.spins[cascadeStep].mutations;\n        if (mutations.length > 0 && mutations[0].type === 'expand') {\n            this.stateMachineService.send({ type: 'PLAY_VIDEOS_AND_EXPAND', cascadeStep });\n        } else {\n            this.stateMachineService.send({ type: 'PLAY_VIDEOS', cascadeStep });\n        }\n    }\n    private onPlaySpecialVideos(cascadeStep: number): void {\n        const hasWin: boolean = this.rootStore.domainStore.betResponse.result.spins[cascadeStep].totalWinAmount > 0;\n        if (hasWin && this.rootStore.isCascadeGreatWin) {\n            this.stateMachineService.send({ type: 'PLAY_SPECIAL_VIDEOS', cascadeStep });\n        }\n    }\n\n    private onStartSpecialVideosExternally(): void {\n        this.stateMachineService.send({ type: 'PLAY_SPECIAL_VIDEOS_EXTERNALLY' });\n    }\n\n    private onShowAllSymbols(): void {\n        this.stateMachineService.send({ type: 'RESET_VIDEO_PLAYER_CONFIG' });\n    }\n\n    private onPlaySymbolOnVideos(symbol): void {\n        this.view.playOnVideos(symbol[0], symbol[1], symbol[2], symbol[3]);\n    }\n\n    private actionPlayVideos(context: VideosContextCascadeWays, event): void {\n        let specialVideos: boolean = false;\n\n        context.specialVideoLoop = 0;\n        context.cascadeStep = event.cascadeStep;\n        context.entries = this.rootStore.domainStore.betResponse.result.spins[event.cascadeStep].entries;\n\n        if (event.type === 'PLAY_SPECIAL_VIDEOS') {\n            specialVideos = true;\n            Core.sounds.play('scatterWin');\n            if (Core.sounds.isPlaying('freeSpinsBackgroundSound')) {\n                Core.sounds.setVolume('freeSpinsBackgroundSound', 0);\n            }\n            if (Core.sounds.isPlaying('superFreeSpinsBackgroundSound')) {\n                Core.sounds.setVolume('superFreeSpinsBackgroundSound', 0);\n            }\n            if (Core.sounds.isPlaying('backgroundMusic')) {\n                Core.sounds.stop('backgroundMusic');\n            } else if (Core.sounds.isPlaying('backgroundNoPlay')) {\n                Core.sounds.stop('backgroundNoPlay');\n            }\n        } else if (this.slotConfiguration.videoExplosionSoundDelay > 0) {\n            Timers.setTimeout(() => {\n                this.playExplodeSound(context);\n            }, this.slotConfiguration.videoExplosionSoundDelay);\n        }\n        this.cascadeSubjects.SHOW_WINS.next(context.cascadeStep);\n\n        this.view.playVideos(context.cascadeStep, context.entries, specialVideos, false);\n    }\n\n    private actionPlayExpandVideos(context: VideosContextCascadeWays, event): void {\n        context.cascadeStep = event.cascadeStep;\n        context.mutations = this.rootStore.domainStore.betResponse.result.spins[event.cascadeStep].mutations;\n        if (context.mutations.length > 0) {\n            this.view.playExpandVideos(context.mutations);\n        }\n    }\n    private actionStartSpecialVideosExternally(context: VideosContextCascadeWays): void {\n        this.cascadeSubjects.PRE_NEW_CASCADE.next(this.rootStore.domainStore.betResponse.result.spins.length - 1);\n        const entries: EntryWays[] =\n            this.rootStore.domainStore.betResponse.result.spins[\n                this.rootStore.domainStore.betResponse.result.spins.length - 1\n            ].entries;\n        context.entries = entries;\n        const hasWin: boolean =\n            this.rootStore.domainStore.betResponse.result.spins[\n                this.rootStore.domainStore.betResponse.result.spins.length - 1\n            ].totalWinAmount > 0;\n        const videoType: string = hasWin && this.rootStore.isCascadeGreatWin ? 'triggerVideo' : 'video';\n        this.view.playVideos(\n            this.rootStore.domainStore.betResponse.result.spins.length - 1,\n            entries,\n            true,\n            true,\n            videoType,\n        );\n        this.cascadeSubjects.HIDE_CASCADE_CELLS_W_ALPHA.next(entries[0].cells);\n    }\n\n    private playSpecialVideosAgainExternally(context: VideosContextCascadeWays): void {\n        if (context.specialVideoLoop < this.slotConfiguration.specialSymbolVideosLoop) {\n            this.view.playVideosAgain(context.entries);\n        }\n    }\n\n    private actionPlayVideoAgain(context: VideosContextCascadeWays, _event): void {\n        context.mainAnimLoops++;\n\n        if (context.mainAnimLoops < this.slotConfiguration.cascadeVideosLoop) {\n            this.view.playVideosAgain(context.entries);\n        } else if (context.mainAnimLoops === this.slotConfiguration.cascadeVideosLoop) {\n            this.stateMachineService.send({ type: 'HIDING_MAIN_SYMBOL' });\n        }\n    }\n\n    private actionPlaySpecialVideoAgain(context: VideosContextCascadeWays, _event): void {\n        if (context.specialVideoLoop < this.slotConfiguration.specialSymbolVideosLoop) {\n            this.view.playVideosAgain(context.entries);\n        } else if (context.specialVideoLoop === this.slotConfiguration.specialSymbolVideosLoop) {\n            this.stateMachineService.send({ type: 'HIDING_MAIN_SYMBOL' });\n        }\n    }\n\n    private actionVideoExploded(context: VideosContextCascadeWays, _event): void {\n        context.mainAnimLoops++;\n        if (this.slotConfiguration.videoExplosionSoundDelay === 0) {\n            this.playExplodeSound(context);\n        }\n        this.stateMachineService.send({ type: 'CASCADE_COMPLETE' });\n        this.view.destroyVideos();\n    }\n\n    private playExplodeSound(context: VideosContextCascadeWays): void {\n        const hasWin: boolean =\n            this.rootStore.domainStore.betResponse.result.spins[context.cascadeStep].totalWinAmount > 0;\n        if (hasWin) {\n            this.cascadeSound++;\n            if (this.cascadeSound > 6) {\n                this.cascadeSound = 6;\n            }\n\n            const freespinRound = this.rootStore.domainStore.betResponse?.rounds?.find(\n                (round) => round.type === 'FREESPIN',\n            );\n            if (\n                freespinRound &&\n                freespinRound?.remain !== freespinRound?.count &&\n                freespinRound?.count > 0 &&\n                Core.sounds.hasSound('fgCascade' + this.cascadeSound)\n            ) {\n                Core.sounds.play('fgCascade' + this.cascadeSound);\n            } else {\n                Core.sounds.play('cascade' + this.cascadeSound);\n            }\n        }\n    }\n\n    private actionMainVideoHidden(context: VideosContextCascadeWays, _event): void {\n        context.mainAnimLoops = 0;\n    }\n\n    private actionComplete(_context: VideosContextCascadeWays, _event): void {\n        this.cascadeSubjects.CASCADE_VIDEO_ANIMATIONS_COMPLETE.next();\n    }\n    private actionResetVideoPlayerConfig(context: VideosContextCascadeWays, _event): void {\n        context.mainAnimLoops = 0;\n        this.view.destroyVideos();\n    }\n    private actionSpecialSymbolAnimCompleteWhenStartExternally(_context: VideosContextCascadeWays, _event): void {\n        this.cascadeSubjects.SPECIAL_SYMBOL_ANIM_COMPLETE_WHEN_START_EXTERNALLY.next();\n    }\n\n    private specialVideoShouldLoop(context: VideosContextCascadeWays, _event): boolean {\n        context.specialVideoLoop++;\n        return context.specialVideoLoop < this.slotConfiguration.specialSymbolVideosLoop;\n    }\n    // When three scatter symbols appear during free spins, we'll add 5 additional spins without triggering videos or sounds for scatter symbols.\n    // This is due to the server only confirming a bonus without providing detailed data in the spin's entries array.\n    // This approach may be revised if updates are made to the server's response. (ON-33286)\n\n    private findRetriggerSpin(betResponse: BetResponse): ISpin | null {\n        return (\n            betResponse.result.spins.find((spin: ISpin) => spin.bonuses.length > 0 && spin.entries.length === 0) || null\n        );\n    }\n\n    /**\n     * Get scatters positions from reels matrix\n     * @param reelsLayout   - reels matrix\n     * @returns  - array with scatter positions\n     */\n    private getScattersPositions(reelsLayout: number[][], scatterIndex: number): number[] {\n        return reelsLayout.reduce((positions, reel, row) => {\n            reel.forEach((symbolIndex, col) => {\n                if (symbolIndex === scatterIndex) {\n                    positions.push(row, col);\n                }\n            });\n            return positions;\n        }, []);\n    }\n}\n","export default class EntryWays {\n    public cells: number[];\n    public coef: number;\n    public mode: string;\n    public multiplier: number;\n    public occurs: number;\n    public symbol: number;\n    public win: number;\n    public winAmount: string;\n}\n","import Entry from './EntryWays';\n\nexport class VideosContextCascadeWays {\n    public cascadeStep: number;\n    public mainAnimLoops: number = 0;\n    public entries: Entry[];\n    public specialVideoLoop: number = 0;\n    public videoLoopsTo = 5;\n    public mutations: any[] = [];\n}\n","import { CascadeSubjects, ICascadeSlotConfiguration } from '@egt/cascade-slot';\nimport Core, { ISpineVideoPlayer } from '@egt/core';\nimport { RootStore } from '@egt/slot';\nimport { ViewContainer } from '@egt/ui-lib';\nimport { Sprite, Texture } from 'pixi.js';\nimport { Subscription } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport Entry from '../data/EntryWays';\nimport { IVideosFeatureConfigurationCascadeWays } from '../configuration/IVideosFeatureConfigurationCascadeWays';\n\n@injectable()\nexport default class VideosViewCascadeWays extends ViewContainer {\n    public stateMachineService;\n    public videoPlayers: ISpineVideoPlayer[] = [];\n    public videoOnPlayers: Map<number | string, ISpineVideoPlayer> = new Map<number | string, ISpineVideoPlayer>();\n    public videoOnSubscriptions: Map<string, Subscription> = new Map<string, Subscription>();\n    public isPlaying: boolean = false;\n    public registeredCells: any[] = [];\n\n    protected symbols: any[] = [];\n    private startVideosExternally: boolean = false;\n\n    private videoInstances: Array<{ roll: number; cell: number; videoInstance: Sprite }> = [];\n    private lastPlayedVideoSymbolId: number;\n\n    constructor(\n        @inject('ISlotConfiguration') protected config: ICascadeSlotConfiguration,\n        @inject('CascadeSubjects') protected cascadeSubjects: CascadeSubjects,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('VideosFeatureConfiguration')\n        protected featureConfig: IVideosFeatureConfigurationCascadeWays,\n    ) {\n        super();\n    }\n\n    public destroy(): void {\n        this.destroyVideos();\n        super.destroy.apply(this, arguments);\n    }\n\n    public destroyVideos(destroyCells: boolean = true): void {\n        Object.keys(this.videoPlayers).forEach((key) => {\n            Core.destroyVideoPlayer(this.videoPlayers[key]);\n            delete this.videoPlayers[key];\n        });\n\n        this.videoPlayers.length = 0;\n        this.symbols.length = 0;\n        if (destroyCells) {\n            this.registeredCells.length = 0;\n        }\n        this.removeChildren();\n\n        this.isPlaying = false;\n    }\n\n    public playVideos(\n        cascadeStep: number,\n        entries: Entry[],\n        specialVideos: boolean = false,\n        startExternally: boolean = false,\n        videoType?: string,\n    ): void {\n        this.startVideosExternally = startExternally;\n        const mutations = this.rootStore.domainStore.betResponse.result.spins[cascadeStep].mutations;\n        if (specialVideos && startExternally) {\n            Core.sounds.play('scatterWin');\n\n            if (Core.sounds.isPlaying('freeSpinsBackgroundSound')) {\n                Core.sounds.setVolume('freeSpinsBackgroundSound', 0);\n            }\n            if (Core.sounds.isPlaying('superFreeSpinsBackgroundSound')) {\n                Core.sounds.setVolume('superFreeSpinsBackgroundSound', 0);\n            }\n            if (Core.sounds.isPlaying('backgroundMusic')) {\n                Core.sounds.stop('backgroundMusic');\n            } else if (Core.sounds.isPlaying('backgroundNoPlay')) {\n                Core.sounds.stop('backgroundNoPlay');\n            }\n        }\n        this.createVideos(cascadeStep, entries, mutations, videoType);\n\n        this.sortableChildren = true;\n        Object.keys(this.videoPlayers).forEach((key) => {\n            this.videoPlayers[key].play();\n        });\n\n        this.children.forEach((child) => {\n            child.visible = true;\n        });\n\n        this.isPlaying = true;\n    }\n\n    public createVideos(cascadeStep: number, entries: Entry[], mutations?: any, videoType?: string): void {\n        if (!entries || entries?.length === 0) {\n            return;\n        }\n\n        const reels = this.rootStore.domainStore.betResponse.result.spins[cascadeStep].reels;\n\n        // Process regular entries\n        entries.forEach((entry: Entry) => {\n            for (let i = 0; i < entry.cells?.length; i += 2) {\n                const col: number = entry.cells[i];\n                const row: number = entry.cells[i + 1];\n\n                // Skip if this cell is in any mutation\n                const isInMutation = mutations?.some((mutation) => this.isCellInMutation(col, row, mutation));\n\n                if (isInMutation) continue;\n\n                const symbol: string = entry.symbol.toString();\n                this.lastPlayedVideoSymbolId = entry.symbol;\n\n                const reelLength =\n                    reels[col]?.length !== this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value\n                        ? reels[col]?.length\n                        : '';\n                const symbolSizeIndex = String(reelLength) + symbol;\n                this.createVideoBySymbol(symbolSizeIndex, col, row, videoType);\n            }\n        });\n    }\n\n    public playExpandVideos(mutations: any[]): void {\n        Core.sounds.play('wildWin');\n        if (mutations?.length) {\n            mutations.forEach((mutation) => {\n                if (!mutation.primes?.length || mutation.type !== 'expand') return;\n                this.cascadeSubjects.WILD_ANIMATION_PLAYING.next();\n                for (let i = 0; i < mutation.primes.length; i += 2) {\n                    const col = mutation.primes[i];\n                    const row = 0;\n                    const symbol = mutation.symbols?.[0]?.toString();\n\n                    if (symbol === undefined) continue;\n\n                    // Create video for mutation prime\n                    const symbolSizeIndex = symbol;\n                    this.createVideoBySymbol(symbolSizeIndex, col, row);\n                }\n            });\n        }\n    }\n\n    private isCellInMutation(col: number, row: number, mutation: any): boolean {\n        if (!mutation.primes?.length || mutation.type !== 'expand') return false;\n        // Check in cells\n        for (let k = 0; k < mutation.cells?.length; k += 2) {\n            if (mutation.cells[k] === col && mutation.cells[k + 1] === row) {\n                return true;\n            }\n        }\n        // Check in primes\n        for (let k = 0; k < mutation.primes?.length; k += 2) {\n            if (mutation.primes[k] === col && mutation.primes[k + 1] === row) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public createVideoBySymbol(\n        symbol: string,\n        col,\n        row,\n        videoType: string = 'video',\n        symbolSprite?: Sprite,\n        videoConfig?: any,\n    ): void {\n        const symbolConfig = videoConfig\n            ? videoConfig\n            : this.config.symbolsConfig.find((p) => p.index === Number(symbol));\n        let symbolVideoConfig;\n        let videoOn = false;\n        if (videoType === 'on') {\n            videoOn = true;\n            symbolVideoConfig = symbolConfig.videoOn;\n        } else if (videoType === 'triggerVideo') {\n            symbolVideoConfig = symbolConfig.triggerVideo;\n        } else {\n            symbolVideoConfig = symbolConfig.video;\n        }\n        if (symbolConfig.useReelSpecialEffectAnim && !videoOn) {\n            this.cascadeSubjects.SPECIAL_SCATTER_ANIM_PLAYING.next(true);\n        }\n        if (videoOn && !symbolVideoConfig) {\n            return;\n        }\n        this.createVideo(col, row, symbolConfig, videoOn, symbolSprite);\n        this.sortChildren();\n    }\n    protected createVideo(\n        col: number,\n        row: number,\n        symbolConfig: any,\n        videoOn,\n        videoCover?: Sprite,\n        handler?: () => void,\n    ): void {\n        let symbolVideoConfig = videoOn ? symbolConfig.videoOn : symbolConfig.video;\n        symbolVideoConfig = JSON.parse(JSON.stringify(symbolVideoConfig));\n        symbolVideoConfig.col = col;\n        symbolVideoConfig.row = row;\n        symbolVideoConfig.symbolId = symbolConfig.index;\n\n        const videoPlayer: ISpineVideoPlayer | undefined = this.getVideoPlayer(symbolVideoConfig, col, row, videoOn);\n\n        if (videoPlayer === undefined) {\n            return;\n        }\n\n        if (videoCover) {\n            if (!videoOn) {\n                this.registeredCells.push({\n                    vp: videoPlayer,\n                    instance: videoCover,\n                    col,\n                    row,\n                    symbol: symbolConfig.index,\n                });\n            }\n            videoPlayer.addInstance(videoCover, symbolVideoConfig, videoOn);\n        } else if (!this.isInstanceRegistered(col, row)) {\n            const symbolSprite: Sprite = this.createSymbolSprite(col, row, symbolConfig, undefined);\n            if (!videoOn) {\n                this.registeredCells.push({\n                    vp: videoPlayer,\n                    instance: symbolSprite,\n                    col,\n                    row,\n                    symbol: symbolConfig.index,\n                });\n            }\n\n            videoPlayer.addInstance(symbolSprite, symbolVideoConfig, videoOn);\n        }\n\n        if (handler) {\n            videoPlayer.addHandler(handler);\n        }\n\n        videoPlayer.play();\n    }\n\n    private createVideoPlayer(symbolVideoConfig: any): ISpineVideoPlayer | undefined {\n        // const symbolConfig = this.config.symbolsConfig.find((sym) => sym.index === symbolVideoConfig.symbolId);\n        let videoPlayer: ISpineVideoPlayer = this.videoPlayers[symbolVideoConfig.id];\n        if (videoPlayer) {\n            return videoPlayer;\n        }\n\n        videoPlayer = Core.createSpineVideoPlayer();\n        videoPlayer.createSpineAnimations(symbolVideoConfig);\n        if (this.startVideosExternally) {\n            videoPlayer.VIDEO_COMPLETE.pipe(takeUntil(this.DESTROY)).subscribe(\n                this.onSymbolAnimCompleteWhenStartExternally.bind(this, symbolVideoConfig.symbolId),\n            );\n        } else {\n            videoPlayer.VIDEO_COMPLETE.pipe(takeUntil(this.DESTROY)).subscribe(\n                this.onSymbolAnimComplete.bind(this, symbolVideoConfig.symbolId),\n            );\n        }\n\n        videoPlayer.config = symbolVideoConfig;\n\n        // biome-ignore lint/suspicious/noAssignInExpressions: <explanation>\n        return (this.videoPlayers[symbolVideoConfig.id] = videoPlayer);\n    }\n\n    private createVideoOnPlayer(symbolVideoConfig: any, col: number, row: number): ISpineVideoPlayer {\n        const videoPlayer: ISpineVideoPlayer = Core.createSpineVideoPlayer();\n        videoPlayer.createSpineAnimations(symbolVideoConfig);\n        videoPlayer.VIDEO_COMPLETE.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onSymbolOnAnimComplete.bind(this, col, row),\n        );\n        videoPlayer.config = symbolVideoConfig;\n        this.videoOnPlayers.set(col.toString() + row.toString() + '_on', videoPlayer);\n        return videoPlayer;\n    }\n\n    protected getVideoPlayer(\n        symbolVideoConfig: any,\n        col: number,\n        row: number,\n        videoOn: boolean,\n    ): ISpineVideoPlayer | undefined {\n        if (!videoOn) {\n            return this.createVideoPlayer(symbolVideoConfig);\n        } else {\n            return this.createVideoOnPlayer(symbolVideoConfig, col, row);\n        }\n    }\n\n    protected isInstanceRegistered(col: number, row: number): boolean {\n        for (const cell of this.registeredCells) {\n            if (cell?.col === col && cell?.row === row) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    protected createSymbolSprite(col: number, row: number, symbolConfig, texture?: Texture): Sprite {\n        const symbolSprite: Sprite = new Sprite();\n        if (texture) {\n            symbolSprite.texture = texture;\n            symbolSprite.visible = false;\n        }\n\n        symbolSprite.x =\n            (this.rootStore.subjects.REELS_POSITION.value.reelWidth +\n                this.rootStore.subjects.REELS_POSITION.value.reelSpacing) *\n                col +\n            this.rootStore.subjects.REELS_POSITION.value.reelWidth / 2;\n        const customOffset: number =\n            symbolConfig.video.height - this.rootStore.subjects.REELS_POSITION.value.symbolHeight;\n        symbolSprite.y =\n            (this.rootStore.subjects.REELS_POSITION.value.symbolHeight + customOffset) * row +\n            (this.rootStore.subjects.REELS_POSITION.value.symbolHeight + customOffset) / 2;\n\n        symbolSprite.anchor.set(0.5);\n        symbolSprite.scale.set(\n            this.rootStore.subjects.REELS_POSITION.value.symbolScale,\n            this.rootStore.subjects.REELS_POSITION.value.symbolScale,\n        );\n        this.addChild(symbolSprite);\n        this.symbols.push(symbolSprite);\n        if (symbolConfig.isWild || symbolConfig.isScatter) {\n            symbolSprite.zIndex = 100 + col + 1 + row;\n        } else {\n            symbolSprite.zIndex = col + 1 + row;\n        }\n        return symbolSprite;\n    }\n\n    public playOnVideos(roll, cell, symbol, videoInstance): void {\n        const symbolId: string = symbol.toString();\n        this.createVideoBySymbol(symbolId, roll, cell, 'on', videoInstance);\n    }\n\n    private destroyOnVideos(col: number, row: number): void {\n        const key = col.toString() + row.toString() + '_on';\n\n        // Get and destroy the video player\n        const player = this.videoOnPlayers.get(key);\n        if (player) {\n            player.stop();\n            Core.destroyVideoPlayer(player);\n            this.videoOnPlayers.delete(key);\n        }\n\n        // Remove from registeredCells\n        this.registeredCells = this.registeredCells.filter((cell) => !(cell.col === col && cell.row === row));\n    }\n\n    public removeOnVideosAnimationsIfNotFinished(_onAnimation: { reel; cell }): void {\n        // this.destroyOnVideos();\n    }\n\n    public playVideosAgain(_entries: Entry[]): void {\n        Object.keys(this.videoPlayers).forEach((key) => {\n            this.videoPlayers[key].play(true);\n        });\n    }\n\n    public orientationChanged(): void {\n        for (const video of this.videoInstances) {\n            video.videoInstance.x =\n                (this.rootStore.subjects.REELS_POSITION.value.symbolWidth +\n                    this.rootStore.subjects.REELS_POSITION.value.reelSpacing) *\n                    video.roll +\n                this.rootStore.subjects.REELS_POSITION.value.symbolWidth / 2;\n            video.videoInstance.y =\n                this.rootStore.subjects.REELS_POSITION.value.symbolHeight * video.cell +\n                this.rootStore.subjects.REELS_POSITION.value.symbolHeight / 2;\n            video.videoInstance.scale.set(\n                this.rootStore.getReelsScaleFactor(\n                    this.rootStore.subjects.REELS_POSITION.value.symbolResolution,\n                    this.rootStore.subjects.PORTRAIT_FIRST.value,\n                ),\n            );\n        }\n    }\n    private onSymbolAnimComplete(symbolID: number): void {\n        let symbolConfig = this.config.symbolsConfig.find((sym) => sym.index === symbolID);\n        if (symbolConfig.isExpandingWild) this.stateMachineService.send({ type: 'EXPAND_VIDEOS_COMPLETE' });\n        else {\n            if (symbolID >= 20 && symbolID < 100) {\n                symbolID %= 10;\n            } else {\n                symbolID %= 100;\n            }\n            // all symbol videos must be same size and need to dispatch complete only for one\n            symbolConfig = this.config.symbolsConfig.find((sym) => sym.index === symbolID);\n            if (this.lastPlayedVideoSymbolId === symbolID && !symbolConfig.isScatter) {\n                this.stateMachineService.send({ type: 'MAIN_VIDEO_COMPLETE' });\n            } else if (symbolConfig.isScatter) {\n                this.stateMachineService.send({ type: 'SPECIAL_VIDEOS_COMPLETE' });\n                if (symbolConfig.useReelSpecialEffectAnim)\n                    this.cascadeSubjects.SPECIAL_SCATTER_ANIM_PLAYING.next(false);\n            }\n        }\n    }\n\n    private onSymbolOnAnimComplete(col: number, row: number): void {\n        this.destroyOnVideos(col, row);\n        this.cascadeSubjects.SHOW_ON_SYMBOL_VIDEO_COMPLETE.next([col, row]);\n    }\n\n    private onSymbolAnimCompleteWhenStartExternally(): void {\n        this.stateMachineService.send({ type: 'SPECIAL_SYMBOL_ANIM_COMPLETE_WHEN_START_EXTERNALLY' });\n        this.destroyVideos();\n        this.cascadeSubjects.SHOW_ALL_CASCADE_SYMBOLS_W_ALPHA.next();\n    }\n}\n","import { BaseComponentConfiguration } from '@egt/core';\nimport { IVideosFeatureConfigurationCascade } from './IVideosFeatureConfigurationCascade';\n\nexport default class VideosFeatureConfigurationCascade extends BaseComponentConfiguration {}\n\nexport function VideosFeatureConfigurationFactoryCascade(): typeof VideosFeatureConfigurationCascade {\n    class VideosFeatureConfigurationInternalClass\n        extends VideosFeatureConfigurationCascade\n        implements IVideosFeatureConfigurationCascade {}\n    return VideosFeatureConfigurationInternalClass;\n}\n","import { CascadeSubjects, ICascadeSlotConfiguration } from '@egt/cascade-slot';\nimport Core, { BaseController, IVideoPlayer, Timers } from '@egt/core';\nimport { BetResponse, ISpin, ISpinEntry, LineMode, RootStore } from '@egt/slot';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { Machine, interpret } from 'xstate';\nimport { VideosContextCascade } from '../data/VideosContextCascade';\nimport Entry from '../data/EntryCascade';\nimport VideosViewCascade from '../views/VideosViewCascade';\n@injectable()\nexport default class VideosControllerCascade extends BaseController {\n    private stateMachine;\n    protected stateMachineService;\n    protected stateMachineInitObject: any;\n    protected stateMachineActions: any;\n    private cascadeSound: number = 0;\n\n    constructor(\n        @inject('VideosView') protected view: VideosViewCascade,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('CascadeSubjects') protected cascadeSubjects: CascadeSubjects,\n        @inject('ISlotConfiguration') protected slotConfiguration: ICascadeSlotConfiguration,\n    ) {\n        super(view);\n    }\n\n    public onGameStarted(): void {\n        this.intStateMachine();\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n        this.rootStore.subjects.BEFORE_SPIN.pipe(takeUntil(this.DESTROY)).subscribe(this.onCascadeComplete.bind(this));\n        this.cascadeSubjects.REMOVE_ON_ANIMATIONS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.removeOnAnimations.bind(this),\n        );\n        this.cascadeSubjects.NEW_CASCADE.pipe(takeUntil(this.DESTROY)).subscribe(this.onPlayVideos.bind(this));\n        this.cascadeSubjects.COMPLETE_ON_VIDEOS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.completeOnVideos.bind(this),\n        );\n        this.cascadeSubjects.SHOW_ON_SYMBOL_VIDEOS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onPlaySymbolOnVideos.bind(this),\n        );\n        this.cascadeSubjects.NO_CASCADE_VIDEOS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onPlaySpecialVideos.bind(this),\n        );\n        this.cascadeSubjects.PLAY_SPECIAL_VIDEOS_EXTERNALLY.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onStartSpecialVideosExternally.bind(this),\n        );\n        this.cascadeSubjects.SHOW_ALL_SYMBOLS.pipe(takeUntil(this.DESTROY)).subscribe(this.onShowAllSymbols.bind(this));\n        this.rootStore.domainStore.BET.pipe(takeUntil(this.DESTROY)).subscribe(this.addRetriggerSpinEntry.bind(this));\n        this.view.sortableChildren = true;\n    }\n\n    public destroy(): void {\n        if (this.stateMachineService) {\n            this.stateMachineService.stop();\n            this.stateMachineService = null;\n        }\n        this.onCascadeComplete();\n        this.view.destroyVideos();\n        super.destroy();\n    }\n\n    private setOrientation(): void {\n        this.view.x = this.rootStore.subjects.REELS_POSITION.value.reelX;\n        this.view.y = this.rootStore.subjects.REELS_POSITION.value.reelY;\n        this.view.orientationChanged();\n    }\n\n    protected intStateMachine(): void {\n        const actionPlayVideos = this.actionPlayVideos.bind(this);\n        const actionPlayVideoAgain = this.actionPlayVideoAgain.bind(this);\n        const actionPlaySpecialVideoAgain = this.actionPlaySpecialVideoAgain.bind(this);\n        const actionHideMinSymbolsAndShowExplosion = this.actionHideMinSymbolsAndShowExplosion.bind(this);\n        const actionMainVideoHidden = this.actionMainVideoHidden.bind(this);\n        const actionComplete = this.actionComplete.bind(this);\n        const actionResetVideoPlayerConfig = this.actionResetVideoPlayerConfig.bind(this);\n        const actionStartSpecialVideosExternally = this.actionStartSpecialVideosExternally.bind(this);\n        const actionSpecialSymbolAnimCompleteWhenStartExternally =\n            this.actionSpecialSymbolAnimCompleteWhenStartExternally.bind(this);\n        const playSpecialVideosAgainExternally = this.playSpecialVideosAgainExternally.bind(this);\n        const specialVideoShouldLoop = this.specialVideoShouldLoop.bind(this);\n        const isTriggeredVideo = this.isTriggeredVideo.bind(this);\n\n        this.stateMachineInitObject = {\n            id: 'cascadeVideoController',\n            context: new VideosContextCascade(),\n            initial: 'readyToStart',\n            states: {\n                readyToStart: {\n                    on: {\n                        PLAY_VIDEOS: { target: 'playVideos' },\n                        PLAY_SPECIAL_VIDEOS: { target: 'playSpecialVideo' },\n                        PLAY_SPECIAL_VIDEOS_EXTERNALLY: { target: 'playSpecialVideosFromExternalFeature' },\n                    },\n                },\n                playVideos: {\n                    entry: ['actionPlayVideos'],\n                    on: {\n                        MAIN_VIDEO_COMPLETE: { actions: 'actionPlayVideoAgain' },\n                        HIDING_MAIN_SYMBOL: { target: 'hideMineSymbolsAndShowExplosion' },\n                    },\n                },\n                playSpecialVideo: {\n                    entry: ['actionPlayVideos'],\n                    on: {\n                        SPECIAL_VIDEOS_COMPLETE: [\n                            { actions: 'actionPlaySpecialVideoAgain', cond: specialVideoShouldLoop },\n                            { actions: 'actionComplete', target: 'waitingToStartFeature', cond: isTriggeredVideo },\n                            { actions: ['actionComplete', 'actionResetVideoPlayerConfig'], target: 'readyToStart' },\n                        ],\n                    },\n                },\n                playSpecialVideosFromExternalFeature: {\n                    entry: ['actionStartSpecialVideosExternally'],\n                    on: {\n                        SPECIAL_SYMBOL_ANIM_COMPLETE_WHEN_START_EXTERNALLY: [\n                            { actions: 'playSpecialVideosAgainExternally', cond: specialVideoShouldLoop },\n                            {\n                                actions: [\n                                    'actionSpecialSymbolAnimCompleteWhenStartExternally',\n                                    'actionResetVideoPlayerConfig',\n                                ],\n                                target: 'readyToStart',\n                            },\n                        ],\n                    },\n                },\n                waitingToStartFeature: {\n                    on: {\n                        RESET_VIDEO_PLAYER_CONFIG: [\n                            { actions: 'actionResetVideoPlayerConfig', target: 'readyToStart' },\n                        ],\n                    },\n                },\n                hideMineSymbolsAndShowExplosion: {\n                    entry: ['actionHideMinSymbolsAndShowExplosion'],\n                    on: {\n                        MAIN_VIDEO_COMPLETE: { actions: 'actionPlayVideoAgain' },\n                        CASCADE_COMPLETE: {\n                            actions: ['actionComplete', 'actionMainVideoHidden'],\n                            target: 'readyToStart',\n                        },\n                    },\n                },\n            },\n        };\n\n        this.stateMachineActions = {\n            actions: {\n                actionPlayVideos,\n                actionPlayVideoAgain,\n                actionPlaySpecialVideoAgain,\n                playSpecialVideosAgainExternally,\n                actionHideMinSymbolsAndShowExplosion,\n                actionMainVideoHidden,\n                actionComplete,\n                actionResetVideoPlayerConfig,\n                actionStartSpecialVideosExternally,\n                actionSpecialSymbolAnimCompleteWhenStartExternally,\n                isTriggeredVideo,\n            },\n            guards: {\n                specialVideoShouldLoop,\n            },\n        };\n        this.createStatMachine();\n    }\n\n    protected createStatMachine(): void {\n        this.stateMachine = Machine(this.stateMachineInitObject, this.stateMachineActions);\n\n        this.stateMachineService = interpret(this.stateMachine, { devTools: Core.configuration.devTools }).start();\n        this.view.stateMachineService = this.stateMachineService;\n    }\n\n    /**\n     * adding non wining entries when non wining symbols explode with win of same type\n     */\n    protected replaceEntry(): void {\n        for (const [spinIndex, spin] of this.rootStore.domainStore.betResponse.result.spins.entries()) {\n            const reels = this.rootStore.domainStore.betResponse.result.spins[spinIndex].mutatedReels\n                ? this.rootStore.domainStore.betResponse.result.spins[spinIndex].mutatedReels\n                : this.rootStore.domainStore.betResponse.result.spins[spinIndex].reels;\n            for (const entry of spin.entries) {\n                const newWinningCells: number[] = [];\n                for (let i = 0; i < reels.length; i++) {\n                    for (let j = 0; j < reels[i].length; j++) {\n                        if (reels[i][j] === entry.symbol) {\n                            newWinningCells.push(i);\n                            newWinningCells.push(j);\n                        }\n                    }\n                }\n                entry.nonWinningCells = [];\n\n                for (let i = 0; i < newWinningCells.length; i += 2) {\n                    const col = newWinningCells[i];\n                    const row = newWinningCells[i + 1];\n\n                    let found = false;\n\n                    for (let j = 0; j < entry.cells.length; j += 2) {\n                        if (entry.cells[j] === col && entry.cells[j + 1] === row) {\n                            found = true;\n                            break;\n                        }\n                    }\n\n                    if (!found) {\n                        entry.nonWinningCells.push(col);\n                        entry.nonWinningCells.push(row);\n                    }\n                }\n            }\n        }\n    }\n\n    protected onCascadeComplete(): void {\n        this.cascadeSound = 0;\n        this.view.resetScatterSoundIndex();\n        this.view.destroyVideos();\n    }\n\n    private removeOnAnimations(onAnimation: { reel; cell }): void {\n        this.view.removeOnVideosAnimationsIfNotFinished(onAnimation);\n    }\n\n    private completeOnVideos(): void {\n        this.view.completeOnVideos();\n    }\n\n    protected onPlayVideos(cascadeStep: number): void {\n        if (this.rootStore.domainStore.betResponse.result.spins[cascadeStep].entries.length > 0) {\n            this.stateMachineService.send({ type: 'PLAY_VIDEOS', cascadeStep });\n        }\n    }\n    private onPlaySpecialVideos(cascadeStep: number): void {\n        this.stateMachineService.send({ type: 'PLAY_SPECIAL_VIDEOS', cascadeStep });\n    }\n\n    private onStartSpecialVideosExternally(): void {\n        this.stateMachineService.send({ type: 'PLAY_SPECIAL_VIDEOS_EXTERNALLY' });\n    }\n\n    private onShowAllSymbols(): void {\n        this.stateMachineService.send({ type: 'RESET_VIDEO_PLAYER_CONFIG' });\n    }\n\n    protected onPlaySymbolOnVideos(symbol): void {\n        this.view.playOnVideos(symbol[0], symbol[1], symbol[2], symbol[3]);\n    }\n\n    protected actionPlayVideos(context: VideosContextCascade, event): void {\n        let specialVideos: boolean = false;\n\n        context.specialVideoLoop = 0;\n        context.cascadeStep = event.cascadeStep;\n        context.entries = this.rootStore.domainStore.betResponse.result.spins[event.cascadeStep].entries;\n        const reels = this.rootStore.domainStore.betResponse.result.spins[event.cascadeStep].reels;\n\n        if (event.type === 'PLAY_SPECIAL_VIDEOS') {\n            specialVideos = true;\n        } else if (this.slotConfiguration.videoExplosionSoundDelay > 0) {\n            Timers.setTimeout(() => {\n                this.playExplodeSound(context);\n            }, this.slotConfiguration.videoExplosionSoundDelay);\n        }\n        this.cascadeSubjects.SHOW_WINS.next(context.cascadeStep);\n        this.view.playVideos(context.entries, reels, specialVideos);\n    }\n\n    protected actionStartSpecialVideosExternally(context: VideosContextCascade): void {\n        context.specialVideoLoop = 0;\n        const lastSpinIndex = this.rootStore.domainStore.betResponse.result.spins.length - 1;\n        this.cascadeSubjects.PRE_NEW_CASCADE.next(lastSpinIndex);\n        const entries: Entry[] = this.rootStore.domainStore.betResponse.result.spins[lastSpinIndex].entries;\n\n        if (!entries || entries.length === 0) {\n            context.entries = [];\n            context.specialVideoLoop = this.slotConfiguration.specialSymbolVideosLoop;\n            this.stateMachineService.send({ type: 'SPECIAL_SYMBOL_ANIM_COMPLETE_WHEN_START_EXTERNALLY' });\n            return;\n        }\n\n        const reels: number[][] = this.rootStore.domainStore.betResponse.result.spins[lastSpinIndex].reels;\n        context.entries = entries;\n        this.cascadeSubjects.SHOW_ALL_CASCADE_SYMBOLS_W_ALPHA.next();\n        this.cascadeSubjects.SHOW_ALL_SYMBOLS.next();\n\n        this.cascadeSubjects.HIDE_CASCADE_CELLS_W_ALPHA.next(entries[0].cells);\n        this.view.playVideos(entries, reels, true, true);\n    }\n\n    private actionPlayVideoAgain(context: VideosContextCascade, _event): void {\n        context.mainAnimLoops++;\n\n        if (context.mainAnimLoops < this.slotConfiguration.cascadeVideosLoop) {\n            this.view.playVideosAgain(context.entries);\n        } else if (context.mainAnimLoops === this.slotConfiguration.cascadeVideosLoop) {\n            this.stateMachineService.send({ type: 'HIDING_MAIN_SYMBOL' });\n        }\n    }\n    private playSpecialVideosAgainExternally(context: VideosContextCascade): void {\n        if (context.specialVideoLoop < this.slotConfiguration.specialSymbolVideosLoop) {\n            this.view.playVideosAgain(context.entries);\n        }\n    }\n\n    private actionPlaySpecialVideoAgain(context: VideosContextCascade, _event): void {\n        if (context.specialVideoLoop < this.slotConfiguration.specialSymbolVideosLoop) {\n            this.view.playVideosAgain(context.entries);\n        } else if (context.specialVideoLoop === this.slotConfiguration.specialSymbolVideosLoop) {\n            this.stateMachineService.send({ type: 'HIDING_MAIN_SYMBOL' });\n        }\n    }\n\n    private actionHideMinSymbolsAndShowExplosion(context: VideosContextCascade, _event): void {\n        context.mainAnimLoops++;\n        for (const entry of context.entries) {\n            const videoPlayer = this.view.videoPlayers.get(entry.symbol) as IVideoPlayer;\n            this.view.showExplosionVideo(videoPlayer);\n            this.view.hideSymbolsWhenExplosionStart(videoPlayer);\n            videoPlayer.gotoAndPlay(0);\n        }\n        if (this.slotConfiguration.videoExplosionSoundDelay === 0) {\n            this.playExplodeSound(context);\n        }\n        // this.cascadeSubjects.SHOW_WINS.next(context.cascadeStep);\n    }\n\n    protected playExplodeSound(context: VideosContextCascade): void {\n        const hasWin: boolean =\n            this.rootStore.domainStore.betResponse.result.spins[context.cascadeStep].totalWinAmount > 0;\n        if (hasWin) {\n            this.cascadeSound++;\n            if (this.cascadeSound > this.slotConfiguration.cascadeSoundCount) {\n                this.cascadeSound = this.slotConfiguration.cascadeSoundCount;\n            }\n\n            const freespinRound = this.rootStore.domainStore.betResponse?.rounds?.find(\n                (round) => round.type === 'FREESPIN',\n            );\n            if (\n                freespinRound &&\n                freespinRound?.remain !== freespinRound?.count &&\n                freespinRound?.count > 0 &&\n                Core.sounds.hasSound('fgCascade' + this.cascadeSound)\n            ) {\n                Core.sounds.play('fgCascade' + this.cascadeSound);\n            } else {\n                Core.sounds.play('cascade' + this.cascadeSound);\n            }\n        }\n    }\n\n    private actionMainVideoHidden(context: VideosContextCascade, _event): void {\n        for (const entry of context.entries) {\n            (this.view.videoPlayers.get(entry.symbol) as IVideoPlayer)?.stop();\n        }\n        context.mainAnimLoops = 0;\n    }\n\n    private actionComplete(context: VideosContextCascade, event): void {\n        this.cascadeSubjects.CASCADE_VIDEO_ANIMATIONS_COMPLETE.next();\n        if (event.type === 'SPECIAL_VIDEOS_COMPLETE') {\n            this.view.loopSpecialVideosWhenComplete(context.entries);\n            this.cascadeSubjects.SHOW_ALL_CASCADE_SYMBOLS_W_ALPHA.next();\n        } else {\n            this.view.destroyVideos();\n        }\n    }\n\n    private actionResetVideoPlayerConfig(context: VideosContextCascade, _event): void {\n        context.mainAnimLoops = 0;\n        this.view.resetSpecialVideoPlayersConfig(context.entries);\n        this.view.destroyVideos();\n    }\n\n    protected actionSpecialSymbolAnimCompleteWhenStartExternally(_context: VideosContextCascade, _event): void {\n        this.cascadeSubjects.SPECIAL_SYMBOL_ANIM_COMPLETE_WHEN_START_EXTERNALLY.next();\n        this.cascadeSubjects.SHOW_ALL_CASCADE_SYMBOLS_W_ALPHA.next();\n        this.view.destroyVideos();\n    }\n\n    private specialVideoShouldLoop(context: VideosContextCascade, event): boolean {\n        if (\n            event.type === 'SPECIAL_VIDEOS_COMPLETE' &&\n            this.slotConfiguration.symbolsConfig[context.entries[0].symbol].triggerVideo &&\n            this.rootStore.isCascadeGreatWin\n        ) {\n            return false;\n        }\n        context.specialVideoLoop++;\n        return (\n            context.specialVideoLoop < this.slotConfiguration.specialSymbolVideosLoop\n            // && this.slotConfiguration.cascadeVideosLoop > 1\n        );\n    }\n\n    private isTriggeredVideo(context: VideosContextCascade, _event): boolean {\n        return this.slotConfiguration.symbolsConfig[context.entries[0].symbol].video.isTriggerAnimation;\n    }\n\n    // When three scatter symbols appear during free spins, we'll add 5 additional spins without triggering videos or sounds for scatter symbols.\n    // This is due to the server only confirming a bonus without providing detailed data in the spin's entries array.\n    // This approach may be revised if updates are made to the server's response. (ON-33286)\n    protected addRetriggerSpinEntry(betResponse: BetResponse): void {\n        if (this.slotConfiguration.nonWinningSymbolExplode) {\n            this.replaceEntry();\n        }\n\n        const retriggerSpin = this.findRetriggerSpin(betResponse);\n        if (retriggerSpin === null) {\n            return;\n        }\n        const scatterIndex: number = this.slotConfiguration.scattersConfig[0].index;\n        const reelsLayout: number[][] = retriggerSpin.reels;\n        const scattersPositions = this.getScattersPositions(reelsLayout, scatterIndex);\n\n        const entry: ISpinEntry = {\n            cells: scattersPositions,\n            coef: 0,\n            mode: LineMode.SCATTER,\n            multiplier: 0,\n            occurs: scattersPositions.length / 2, // row and col pairs for each scatter\n            symbol: scatterIndex,\n            win: 0,\n            winAmount: '0',\n        };\n        retriggerSpin.entries.push(entry);\n    }\n\n    protected findRetriggerSpin(betResponse: BetResponse): ISpin | null {\n        return (\n            betResponse.result.spins.find((spin: ISpin) => spin.bonuses.length > 0 && spin.entries.length === 0) || null\n        );\n    }\n\n    /**\n     * Get scatters positions from reels matrix\n     * @param reelsLayout   - reels matrix\n     * @returns  - array with scatter positions\n     */\n    protected getScattersPositions(reelsLayout: number[][], scatterIndex: number): number[] {\n        return reelsLayout.reduce((positions, reel, row) => {\n            reel.forEach((symbolIndex, col) => {\n                if (symbolIndex === scatterIndex) {\n                    positions.push(row, col);\n                }\n            });\n            return positions;\n        }, []);\n    }\n}\n","export default class EntryCascade {\n    public cells: number[];\n    public nonWinningCells: number[];\n    public coef: number;\n    public mode: string;\n    public multiplier: number;\n    public occurs: number;\n    public symbol: number;\n    public win: number;\n    public winAmount: string;\n}\n","import Entry from './EntryCascade';\n\nexport class VideosContextCascade {\n    public cascadeStep: number;\n    public mainAnimLoops: number = 0;\n    public entries: Entry[];\n    public specialVideoLoop: number = 0;\n    public videoLoopsTo = 5;\n}\n","import { CascadeSubjects, ICascadeSlotConfiguration } from '@egt/cascade-slot';\nimport Core, { Timers, IVideoPlayer } from '@egt/core';\nimport { RootStore, ZOrders } from '@egt/slot';\nimport { ViewContainer } from '@egt/ui-lib';\nimport { gsap } from 'gsap';\nimport { Sprite } from 'pixi.js';\nimport { Subject, Subscription, merge } from 'rxjs';\nimport { take, takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport Entry from '../data/EntryCascade';\n\n@injectable()\nexport default class VideosViewCascade extends ViewContainer {\n    public stateMachineService;\n    public videoPlayers: Map<number | string, IVideoPlayer> = new Map<number | string, IVideoPlayer>();\n    public videoOnPlayers: Map<number | string, IVideoPlayer> = new Map<number | string, IVideoPlayer>();\n    public videoOnSubscriptions: Map<string, Subscription> = new Map<string, Subscription>();\n    private explosionsVideoPlayer: IVideoPlayer;\n    private videoInstances: Array<{ roll: number; cell: number; videoInstance: Sprite }> = [];\n    protected lastPlayedVideoSymbolId: number;\n    protected videoComplete = new Subject();\n\n    protected scatterSoundIndex: number = 3;\n\n    constructor(\n        @inject('ISlotConfiguration') protected config: ICascadeSlotConfiguration,\n        @inject('CascadeSubjects') protected cascadeSubjects: CascadeSubjects,\n        @inject('RootStore') protected rootStore: RootStore,\n    ) {\n        super();\n    }\n\n    public playVideos(\n        entries: Entry[],\n        reels: number[][],\n        specialVideos: boolean = false,\n        startExternally: boolean = false,\n    ): void {\n        if (specialVideos) {\n            this.zIndex = ZOrders.VIDEOS_LEVEL;\n        } else {\n            this.zIndex = ZOrders.REELS_LEVEL - 1;\n        }\n\n        for (const entry of entries) {\n            this.lastPlayedVideoSymbolId = entry.symbol;\n            const videoPlayer = this.createVideoPlayer(entry, startExternally, specialVideos);\n            let wildVideoPlayer: IVideoPlayer | null = null;\n            if (videoPlayer) {\n                for (let i: number = 0; i < entry.cells.length; i += 2) {\n                    const roll: number = entry.cells[i];\n                    const cell: number = entry.cells[i + 1];\n\n                    const reelSymbol = reels[roll][cell];\n                    const entrySymbol = entry.symbol;\n                    // The wild symbol has a different index than the winning symbol\n                    // but it would be included in the winning cells\n                    // since it substitutes for all symbols except scatters\n                    // Therefore, we need to create a wild animation and play it\n                    // in sync with the winning symbols from the cascade.\n                    if (reelSymbol !== entrySymbol) {\n                        wildVideoPlayer = this.createWildVideoPlayer(reelSymbol, roll, cell);\n                    } else {\n                        this.addVideoInstances(entry.symbol, roll, cell);\n                    }\n                }\n\n                if (wildVideoPlayer) {\n                    wildVideoPlayer?.play();\n                    wildVideoPlayer.instances[entry.symbol]?.scale.set(\n                        this.rootStore.getReelsScaleFactor(\n                            this.rootStore.subjects.REELS_POSITION.value.symbolResolution,\n                            this.rootStore.subjects.PORTRAIT_FIRST.value,\n                        ),\n                    );\n                }\n\n                const player = this.videoPlayers.get(entry.symbol) as IVideoPlayer;\n                if (this.config.nonWinningSymbolExplode) {\n                    videoPlayer.VIDEO_ON_SPECIFIC_FRAME.pipe(take(1)).subscribe(() => {\n                        for (let t: number = 0; t < entry.nonWinningCells.length; t += 2) {\n                            const roll: number = entry.nonWinningCells[t];\n                            const cell: number = entry.nonWinningCells[t + 1];\n                            this.addVideoInstances(reels[roll][cell], roll, cell);\n                        }\n                        Timers.setTimeout(() => {\n                            this.cascadeSubjects.ON_HIDE_NON_WINNING_SYMBOLS_WHEN_WIN.next(entry.nonWinningCells);\n                        }, 100);\n                    });\n                }\n                player.instances[entry.symbol]?.scale.set(\n                    this.rootStore.getReelsScaleFactor(\n                        this.rootStore.subjects.REELS_POSITION.value.symbolResolution,\n                        this.rootStore.subjects.PORTRAIT_FIRST.value,\n                    ),\n                );\n\n                player.play();\n                //TO DO refactor this sorting to work correct for all game use configuration how to sort special symbols use same ordering on all places\n                if (specialVideos) {\n                    let instanceZIndex = 0;\n                    // revers special symbols zIndex\n                    for (let i: number = this.children.length; i > 0; i--) {\n                        this.children[i - 1].zIndex = instanceZIndex;\n                        instanceZIndex++;\n                    }\n                    this.sortChildren();\n                }\n            }\n        }\n    }\n\n    public playOnVideos(roll, cell, symbol, videoInstance): void {\n        if (!this.config.symbolsConfig[symbol]?.videoOn) {\n            return;\n        }\n        const entry: Entry = new Entry();\n        entry.symbol = symbol;\n        if (this.config.symbolsConfig[symbol].isScatter) {\n            this.cascadeSubjects.SCATTER_STOPPING.next(roll);\n        }\n        if (this.cascadeSubjects.REEL_ANTICIPATION_PLAYING.value && !this.rootStore.subjects.REELS_FORCE_STOP.value) {\n            this.playAnticipationSpecialSymbolSounds(symbol);\n        }\n\n        entry.cells = [roll, cell];\n        this.createVideoPlayerOn(entry);\n        const player = this.videoOnPlayers.get(roll.toString() + cell.toString() + '_on') as IVideoPlayer;\n        player.addInstance(videoInstance);\n        const subscription = player.VIDEO_COMPLETE.subscribe(() => {\n            if (this.videoOnPlayers.has(roll.toString() + cell.toString() + '_on')) {\n                const innerPlayer = this.videoOnPlayers.get(roll.toString() + cell.toString() + '_on') as IVideoPlayer;\n                innerPlayer.stop();\n                Core.destroyVideoPlayer(innerPlayer);\n                subscription.unsubscribe();\n                this.videoOnPlayers.delete(roll.toString() + cell.toString() + '_on');\n                this.cascadeSubjects.SHOW_ON_SYMBOL_VIDEO_COMPLETE.next([roll, cell, symbol]);\n\n                if (\n                    this.config.symbolsConfig[symbol].isScatter &&\n                    this.rootStore.subjects.REELS_FORCE_STOP.value &&\n                    !this.rootStore.domainStore.betResponse.stateWinAmount\n                ) {\n                    this.cascadeSubjects.SCATTER_ON_ANIMATION_VIDEO_COMPLETE.next();\n                }\n            }\n        });\n        this.videoOnSubscriptions.set(roll.toString() + cell.toString() + '_on', subscription);\n        player.gotoAndPlay(0);\n    }\n\n    public completeOnVideos(): void {\n        this.videoOnPlayers.forEach((vp) => {\n            vp.VIDEO_COMPLETE.next();\n        });\n    }\n\n    public destroyVideos(): void {\n        this.removeChildren().forEach((child) => child.destroy({ children: true }));\n        this.videoPlayers.forEach((vp) => {\n            Core.destroyVideoPlayer(vp);\n            // @ts-ignore\n            vp = null;\n        });\n        this.videoPlayers.clear();\n        this.videoOnPlayers.forEach((vp) => {\n            Core.destroyVideoPlayer(vp);\n            // @ts-ignore\n            vp = null;\n        });\n        this.videoOnPlayers.clear();\n        this.videoOnSubscriptions.clear();\n        this.videoInstances = [];\n    }\n\n    public removeOnVideosAnimationsIfNotFinished(onAnimation: { reel; cell }): void {\n        if (this.videoOnPlayers.has(onAnimation.reel.toString() + onAnimation.cell.toString() + '_on')) {\n            // this.cascadeSubjects.SHOW_ON_SYMBOL_VIDEO_COMPLETE.next([videoOn.reel, videoOn.cell]);\n            const player = this.videoOnPlayers.get(\n                onAnimation.reel.toString() + onAnimation.cell.toString() + '_on',\n            ) as IVideoPlayer;\n\n            const subscription = this.videoOnSubscriptions.get(\n                onAnimation.reel.toString() + onAnimation.cell.toString() + '_on',\n            ) as Subscription;\n            player.stop();\n            Core.destroyVideoPlayer(player);\n            // @ts-ignore\n            player = null;\n            subscription.unsubscribe();\n\n            this.videoOnPlayers.delete(onAnimation.reel.toString() + onAnimation.cell.toString() + '_on');\n            this.videoOnSubscriptions.delete(onAnimation.reel.toString() + onAnimation.cell.toString() + '_on');\n        }\n    }\n\n    public showExplosionVideo(videoPlayer: IVideoPlayer): void {\n        const videoConfig = this.config.videoConfigs[1];\n\n        if (!this.explosionsVideoPlayer) {\n            this.explosionsVideoPlayer = Core.createVideoPlayer();\n            this.explosionsVideoPlayer.VIDEO_COMPLETE.pipe(takeUntil(this.DESTROY)).subscribe(\n                this.explosionComplete.bind(this),\n            );\n        }\n        this.explosionsVideoPlayer.config = videoConfig;\n        if (!Core.assets.getAsset('explosion')) {\n            this.explosionComplete();\n            return;\n        }\n        const videoTexture = Core.assets.getAnimationAssets('explosion', 'explosion_');\n\n        this.explosionsVideoPlayer.frames = Object.keys(videoTexture).map((personNamedIndex) => {\n            return videoTexture[personNamedIndex];\n        });\n\n        this.explosionsVideoPlayer.play();\n        for (const videoInstance of videoPlayer.getAllInstances()) {\n            const explosionInstance: Sprite = new Sprite();\n            explosionInstance.x = videoInstance.x;\n            explosionInstance.y = videoInstance.y;\n            explosionInstance.anchor.set(0.5);\n            explosionInstance.scale.set(videoInstance.scale.x);\n            this.addChild(explosionInstance);\n            this.explosionsVideoPlayer.addInstance(explosionInstance);\n        }\n    }\n\n    public hideSymbolsWhenExplosionStart(videoPlayer: IVideoPlayer): void {\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/features/slot/videos/src/egt/modes/cascade/views/VideosViewCascade.ts:230:9\",null]), gsap.to(videoPlayer.getAllInstances(), {\n            duration: 0.25,\n            alpha: 0,\n            ease: 'none',\n        }));\n    }\n\n    public playVideosAgain(entries: Entry[]): void {\n        for (const entry of entries) {\n            (this.videoPlayers.get(entry.symbol) as IVideoPlayer).gotoAndPlay(0);\n        }\n    }\n\n    public loopSpecialVideosWhenComplete(entries: Entry[]): void {\n        for (const entry of entries) {\n            if (this.videoPlayers.has(entry.symbol)) {\n                (this.videoPlayers.get(entry.symbol) as IVideoPlayer).config.loop = true;\n                (this.videoPlayers.get(entry.symbol) as IVideoPlayer).gotoAndPlay(0);\n            }\n        }\n    }\n\n    public resetSpecialVideoPlayersConfig(entries: Entry[]): void {\n        for (const entry of entries) {\n            const symbolVideoPlayer: IVideoPlayer = this.videoPlayers.get(entry.symbol) as IVideoPlayer;\n            if (symbolVideoPlayer) {\n                symbolVideoPlayer.config.loop = false;\n            }\n        }\n    }\n\n    public orientationChanged(): void {\n        for (const video of this.videoInstances) {\n            video.videoInstance.x =\n                (this.rootStore.subjects.REELS_POSITION.value.symbolWidth +\n                    this.rootStore.subjects.REELS_POSITION.value.reelSpacing) *\n                    video.roll +\n                this.rootStore.subjects.REELS_POSITION.value.symbolWidth / 2;\n            video.videoInstance.y =\n                this.rootStore.subjects.REELS_POSITION.value.symbolHeight * video.cell +\n                this.rootStore.subjects.REELS_POSITION.value.symbolHeight / 2;\n            video.videoInstance.scale.set(\n                this.rootStore.getReelsScaleFactor(\n                    this.rootStore.subjects.REELS_POSITION.value.symbolResolution,\n                    this.rootStore.subjects.PORTRAIT_FIRST.value,\n                ),\n            );\n        }\n    }\n\n    protected createVideoPlayer(\n        entry: Entry,\n        startExternally: boolean,\n        specialVideos: boolean = false,\n        scatterWinSound: string = 'scatterWin', // for TNTjSlot we need different scatterWin sound for retrigger\n    ): IVideoPlayer | null {\n        this.videoComplete.next();\n\n        const symbolConfig = this.config.symbolsConfig[entry.symbol];\n        let videoConfig = symbolConfig.video;\n        let extension: string = '';\n\n        const willPlayTrigger =\n            (startExternally && symbolConfig.triggerVideo) ||\n            (!startExternally &&\n                symbolConfig.triggerVideo &&\n                symbolConfig.scatterPay &&\n                !this.rootStore.isCascadeGreatWin);\n\n        if (symbolConfig.isScatter && (willPlayTrigger || (!symbolConfig.triggerVideo && specialVideos))) {\n            if (Core.sounds.isPlaying('freeSpinsBackgroundSound')) {\n                Core.sounds.setVolume('freeSpinsBackgroundSound', 0);\n            }\n            if (Core.sounds.isPlaying('superFreeSpinsBackgroundSound')) {\n                Core.sounds.setVolume('superFreeSpinsBackgroundSound', 0);\n            }\n            if (Core.sounds.isPlaying('megaFreeSpinsBackgroundSound')) {\n                Core.sounds.setVolume('megaFreeSpinsBackgroundSound', 0);\n            }\n            if (Core.sounds.isPlaying('backgroundMusic')) {\n                Core.sounds.stop('backgroundMusic');\n            } else if (Core.sounds.isPlaying('backgroundNoPlay')) {\n                Core.sounds.stop('backgroundNoPlay');\n            }\n        }\n\n        if (willPlayTrigger) {\n            videoConfig = symbolConfig.triggerVideo;\n            extension = 'Trigger';\n            this.cascadeSubjects.PLAY_SCATTER_TRIGGER_ANIM.next();\n            const bonusGameType: string = this.rootStore.domainStore.betResponse?.gameState?.bet?.gameMode;\n            let soundToPlaySuffix: string = '';\n\n            if (bonusGameType) {\n                if (bonusGameType === 'SUPER_BUY_BONUS') {\n                    soundToPlaySuffix = 'SFS';\n                } else if (bonusGameType === 'MEGA_BUY_BONUS') {\n                    soundToPlaySuffix = 'MFS';\n                }\n            }\n\n            const soundToPlay: string = Core.sounds.hasSound('scatterTrigger' + soundToPlaySuffix)\n                ? 'scatterTrigger' + soundToPlaySuffix\n                : 'scatterTrigger';\n\n            if (!Core.sounds.isPlaying(soundToPlay)) {\n                Core.sounds.play(soundToPlay);\n            }\n        } else if (symbolConfig.isScatter && !Core.sounds.isPlaying(scatterWinSound)) {\n            Core.sounds.play(scatterWinSound);\n        }\n\n        const videoPlayer = Core.createVideoPlayer();\n        videoPlayer.config = videoConfig;\n        const videoTexture = Core.assets.getAnimationAssets(\n            this.config.symbolsConfig[entry.symbol].name + extension,\n            '',\n        );\n        // const scale = this.config.symbolScale;\n\n        videoPlayer.frames = Object.keys(videoTexture).map((personNamedIndex) => {\n            return videoTexture[personNamedIndex];\n        });\n        const sub = merge(this.DESTROY, this.videoComplete);\n        if (startExternally) {\n            videoPlayer.VIDEO_COMPLETE.pipe(takeUntil(sub)).subscribe(\n                this.onSymbolAnimCompleteWhenStartExternally.bind(this, entry.symbol),\n            );\n        } else {\n            videoPlayer.VIDEO_COMPLETE.pipe(takeUntil(sub)).subscribe(\n                this.onSymbolAnimComplete.bind(this, entry.symbol),\n            );\n        }\n\n        this.videoPlayers.set(entry.symbol, videoPlayer);\n        return videoPlayer;\n    }\n\n    protected createWildVideoPlayer(symbolIndex: number, reel: number, cell: number): IVideoPlayer | null {\n        const wildConfig = this.config.symbolsConfig.find((symbol) => symbol.isWild);\n        if (!wildConfig || symbolIndex !== wildConfig.index) return null;\n\n        if (this.videoPlayers.has(symbolIndex)) {\n            this.addVideoInstances(wildConfig.index, reel, cell);\n            return this.videoPlayers.get(symbolIndex) as IVideoPlayer;\n        }\n        const player = Core.createVideoPlayer();\n        player.config = wildConfig.video;\n        const textures = Core.assets.getAnimationAssets(wildConfig.video.id, '');\n        player.frames = Object.keys(textures).map((personNamedIndex) => {\n            return textures[personNamedIndex];\n        });\n        this.videoPlayers.set(wildConfig.index, player);\n        this.addVideoInstances(wildConfig.index, reel, cell);\n        return player;\n    }\n\n    protected createVideoPlayerOn(entry: Entry): void {\n        // if (this.videoPlayers.has(entry.symbol + '_on')) {\n        //     return this.videoPlayers.get(entry.symbol) as IVideoPlayer;\n        // }\n\n        const videoConfig = this.config.symbolsConfig[entry.symbol].videoOn;\n        const videoPlayer = Core.createVideoPlayer();\n        videoPlayer.config = videoConfig;\n        const videoTexture = Core.assets.getAnimationAssets(this.config.symbolsConfig[entry.symbol].name + 'On', '');\n\n        videoPlayer.frames = Object.keys(videoTexture).map((personNamedIndex) => {\n            return videoTexture[personNamedIndex];\n        });\n\n        this.videoOnPlayers.set(entry.cells[0].toString() + entry.cells[1].toString() + '_on', videoPlayer);\n    }\n\n    protected onSymbolAnimCompleteWhenStartExternally(): void {\n        this.stateMachineService.send({ type: 'SPECIAL_SYMBOL_ANIM_COMPLETE_WHEN_START_EXTERNALLY' });\n    }\n\n    protected onSymbolAnimComplete(symbolID: number): void {\n        // all symbol videos must be same size and need to dispatch complete only for one\n        if (this.lastPlayedVideoSymbolId === symbolID && !this.config.symbolsConfig[symbolID].isScatter) {\n            this.stateMachineService.send({ type: 'MAIN_VIDEO_COMPLETE' });\n        } else if (this.config.symbolsConfig[symbolID].isScatter) {\n            this.stateMachineService.send({ type: 'SPECIAL_VIDEOS_COMPLETE' });\n        }\n    }\n\n    private explosionComplete(): void {\n        for (const videoInstance of this.explosionsVideoPlayer.getAllInstances()) {\n            this.removeChild(videoInstance).destroy({ children: true });\n        }\n        this.explosionsVideoPlayer.removeAllInstances();\n        this.explosionsVideoPlayer.stop();\n        Core.destroyVideoPlayer(this.explosionsVideoPlayer);\n        // @ts-ignore\n        this.explosionsVideoPlayer = null;\n        this.stateMachineService.send({ type: 'CASCADE_COMPLETE' });\n        this.videoComplete.next();\n    }\n\n    protected addVideoInstances(symbolId: number, roll: number, cell: number): void {\n        const videoInstance: Sprite = new Sprite();\n        videoInstance.anchor.set(0.5);\n        videoInstance.scale.set(\n            this.rootStore.getReelsScaleFactor(\n                this.rootStore.subjects.REELS_POSITION.value.symbolResolution,\n                this.rootStore.subjects.PORTRAIT_FIRST.value,\n            ),\n        );\n        videoInstance.x =\n            (this.rootStore.subjects.REELS_POSITION.value.symbolWidth +\n                this.rootStore.subjects.REELS_POSITION.value.reelSpacing) *\n                roll +\n            this.rootStore.subjects.REELS_POSITION.value.symbolWidth / 2;\n        videoInstance.y =\n            this.rootStore.subjects.REELS_POSITION.value.symbolHeight * cell +\n            this.rootStore.subjects.REELS_POSITION.value.symbolHeight / 2;\n        this.addChild(videoInstance);\n        videoInstance.zIndex = roll + cell;\n        const player = this.videoPlayers.get(symbolId) as IVideoPlayer;\n        player.addInstance(videoInstance);\n        this.videoInstances.push({ roll, cell, videoInstance });\n    }\n\n    protected playAnticipationSpecialSymbolSounds(symbol: number): void {\n        const symbolConfig = this.config.symbolsConfig[symbol];\n        if (symbolConfig.isScatter) {\n            Core.sounds.play(`stopScatter${this.scatterSoundIndex}`);\n            this.cascadeSubjects.SCATTER_STOP_SOUND_ON_ANTICIPATION_PLAYED.next(this.scatterSoundIndex - 2);\n            this.scatterSoundIndex++;\n        }\n        if (symbolConfig.isWild) {\n            Core.sounds.play('stopWild');\n        }\n        if (symbolConfig.isActivator) {\n            Core.sounds.play('stopActivator');\n        }\n    }\n\n    public resetScatterSoundIndex(): void {\n        this.scatterSoundIndex = 3;\n    }\n\n    // private addVideoOnInstances(entry: Entry, roll: number, cell: number): Sprite {\n    //     const videoInstance: Sprite = new Sprite();\n    //     videoInstance.anchor.set(0.5);\n    //     videoInstance.scale.set(this.config.symbolScale);\n    //     videoInstance.x = this.config.symbolWidth * roll + this.config.reelSpacing * roll + this.config.symbolWidth / 2;\n    //     videoInstance.y = this.config.symbolHeight * cell + this.config.symbolHeight / 2;\n    //     const player = this.videoPlayers.get(entry.symbol + '_on') as IVideoPlayer;\n    //     player.addInstance(videoInstance);\n    //     this.addChild(videoInstance);\n    //     return videoInstance;\n    // }\n}\n","import { BaseComponentConfiguration, DefaultValue, DynamicPositionObject } from '@egt/core';\nimport { IPointData } from 'pixi.js';\nimport { IVideosFeatureConfigurationDefault } from './IVideosFeatureConfigurationDefault';\n\nexport default class VideosFeatureConfigurationDefault extends BaseComponentConfiguration {}\n\nexport function VideosFeatureConfigurationFactoryDefault(): typeof VideosFeatureConfigurationDefault {\n    class VideosFeatureConfigurationInternalClass\n        extends VideosFeatureConfigurationDefault\n        implements IVideosFeatureConfigurationDefault\n    {\n        public nonProportionalReels = false;\n        public createVideoCovers = true;\n\n        @DefaultValue<IPointData>({\n            defaults: { x: 1, y: 1 },\n        })\n        public symbolScale: DynamicPositionObject<IPointData> & IPointData;\n    }\n    return VideosFeatureConfigurationInternalClass;\n}\n","import { BaseController } from '@egt/core';\nimport { Features, ISlotConfiguration, InitialSettings, LineMode, RootStore, UIState } from '@egt/slot';\nimport { merge } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { DependencyContainer, inject, injectable } from 'tsyringe';\nimport { IVideosFeatureConfigurationDefault } from '../configuration/IVideosFeatureConfigurationDefault';\nimport VideosViewDefault from '../views/VideosViewDefault';\n\n@injectable()\nexport default class VideosControllerDefault extends BaseController {\n    protected featureConfiguration: IVideosFeatureConfigurationDefault;\n\n    constructor(\n        @inject('ISlotConfiguration') protected config: ISlotConfiguration,\n        @inject('VideosView') protected view: VideosViewDefault,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('RootStore') protected rootStore: RootStore, // @inject('FeatureController') protected featureController: FeatureController,\n    ) {\n        super(view);\n    }\n\n    public afterResolvedDependencies(dependencyContainer: DependencyContainer): void {\n        this.featureConfiguration = dependencyContainer.resolve('VideosFeatureConfiguration');\n    }\n\n    // public afterInitComplete(): void {\n    // this.view.x = this.rootStore.subjects.REELS_POSITION.value.reelX;\n    // this.view.y = this.rootStore.subjects.REELS_POSITION.value.reelY;\n    // }\n\n    public onGameStarted(settings: any): void {\n        this.rootStore.subjects.REELS_STOPPED.chainSubscribe(Features.VIDEOS, this.playVideos.bind(this));\n\n        const destroyVideosMerge = merge(\n            this.rootStore.subjects.BEFORE_SPIN,\n            this.rootStore.subjects.BET_PROGRESS_BEFORE_SPIN,\n            this.rootStore.domainStore.COLLECT_RESPONSE,\n        );\n\n        destroyVideosMerge.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            if (this.view.isPlaying) {\n                this.rootStore.subjects.VIDEOS_PLAYING.next(false);\n            }\n            this.view.destroyVideos();\n        });\n\n        this.rootStore.subjects.HIDE_VIDEO_SYMBOLS_ON_TOP.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.view.hideSymbolsOnTop();\n        });\n\n        this.rootStore.subjects.RESTORE.chainSubscribe(Features.VIDEOS, this.onRestore.bind(this));\n\n        if (settings.state !== UIState.IDLE && settings.state !== UIState.BONUS_IDLE) {\n            this.view.createVideos(settings.entries, settings.reels);\n            this.view.playVideos();\n        }\n    }\n\n    public destroy(): void {\n        this.clearVideos();\n        super.destroy();\n    }\n\n    public clearVideos(): void {\n        this.view.destroyVideos();\n    }\n\n    public onRestore(_event): void {\n        // if is from Blitz videos are already shown\n        if (this.rootStore.uiStore.lastResponseFromBlitzPlay) {\n            this.rootStore.subjects.RESTORE.executorComplete();\n            return;\n        }\n        // if (this.rootStore.domainStore.SERVER_STATE.value === ServerState.WIN) {\n        this.view.destroyVideos();\n        if (\n            this.rootStore.domainStore.betResponse &&\n            this.rootStore.domainStore.betResponse.restoreResponse &&\n            !this.rootStore.domainStore.betResponse.restoreResponse.alreadyRestored\n        ) {\n            const restoreData = this.rootStore.domainStore.betResponse.restoreResponse;\n            this.view.createVideos(restoreData.entries, restoreData.reels);\n            this.view.playVideos();\n        }\n\n        this.rootStore.subjects.RESTORE.executorComplete();\n    }\n\n    protected playVideos(): void {\n        const betResponse = this.rootStore.domainStore.betResponse;\n        let reels = betResponse.reels;\n        if (betResponse.entries[0]?.mode === LineMode.OVERFLOW) {\n            return;\n        }\n        if (betResponse.mutations && betResponse.mutations.length > 0 && betResponse.mutatedReels) {\n            reels = betResponse.mutatedReels;\n        }\n\n        this.view.createVideos(betResponse.entries, reels);\n\n        // TODO: remove this condition and replace it with the above commented one after the new great win animation is done\n        // if (!this.rootStore.uiStore.turboModeEnabled) {\n        this.view.playVideos();\n        if (betResponse.entries && betResponse.entries.length > 0) {\n            this.rootStore.subjects.VIDEOS_PLAYING.next(true);\n        }\n        // }\n        this.rootStore.subjects.REELS_STOPPED.executorComplete();\n    }\n}\n","import Core, { IVideoPlayer, ScaleUntil, SymbolCredits, IOrientation } from '@egt/core';\nimport { ISlotConfiguration, Line, RootStore, SpinAnalyzer } from '@egt/slot';\nimport { ViewContainer } from '@egt/ui-lib';\nimport { BitmapText, Sprite, Texture } from 'pixi.js';\nimport { first, takeUntil } from 'rxjs/operators';\nimport { DependencyContainer, inject, injectable } from 'tsyringe';\nimport { IVideosFeatureConfigurationDefault } from '../configuration/IVideosFeatureConfigurationDefault';\n\n@injectable()\nexport default class VideosViewDefault extends ViewContainer {\n    public symbolsContainer: Sprite;\n    public registeredCells: any[] = [];\n    public videoPlayers: any = {};\n\n    public isPlaying: boolean = false;\n    public videoLoadingCallbacks: Array<() => void> = [];\n\n    protected featureConfiguration: IVideosFeatureConfigurationDefault;\n    protected symbolCoverSprites: Array<{ sprite: Sprite; row: number; col: number }> = [];\n\n    protected zIndexMultiplier: number = 10;\n\n    protected symbolsOnTop: any[] = [];\n    protected popSymbolsValuesInCredits: any[] = [];\n\n    protected topTexturesZIndexMultiplier: number = 100;\n\n    constructor(\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('SpinAnalyzer') protected spinAnalyzer: SpinAnalyzer,\n    ) {\n        super();\n    }\n\n    public afterResolvedDependencies(dependencyContainer: DependencyContainer): void {\n        this.featureConfiguration = dependencyContainer.resolve('VideosFeatureConfiguration');\n    }\n\n    public afterInit(): void {\n        Core.MONEY_MODE_IN_CREDITS.pipe(takeUntil(Core.ON_GAME_UNLOADED)).subscribe(this.onMoneyModeChanged.bind(this));\n        this.symbolsContainer = new Sprite();\n        this.addChild(this.symbolsContainer);\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n    }\n\n    public playVideos(): void {\n        /*         if (this.rootStore.uiStore.STATE.value === UIState.RESPIN) {\n            return;\n        } */\n\n        Object.keys(this.videoPlayers).forEach((key) => {\n            this.videoPlayers[key].play();\n        });\n\n        this.symbolsContainer.children.forEach((child) => {\n            child.visible = true;\n        });\n\n        this.isPlaying = true;\n        this.showSymbolsOnTop();\n    }\n\n    public createVideos(entries: Line[], reels: number[][]): void {\n        if (!entries || entries?.length === 0) {\n            return;\n        }\n        this.createSymbolsOnTop(entries, reels);\n        entries.forEach((entry: Line) => {\n            for (let i = 0; i < entry.cells?.length; i += 2) {\n                const row: number = entry.cells[i];\n                const col: number = entry.cells[i + 1];\n                const symbol: string = reels[row][col + 1].toString();\n                let symbolVideoConfig: any;\n\n                if (\n                    this.slotConfiguration.symbolsConfig[symbol].hasSecondVideo &&\n                    this.spinAnalyzer.shouldPlaySecondVideo(this.slotConfiguration.symbolsConfig[symbol].index)\n                ) {\n                    symbolVideoConfig = this.slotConfiguration.symbolsConfig[symbol].video2;\n                } else {\n                    symbolVideoConfig = this.slotConfiguration.symbolsConfig[symbol].video;\n                }\n\n                const asset: any = symbolVideoConfig ? Core.assets.getAsset(symbolVideoConfig.id) : null;\n                const animResource: any = this.slotConfiguration.assets.find((res) => res.id === symbolVideoConfig.id);\n\n                if (\n                    asset &&\n                    (asset.spritesheet || (Array.isArray(asset) && asset.length === animResource.url.length))\n                ) {\n                    // Create a VideoPlayer when the video asset and the textures are loaded.\n                    this.createVideo(row, col, symbol);\n                } else {\n                    if (!this.featureConfiguration.createVideoCovers) {\n                        if (symbolVideoConfig) {\n                            this.videoLoadingCallbacks.push(this.createVideo.bind(this, row, col, symbol));\n                        }\n                    } else {\n                        this.setZIndexMultiplier(row, symbol);\n                        const symbolSprite: Sprite = this.createSymbolSprite(\n                            row,\n                            col,\n                            this.slotConfiguration.symbols[symbol].texture(),\n                        );\n                        this.symbolCoverSprites.push({\n                            sprite: symbolSprite,\n                            row,\n                            col,\n                        });\n                        // Delay the creation of the VideoPlayer to when the video asset and the textures are loaded.\n                        if (symbolVideoConfig) {\n                            this.videoLoadingCallbacks.push(\n                                this.createVideo.bind(this, row, col, symbol, symbolSprite),\n                            );\n                        }\n                    }\n                    // Create a video cover.\n                }\n                this.symbolsContainer.sortChildren();\n            }\n        });\n    }\n\n    public refreshVideos(): void {\n        this.videoLoadingCallbacks.forEach((fn) => {\n            fn();\n        });\n        this.videoLoadingCallbacks = [];\n    }\n\n    public destroy(): void {\n        this.destroyVideos();\n        super.destroy.apply(this, arguments);\n    }\n\n    public destroyVideos(): void {\n        if (this.rootStore.subjects?.TRANSPARENT_REELS.value && this.registeredCells.length > 0) {\n            this.rootStore?.subjects?.SHOW_CELLS.next(this.registeredCells);\n        }\n\n        Object.keys(this.videoPlayers).forEach((key) => {\n            this.videoPlayers[key].stop();\n            this.videoPlayers[key].removeAllInstances();\n            Core.destroyVideoPlayer(this.videoPlayers[key]);\n        });\n        this.videoPlayers = [];\n        this.videoLoadingCallbacks = [];\n        this.registeredCells = [];\n        this.symbolsOnTop = [];\n        this.popSymbolsValuesInCredits = [];\n        this.symbolCoverSprites = [];\n        this.symbolsContainer.removeChildren();\n        this.isPlaying = false;\n    }\n\n    public hideSymbolsOnTop(): void {\n        for (const symbol of this.symbolsOnTop) {\n            symbol.visible = false;\n        }\n    }\n\n    public setOrientation(_orientation: IOrientation): void {\n        this.symbolsContainer.x = this.rootStore.subjects.REELS_POSITION.value.reelX;\n        this.symbolsContainer.y = this.rootStore.subjects.REELS_POSITION.value.reelY;\n        this.symbolsContainer.scale.set(this.getSymbolsContainerScale());\n        this.refreshVideosLayout();\n        this.refreshSymbolsOnTop();\n    }\n\n    protected isInstanceRegistered(row: number, col: number): boolean {\n        for (const cell of this.registeredCells) {\n            if (cell.row === row && cell.col === col) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    protected onFirstVideoFrameDispatched(vp: IVideoPlayer): void {\n        this.rootStore.subjects.CLEAR_CELLS.next(this.getRegisteredCellsFromPlayer(vp));\n    }\n\n    protected getVideoPlayer(symbol: string): IVideoPlayer | undefined {\n        let videoPlayer: IVideoPlayer = this.videoPlayers[symbol];\n        if (videoPlayer) {\n            return videoPlayer;\n        }\n\n        let symbolVideoConfig: any;\n        if (\n            this.slotConfiguration.symbolsConfig[symbol].hasSecondVideo &&\n            this.spinAnalyzer.shouldPlaySecondVideo(this.slotConfiguration.symbolsConfig[symbol].index)\n        ) {\n            symbolVideoConfig = this.slotConfiguration.symbolsConfig[symbol].video2;\n        } else {\n            symbolVideoConfig = this.slotConfiguration.symbolsConfig[symbol].video;\n        }\n\n        const asset: any = Core.assets.getAsset(symbolVideoConfig.id);\n        if (!asset) {\n            return undefined;\n        }\n        let symbolTextures = {};\n        if (Array.isArray(asset)) {\n            asset.forEach((a) => {\n                symbolTextures = Object.assign(symbolTextures, a.spritesheet.textures);\n            });\n        } else {\n            symbolTextures = asset.spritesheet.textures;\n        }\n        videoPlayer = Core.createVideoPlayer();\n        videoPlayer.frames = Object.keys(symbolTextures)\n            .sort()\n            .map((personNamedIndex) => {\n                return symbolTextures[personNamedIndex];\n            });\n\n        if (this.rootStore.subjects.TRANSPARENT_REELS.value) {\n            symbolVideoConfig.dispatchFirstFrame = true;\n            videoPlayer.FIRST_FRAME.pipe(first()).subscribe(this.onFirstVideoFrameDispatched.bind(this));\n        }\n        videoPlayer.config = symbolVideoConfig;\n        // biome-ignore lint/suspicious/noAssignInExpressions: <explanation>\n        return (this.videoPlayers[symbol] = videoPlayer);\n    }\n\n    protected createVideo(row: number, col: number, symbol: string, videoCover?: Sprite): void {\n        const videoPlayer: IVideoPlayer | undefined = this.getVideoPlayer(symbol);\n        if (videoPlayer === undefined) {\n            return;\n        }\n\n        this.setZIndexMultiplier(row, symbol);\n\n        if (videoCover) {\n            videoPlayer.addInstance(videoCover);\n            this.registeredCells.push({ vp: videoPlayer, instance: videoCover, row, col });\n        } else if (!this.isInstanceRegistered(row, col)) {\n            const symbolSprite: Sprite = this.createSymbolSprite(row, col);\n            this.registeredCells.push({ vp: videoPlayer, instance: symbolSprite, row, col });\n            videoPlayer.addInstance(symbolSprite);\n        }\n\n        if (this.isPlaying) {\n            videoPlayer.play();\n            // this.clearCellsUnderVideo(videoPlayer);\n        }\n    }\n\n    protected createSymbolSprite(row: number, col: number, texture?: Texture): Sprite {\n        const symbolSprite: Sprite = new Sprite();\n        if (texture) {\n            symbolSprite.texture = texture;\n            symbolSprite.visible = false;\n        }\n        this.calculateSpritePossitions(row, col, symbolSprite);\n        this.symbolsContainer.addChild(symbolSprite);\n        symbolSprite.zIndex = (row + 1) * this.zIndexMultiplier + col;\n        return symbolSprite;\n    }\n\n    protected calculateSpritePossitions(row: number, col: number, symbolSprite: Sprite): void {\n        const reelsPosition = this.rootStore.subjects.REELS_POSITION.value;\n        symbolSprite.x = (reelsPosition.reelWidth + reelsPosition.reelSpacing) * row + reelsPosition.reelWidth / 2;\n        symbolSprite.y = reelsPosition.symbolHeight * col + reelsPosition.symbolHeight / 2;\n        symbolSprite.anchor.set(0.5);\n        this.distortReel(symbolSprite, row);\n\n        if (this.featureConfiguration.nonProportionalReels) {\n            symbolSprite.scale.set(this.rootStore.subjects.REELS_SCALE_FACTOR.value);\n        } else {\n            symbolSprite.scale.set(this.rootStore.subjects.REELS_POSITION.value.symbolScale);\n        }\n    }\n\n    protected distortReel(sprite: Sprite, reelIndex: number) {\n        const reelsPosition = this.rootStore.subjects.REELS_POSITION.value;\n        if (\n            !reelsPosition.threeDimentionalRadiusesPerReels ||\n            reelsPosition.threeDimentionalRadiusesPerReels.length === 0\n        ) {\n            return;\n        }\n        const centralReel = Math.floor(this.rootStore.subjects.NUMBER_OF_REELS.value / 2);\n        const reelCenterY = this.rootStore.subjects.REELS_POSITION.value.reelHeight / 2;\n        const symbolCenterY = sprite.y;\n        const distanceFromYCenter = symbolCenterY - reelCenterY;\n\n        const radius = reelsPosition.threeDimentionalRadiusesPerReels[reelIndex];\n        const angle = distanceFromYCenter / radius;\n        const xOffset = radius - Math.cos(angle) * radius;\n\n        const direction = reelIndex < centralReel ? 1 : reelIndex > centralReel ? -1 : 0;\n        sprite.x += xOffset * direction;\n    }\n\n    protected createSymbolsOnTop(entries: Line[], reels: number[][]): void {\n        if (this.rootStore.subjects.TRANSPARENT_REELS.value && entries.length > 0) {\n            let reel: number = 0;\n            let cell: number = 0;\n\n            for (let i: number = 0; i < reels.length; i++) {\n                reel = i;\n                for (let t: number = 1; t < reels[i].length - 1; t++) {\n                    cell = t;\n                    const symbolId: number = this.getSymbolArrayIndex(reels[reel][cell]);\n                    // TO DO this line \"!this.slotConfiguration.symbolsConfig[symbolId].isExpandingWild\" is\n                    // for fixing duplicate wilds when wild expand\n                    if (\n                        symbolId > -1 &&\n                        this.slotConfiguration.symbolsConfig[symbolId].topTexture &&\n                        !this.hasVideoOnThisFrame(entries, reel, cell) &&\n                        !this.slotConfiguration.symbolsConfig[symbolId].isExpandingWild &&\n                        this.slotConfiguration.symbolsConfig[symbolId].specialSymbol\n                    ) {\n                        const topSymbol: Sprite = new Sprite(this.slotConfiguration.symbols[symbolId].topTexture());\n                        topSymbol.x =\n                            (this.rootStore.subjects.REELS_POSITION.value.reelWidth +\n                                this.rootStore.subjects.REELS_POSITION.value.reelSpacing) *\n                                reel +\n                            this.rootStore.subjects.REELS_POSITION.value.reelWidth / 2;\n                        topSymbol.y =\n                            this.rootStore.subjects.REELS_POSITION.value.symbolHeight * (cell - 1) +\n                            this.rootStore.subjects.REELS_POSITION.value.symbolHeight / 2;\n                        topSymbol.anchor.set(0.5);\n                        (topSymbol as Sprite & { reelRow?: number; reelCol?: number }).reelRow = reel;\n                        (topSymbol as Sprite & { reelRow?: number; reelCol?: number }).reelCol = cell - 1;\n                        topSymbol.scale.set(this.rootStore.subjects.REELS_POSITION.value.symbolScale);\n                        this.symbolsContainer.addChild(topSymbol);\n                        topSymbol.zIndex = (reel + 1) * this.topTexturesZIndexMultiplier - cell;\n                        topSymbol.visible = false;\n                        this.symbolsOnTop.push(topSymbol);\n\n                        if (symbolId > -1 && this.slotConfiguration.symbolsConfig[symbolId].value) {\n                            const bellValue: number =\n                                this.slotConfiguration.symbolsConfig[symbolId].value *\n                                this.rootStore.settings.factor *\n                                this.rootStore.uiStore.SELECTED_BET.value;\n\n                            /* const currency: BitmapText = new BitmapText(this.rootStore.uiStore.currency, {\n                                fontName: 'currencyValueText',\n                            });\n                            currency.anchor = new Point(0.5, 0.5);\n                            if (this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value === 4) {\n                                currency.y = -35;\n                            } else {\n                                currency.y = -45;\n                            }\n\n                            topSymbol.addChild(currency); */\n\n                            const bellValueCredits: SymbolCredits = new SymbolCredits(\n                                bellValue,\n                                Core.SELECTED_DENOMINATION.value,\n                            );\n                            let bellText: string = bellValueCredits.stringMoney;\n                            if (Core.MONEY_MODE_IN_CREDITS.value) {\n                                bellText = bellValueCredits.stringCredits;\n                                // currency.visible = false;\n                            }\n                            this.popSymbolsValuesInCredits.push(bellValueCredits);\n\n                            const text: BitmapText = new BitmapText(bellText, {\n                                fontName: 'symbolValueText',\n                            });\n\n                            ScaleUntil.scaleBitmapTextUntilFitInDimension(\n                                text,\n                                this.rootStore.subjects.REELS_POSITION.value.symbolWidth,\n                            );\n                            text.anchor.set(0.5, 0.5);\n                            // text.x = topSymbol.x;\n                            // text.y = topSymbol.y;\n                            // text.scale.set(this.slotConfiguration.symbolScale);\n                            // text.visible = false;\n                            // this.symbolsOnTop.push(text);\n                            topSymbol.addChild(text);\n                            // text.zIndex = (reel + 1) * 1000 - cell;\n                        } else {\n                            this.popSymbolsValuesInCredits.push(undefined);\n                        }\n                    }\n                }\n            }\n        }\n        this.symbolsContainer.sortChildren();\n    }\n\n    protected showSymbolsOnTop(): void {\n        for (const symbol of this.symbolsOnTop) {\n            symbol.visible = true;\n        }\n    }\n\n    protected refreshSymbolsOnTop(): void {\n        const reelsPosition = this.rootStore.subjects.REELS_POSITION.value;\n\n        for (const symbol of this.symbolsOnTop) {\n            const row = (symbol as Sprite & { reelRow?: number }).reelRow;\n            const col = (symbol as Sprite & { reelCol?: number }).reelCol;\n\n            if (row === undefined || col === undefined) {\n                continue;\n            }\n\n            symbol.x = (reelsPosition.reelWidth + reelsPosition.reelSpacing) * row + reelsPosition.reelWidth / 2;\n            symbol.y = reelsPosition.symbolHeight * col + reelsPosition.symbolHeight / 2;\n            symbol.scale.set(reelsPosition.symbolScale);\n        }\n    }\n\n    protected refreshVideosLayout(): void {\n        this.registeredCells.forEach(({ instance: symbolSprite, row, col }) => {\n            this.calculateSpritePossitions(row, col, symbolSprite);\n        });\n    }\n\n    protected getSymbolsContainerScale(): number {\n        return Core.ORIENTATION.value.isLandscape ? 1 : this.rootStore.subjects.PORTRAIT_SCALE.value;\n    }\n\n    protected setZIndexMultiplier(row: number, symbol: string): void {\n        this.zIndexMultiplier = this.slotConfiguration.symbolsConfig[symbol].videoOnTop\n            ? (row + 2) * this.topTexturesZIndexMultiplier + 10\n            : 10;\n    }\n\n    protected onMoneyModeChanged(): void {\n        for (let i: number = 0; i < this.symbolsOnTop.length; i++) {\n            if (this.popSymbolsValuesInCredits[i]) {\n                // const currency: BitmapText = this.symbolsOnTop[i].getChildAt(0) as BitmapText;\n                const value: BitmapText = this.symbolsOnTop[i].getChildAt(0) as BitmapText;\n\n                if (Core.MONEY_MODE_IN_CREDITS.value) {\n                    value.text = this.popSymbolsValuesInCredits[i].stringCredits;\n                    // currency.visible = false;\n                } else {\n                    value.text = this.popSymbolsValuesInCredits[i].stringMoney;\n                    // currency.visible = true;\n                }\n\n                ScaleUntil.scaleBitmapTextUntilFitInDimension(\n                    value,\n                    this.rootStore.subjects.REELS_POSITION.value.symbolWidth,\n                );\n            }\n        }\n    }\n\n    protected getRegisteredCellsFromPlayer(vp: IVideoPlayer): any[] {\n        return this.registeredCells\n            .filter((instance) => {\n                if (instance.vp === vp) {\n                    return true;\n                }\n                return false;\n            })\n            .map((instance) => {\n                if (this.featureConfiguration.nonProportionalReels) {\n                    return instance;\n                }\n\n                return {\n                    row: instance.row,\n                    col: instance.col,\n                };\n            });\n    }\n\n    protected hasVideoOnThisFrame(entries: Line[], reel: number, cell: number): boolean {\n        let hasVideo: boolean = false;\n        for (const entry of entries) {\n            for (let i = 0; i < entry?.cells?.length; i += 2) {\n                const row: number = entry.cells[i];\n                const col: number = entry.cells[i + 1];\n                if (reel === row && cell - 1 === col) {\n                    hasVideo = true;\n                }\n            }\n        }\n\n        return hasVideo;\n    }\n\n    protected getSymbolArrayIndex(symbolIndex: number): number {\n        let id: number = -1;\n        for (let i: number = 0; i < this.slotConfiguration.symbolsConfig.length; i++) {\n            if (this.slotConfiguration.symbolsConfig[i].index === symbolIndex) {\n                id = i;\n            }\n        }\n        return id;\n    }\n}\n","import { BaseComponentConfiguration } from '@egt/core';\nimport { IVideosFeatureConfigurationSpine } from './IVideosFeatureConfigurationSpine';\n\nexport default class VideosFeatureConfigurationSpine extends BaseComponentConfiguration {}\n\nexport function VideosFeatureConfigurationFactorySpine(): typeof VideosFeatureConfigurationSpine {\n    class VideosFeatureConfigurationInternalClass\n        extends VideosFeatureConfigurationSpine\n        implements IVideosFeatureConfigurationSpine {}\n    return VideosFeatureConfigurationInternalClass;\n}\n","import Core, { BaseController, IOrientation, VideoTypes } from '@egt/core';\nimport { Features, ISlotConfiguration, InitialSettings, LineMode, RootStore, UIState } from '@egt/slot';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport VideoStoreSpine from '../store/VideoStoreSpine';\nimport VideosViewSpine from '../views/VideosViewSpine';\nimport { merge } from 'rxjs';\n\n@injectable()\nexport default class VideosControllerSpine extends BaseController {\n    protected onVideoPlayed = false;\n    protected reelsHasStopped: boolean = false;\n    constructor(\n        @inject('ISlotConfiguration') protected config: ISlotConfiguration,\n        @inject('VideosView') protected view: VideosViewSpine,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('VideoStore') protected store: VideoStoreSpine,\n        @inject('RootStore') protected rootStore: RootStore, // @inject('FeatureController') protected featureController: FeatureController,\n    ) {\n        super(view);\n    }\n\n    public afterInitComplete(): void {\n        this.view.x = this.rootStore.subjects.REELS_POSITION.value.reelX;\n        this.view.y = this.rootStore.subjects.REELS_POSITION.value.reelY;\n    }\n\n    public onGameStarted(settings: any): void {\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n\n        this.rootStore.subjects.REELS_STOPPED.chainSubscribe(Features.VIDEOS, this.onReelsStopped.bind(this));\n        this.rootStore.subjects.DESTROY_CUSTOM_VIDEO.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.destroyCustomVideo.bind(this),\n        );\n        this.rootStore.subjects.PLAY_CUSTOM_VIDEO.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.createCustomVideo.bind(this),\n        );\n\n        this.rootStore.subjects.REELS_STOP_ALL.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.store.allReelsHaveStopped = true;\n        });\n\n        const onBeforeSpinMerge = merge(\n            this.rootStore.subjects.BEFORE_SPIN,\n            this.rootStore.subjects.BET_PROGRESS_BEFORE_SPIN,\n        );\n\n        onBeforeSpinMerge.pipe(takeUntil(this.DESTROY)).subscribe(this.onBeforeSpin.bind(this));\n\n        this.rootStore.subjects.RESTORE.chainSubscribe(Features.VIDEOS, this.onRestore.bind(this));\n\n        if (settings.state !== UIState.IDLE && settings.state !== UIState.BONUS_IDLE) {\n            this.view.createVideos(settings.entries, settings.reels);\n            this.view.playVideos();\n        }\n\n        this.rootStore.domainStore.COLLECT_RESPONSE.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            if (this.view.isPlaying) {\n                this.rootStore.subjects.VIDEOS_PLAYING.next(false);\n            }\n            this.clearVideos();\n        });\n    }\n\n    public destroy(): void {\n        this.clearVideos();\n        super.destroy();\n    }\n\n    public clearVideos(): void {\n        this.view.destroyVideos();\n    }\n\n    public onRestore(_event): void {\n        // if (this.rootStore.domainStore.SERVER_STATE.value === ServerState.WIN) {\n        this.view.destroyVideos();\n        if (\n            this.rootStore.domainStore.betResponse &&\n            this.rootStore.domainStore.betResponse.restoreResponse &&\n            !this.rootStore.domainStore.betResponse.restoreResponse.alreadyRestored\n        ) {\n            const restoreData = this.rootStore.domainStore.betResponse.restoreResponse;\n            this.view.createVideos(restoreData.entries, restoreData.reels);\n            this.view.playVideos();\n        }\n\n        this.rootStore.subjects.RESTORE.executorComplete();\n    }\n\n    protected onBeforeSpin(): void {\n        if (this.view.isPlaying) {\n            this.rootStore.subjects.VIDEOS_PLAYING.next(false);\n            this.store.allReelsHaveStopped = false;\n        }\n        this.reelsHasStopped = false;\n        this.view.destroyVideos();\n    }\n\n    protected videoFinished(_val?): void {\n        // CUSTOM LOGIC\n    }\n\n    protected specialVideoFinished(_val) {\n        // CUSTOM IMPLEMENTATION\n    }\n\n    protected playVideos(): void {\n        const betResponse = this.rootStore.domainStore.betResponse;\n        const reels = betResponse.reels;\n        if (betResponse.entries[0]?.mode === LineMode.OVERFLOW) {\n            return;\n        }\n\n        this.view.createVideos(betResponse.entries, reels);\n        this.store.numberOfActiveVideos = Number(betResponse.entries) / 2;\n\n        this.view.playVideos();\n    }\n\n    protected onReelsStopped(): void {\n        this.playVideos();\n        const betResponse = this.rootStore.domainStore.betResponse;\n        if (betResponse.entries && betResponse.entries.length > 0) {\n            this.rootStore.subjects.VIDEOS_PLAYING.next(true);\n        }\n        this.rootStore.subjects.REELS_STOPPED.executorComplete();\n    }\n\n    protected destroyCustomVideo(): void {\n        this.clearVideos();\n    }\n\n    protected createCustomVideo(val): void {\n        if (val.videoType === VideoTypes.CUSTOM) {\n            this.view.createAndPlayCustomVideo(val);\n        } else if (val.symbol !== -1) {\n            this.view.isPlaying = true;\n            this.view.createVideoBySymbol(val.symbol, val.pos.row, val.pos.col, false, val.pos, val.handler);\n        }\n    }\n\n    protected setOrientation(orientation: IOrientation): void {\n        this.view.x = this.rootStore.subjects.REELS_POSITION.value.reelX;\n        this.view.y = this.rootStore.subjects.REELS_POSITION.value.reelY;\n        const scale = orientation.isLandscape ? 1 : this.rootStore.subjects.PORTRAIT_SCALE.value;\n        this.view.scale.set(scale);\n    }\n}\n","import { Subject } from 'rxjs';\nimport { injectable } from 'tsyringe';\nimport { BaseStore } from '@egt/core';\n\n@injectable()\nexport default class VideoStoreSpine extends BaseStore {\n    numberOfActiveVideos = 0;\n    numberOfFinishedVideos = 0;\n    allReelsHaveStopped = false;\n    public readonly VIDEO_FINISHED = new Subject();\n    public readonly SPECIAL_VIDEO_FINISHED = new Subject();\n\n    constructor() {\n        super();\n        this.enableLogging();\n    }\n}\n","import Core, { DynamicPositionObject, ISpineVideoPlayer, IVideoPositionPoint, ScaleUntil } from '@egt/core';\nimport { ISlotConfiguration, Line, RootStore, SpinAnalyzer } from '@egt/slot';\nimport { ViewContainer } from '@egt/ui-lib';\nimport { BitmapText, Sprite, Texture } from 'pixi.js';\nimport { first, takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport VideoStoreSpine from '../store/VideoStoreSpine';\n\n@injectable()\nexport default class VideosViewSpine extends ViewContainer {\n    public registeredCells: any[] = [];\n    public videoPlayers: ISpineVideoPlayer[] = [];\n    public specialVideoPlayers: ISpineVideoPlayer[] = [];\n\n    public isPlaying: boolean = false;\n    public videoLoadingCallbacks: Array<() => void> = [];\n\n    protected zIndexMultiplier: number = 10;\n\n    protected symbolsOnTop: any[] = [];\n    protected symbols: any[] = [];\n    protected popSymbolsValuesInCredits: any[] = [];\n\n    protected topTexturesZIndexMultiplier: number = 100;\n\n    constructor(\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('SpinAnalyzer') protected spinAnalyzer: SpinAnalyzer,\n        @inject('VideoStore') protected store: VideoStoreSpine,\n    ) {\n        super();\n    }\n\n    public afterInit(): void {\n        Core.MONEY_MODE_IN_CREDITS.pipe(takeUntil(Core.ON_GAME_UNLOADED)).subscribe(this.onMoneyModeChanged.bind(this));\n    }\n\n    public playVideos(): void {\n        Object.keys(this.videoPlayers).forEach((key) => {\n            this.videoPlayers[key].play();\n        });\n\n        this.children.forEach((child) => {\n            child.visible = true;\n        });\n\n        this.isPlaying = true;\n        this.showSymbolsOnTop();\n    }\n\n    public createAndPlayCustomVideo(val): void {\n        // val.videoConfig.video.id = 'wildChange1x2'\n        const key = `replace${val.videoConfig.video.id}`;\n\n        let videoPlayer: ISpineVideoPlayer = this.videoPlayers[key];\n        if (!videoPlayer) {\n            videoPlayer = Core.createSpineVideoPlayer();\n            videoPlayer.createSpineAnimations(val.videoConfig.video, val.videoConfig.assetId);\n            this.videoPlayers[key] = videoPlayer;\n        }\n        videoPlayer.VIDEO_COMPLETE.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            videoPlayer.destroy();\n        });\n        videoPlayer.config = val.videoConfig.video;\n        videoPlayer.config.row = val.pos.row;\n        videoPlayer.config.col = val.pos.col;\n        videoPlayer.config.getEachFrame = true;\n        if (val.handler) {\n            videoPlayer.addHandler(val.handler);\n        }\n\n        this.setZIndexMultiplier(val.pos.row, {});\n        const symbolVideoConfig = val.videoConfig;\n        symbolVideoConfig.row = val.pos.row;\n        symbolVideoConfig.col = val.pos.col;\n        const symbolSprite: Sprite = this.createSymbolSprite(val.pos.row, val.pos.col, symbolVideoConfig, undefined);\n        this.registeredCells.push({\n            vp: videoPlayer,\n            instance: symbolSprite,\n            row: val.pos.row,\n            col: val.pos.col,\n            symbol: -1,\n        });\n        let frameIndex = 0;\n        if (val.frameIndexNotification > -1 && val.handlerFrameDisplayed) {\n            const sub = videoPlayer.VIDEO_FRAME.subscribe(() => {\n                frameIndex++;\n                if (frameIndex === val.frameIndexNotification) {\n                    sub.unsubscribe();\n                    val.handlerFrameDisplayed(val);\n                }\n            });\n        }\n        videoPlayer.addInstance(symbolSprite, videoPlayer.config);\n\n        this.isPlaying = true;\n        videoPlayer.play();\n    }\n\n    public createVideoBySymbol(\n        symbol: string,\n        row,\n        col,\n        videoOn: boolean,\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        position?: DynamicPositionObject<IVideoPositionPoint>,\n        handler?: () => void,\n    ): void {\n        const symbolConfig: any = this.slotConfiguration.symbolsConfig.find((p) => p.index === Number(symbol));\n\n        const symbolVideoConfig = videoOn ? symbolConfig.videoOn : symbolConfig.video;\n\n        if (videoOn && !symbolVideoConfig) {\n            return;\n        }\n        const asset: any = symbolVideoConfig\n            ? Core.assets.getAsset(symbolVideoConfig.assetId || symbolVideoConfig.id)\n            : null;\n        if (asset && asset.spineData) {\n            this.createVideo(row, col, symbolConfig, videoOn, undefined, handler);\n        } else {\n            // const symbolConfiguration: any = this.slotConfiguration.symbols.find((p) => p.index() === Number(symbol));\n            // this.setZIndexMultiplier(row, symbolConfig);\n            // const symbolSprite: Sprite = this.createSymbolSprite(row, col, symbolConfig, undefined);\n            // Delay the creation of the VideoPlayer to when the video asset and the textures are loaded.\n            if (symbolVideoConfig) {\n                this.videoLoadingCallbacks.push(\n                    this.createVideo.bind(this, row, col, symbolConfig, videoOn, undefined, handler),\n                );\n            }\n        }\n        this.sortChildren();\n    }\n\n    public createVideos(entries: Line[], reels: number[][], onVideo: boolean = false): void {\n        if (!entries || entries?.length === 0) {\n            return;\n        }\n        //  this.createSymbolsOnTop(entries, reels);\n        entries.forEach((entry: Line) => {\n            for (let i = 0; i < entry.cells?.length; i += 2) {\n                const row: number = entry.cells[i];\n                const col: number = entry.cells[i + 1];\n                if (reels[row]) {\n                    // CHECK FOR HORIZONTAL REEL REMOVE WHEN SERVER READY\n\n                    const symbol: string = reels[row][col + 1].toString() || '0';\n                    this.createVideoBySymbol(symbol, row, col, onVideo);\n                }\n            }\n        });\n    }\n\n    public refreshVideos(): void {\n        this.videoLoadingCallbacks.forEach((fn) => {\n            fn();\n        });\n        if (this.videoLoadingCallbacks.length) {\n            this.rootStore.subjects.CLEAR_CELLS_LAYERS.next([this.registeredCells, [1, 2]]);\n        }\n\n        this.videoLoadingCallbacks = [];\n    }\n\n    public destroy(): void {\n        this.destroyVideos();\n        super.destroy.apply(this, arguments);\n    }\n\n    public destroyVideos(destroyCells: boolean = true): void {\n        if (this.rootStore.subjects?.TRANSPARENT_REELS?.value && this.registeredCells.length > 0) {\n            this.rootStore?.subjects?.SHOW_CELLS.next(this.registeredCells);\n        }\n\n        Object.keys(this.videoPlayers).forEach((key) => {\n            Core.destroyVideoPlayer(this.videoPlayers[key]);\n            delete this.videoPlayers[key];\n        });\n\n        this.videoPlayers.length = 0;\n        this.videoLoadingCallbacks.length = 0;\n        this.symbols.length = 0;\n        this.symbols = [];\n        this.symbolsOnTop.length = 0;\n        this.popSymbolsValuesInCredits.length = 0;\n\n        if (destroyCells) {\n            this.registeredCells.length = 0;\n        }\n        this.removeChildren();\n\n        this.isPlaying = false;\n    }\n\n    public hideSymbolsOnTop(): void {\n        for (const symbol of this.symbolsOnTop) {\n            symbol.visible = false;\n        }\n    }\n\n    protected isInstanceRegistered(row: number, col: number): boolean {\n        for (const cell of this.registeredCells) {\n            if (cell?.row === row && cell?.col === col) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    // protected onFirstVideoFrameDispatched(vp: ISpineVideoPlayer): void {\n    //     this.rootStore.subjects.CLEAR_CELLS.next(this.getRegisteredCellsFromPlayer(vp));\n    // }\n\n    protected getVideoPlayer(\n        symbolConfig: any,\n        row: number,\n        col: number,\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        videoOn: boolean,\n    ): ISpineVideoPlayer | undefined {\n        let symbolVideoConfig: any;\n        if (symbolConfig.hasSecondVideo) {\n            symbolVideoConfig = JSON.parse(JSON.stringify(symbolConfig.video2));\n        } else {\n            symbolVideoConfig = JSON.parse(JSON.stringify(symbolConfig.video));\n        }\n\n        symbolVideoConfig.row = row;\n        symbolVideoConfig.col = col;\n        symbolVideoConfig.symbolId = symbolConfig.index;\n        let videoPlayer: ISpineVideoPlayer = this.videoPlayers[symbolVideoConfig.id];\n        if (videoPlayer) {\n            return videoPlayer;\n        }\n\n        videoPlayer = Core.createSpineVideoPlayer();\n        videoPlayer.createSpineAnimations(symbolVideoConfig);\n        videoPlayer.VIDEO_COMPLETE.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onVideoAnimComplete.bind(this, symbolVideoConfig),\n        );\n        if (this.rootStore.subjects.TRANSPARENT_REELS.value) {\n            symbolVideoConfig.dispatchFirstFrame = true;\n            if (!symbolConfig.topTexture && !symbolConfig.onTopTexture) {\n                videoPlayer.FIRST_FRAME.pipe(first()).subscribe(this.hideBottomLayer.bind(this));\n            } else {\n                videoPlayer.FIRST_FRAME.pipe(first()).subscribe(this.hideTopLayers.bind(this));\n            }\n        }\n\n        videoPlayer.config = symbolVideoConfig;\n\n        // biome-ignore lint/suspicious/noAssignInExpressions: <explanation>\n        return (this.videoPlayers[symbolVideoConfig.id] = videoPlayer);\n    }\n\n    protected onVideoAnimComplete(val): void {\n        this.store.VIDEO_FINISHED.next(val);\n    }\n\n    protected hideBottomLayer(vp: ISpineVideoPlayer): void {\n        this.rootStore.subjects.CLEAR_CELLS.next(this.getRegisteredCellsFromPlayer(vp));\n    }\n\n    protected hideTopLayers(vp: ISpineVideoPlayer): void {\n        this.rootStore.subjects.CLEAR_CELLS_LAYERS.next([this.getRegisteredCellsFromPlayer(vp), [1, 2]]);\n    }\n\n    protected createVideo(\n        row: number,\n        col: number,\n        symbolConfig: any,\n        videoOn,\n        videoCover?: Sprite,\n        handler?: () => void,\n    ): void {\n        const videoPlayer: ISpineVideoPlayer | undefined = this.getVideoPlayer(symbolConfig, row, col, videoOn);\n\n        if (videoPlayer === undefined) {\n            return;\n        }\n\n        this.setZIndexMultiplier(row, symbolConfig);\n        let symbolVideoConfig;\n        if (symbolConfig.hasSecondVideo) {\n            symbolVideoConfig = JSON.parse(JSON.stringify(symbolConfig.video2));\n        } else {\n            symbolVideoConfig = JSON.parse(JSON.stringify(symbolConfig.video));\n        }\n        symbolVideoConfig.row = row;\n        symbolVideoConfig.col = col;\n        if (videoCover) {\n            this.registeredCells.push({ vp: videoPlayer, instance: videoCover, row, col, symbol: symbolConfig.index });\n            videoPlayer.addInstance(videoCover, symbolVideoConfig);\n        } else if (!this.isInstanceRegistered(row, col)) {\n            const symbolSprite: Sprite = this.createSymbolSprite(row, col, symbolConfig, undefined);\n            this.registeredCells.push({\n                vp: videoPlayer,\n                instance: symbolSprite,\n                row,\n                col,\n                symbol: symbolConfig.index,\n            });\n            videoPlayer.addInstance(symbolSprite, symbolVideoConfig);\n        }\n\n        if (handler) {\n            videoPlayer.addHandler(handler);\n        }\n\n        if (this.isPlaying) {\n            videoPlayer.play();\n        }\n    }\n\n    protected createSymbolSprite(row: number, col: number, symbolConfig, texture?: Texture): Sprite {\n        const symbolSprite: Sprite = new Sprite();\n        if (texture) {\n            symbolSprite.texture = texture;\n            symbolSprite.visible = false;\n        }\n\n        symbolSprite.x =\n            (this.rootStore.subjects.REELS_POSITION.value.reelWidth +\n                this.rootStore.subjects.REELS_POSITION.value.reelSpacing) *\n                row +\n            this.rootStore.subjects.REELS_POSITION.value.reelWidth / 2;\n        const customOffset: number =\n            symbolConfig.video.height - this.rootStore.subjects.REELS_POSITION.value.symbolHeight;\n        symbolSprite.y =\n            (this.rootStore.subjects.REELS_POSITION.value.symbolHeight + customOffset) * col +\n            (this.rootStore.subjects.REELS_POSITION.value.symbolHeight + customOffset) / 2;\n\n        symbolSprite.anchor.set(0.5);\n        symbolSprite.scale.set(\n            this.rootStore.subjects.REELS_POSITION.value.symbolScale,\n            this.rootStore.subjects.REELS_POSITION.value.symbolScale,\n        );\n\n        this.addChild(symbolSprite);\n        this.symbols.push(symbolSprite);\n        symbolSprite.zIndex = (row + 1) * this.zIndexMultiplier + col;\n        return symbolSprite;\n    }\n\n    protected createSymbolsOnTop(_entries: Line[], _reels: number[][]): void {\n        //implement for BellLink if needed\n    }\n\n    protected showSymbolsOnTop(): void {\n        for (const symbol of this.symbolsOnTop) {\n            symbol.visible = true;\n        }\n    }\n\n    protected setZIndexMultiplier(row: number, symbolConfig: any): void {\n        this.zIndexMultiplier = symbolConfig.videoOnTop ? (row + 2) * this.topTexturesZIndexMultiplier + 10 : 10;\n    }\n\n    protected onMoneyModeChanged(): void {\n        for (let i: number = 0; i < this.symbolsOnTop.length; i++) {\n            if (this.popSymbolsValuesInCredits[i]) {\n                // const currency: BitmapText = this.symbolsOnTop[i].getChildAt(0) as BitmapText;\n                const value: BitmapText = this.symbolsOnTop[i].getChildAt(0) as BitmapText;\n\n                if (Core.MONEY_MODE_IN_CREDITS.value) {\n                    value.text = this.popSymbolsValuesInCredits[i].stringCredits;\n                    // currency.visible = false;\n                } else {\n                    value.text = this.popSymbolsValuesInCredits[i].stringMoney;\n                    // currency.visible = true;\n                }\n\n                ScaleUntil.scaleBitmapTextUntilFitInDimension(\n                    value,\n                    this.rootStore.subjects.REELS_POSITION.value.symbolWidth,\n                );\n            }\n        }\n    }\n\n    protected getRegisteredCellsFromPlayer(vp: ISpineVideoPlayer): any[] {\n        return this.registeredCells.filter((instance) => {\n            if (instance?.vp === vp) {\n                delete instance.vp;\n                delete instance.instance;\n                return true;\n            }\n            return false;\n        });\n    }\n\n    protected hasVideoOnThisFrame(entries: Line[], reel: number, cell: number): boolean {\n        let hasVideo: boolean = false;\n        for (const entry of entries) {\n            for (let i = 0; i < entry.cells.length; i += 2) {\n                const row: number = entry.cells[i];\n                const col: number = entry.cells[i + 1];\n                if (reel === row && cell - 1 === col) {\n                    hasVideo = true;\n                }\n            }\n        }\n\n        return hasVideo;\n    }\n\n    protected getSymbolArrayIndex(symbolIndex: number): number {\n        let id: number = -1;\n        for (let i: number = 0; i < this.slotConfiguration.symbolsConfig.length; i++) {\n            if (this.slotConfiguration.symbolsConfig[i].index === symbolIndex) {\n                id = i;\n            }\n        }\n        return id;\n    }\n}\n","const enum ScratchFeatures {\n    NONE = 'NONE',\n    SCRATCH_WIN_VISUALIZATION = 'SCRATCH_WIN_VISUALIZATION',\n    SCRATCH_RESTORE_FEATURE = 'SCRATCH_RESTORE_FEATURE',\n    SCRATCH_MYSTERY_JACKPOT = 'SCRATCH_MYSTERY_JACKPOT',\n    SCRATCH_AUTOPLAY_FEATURE = 'SCRATCH_AUTOPLAY_FEATURE',\n    SCRATCH_READY_FOR_NEW_AUTOPLAY = 'SCRATCH_READY_FOR_NEW_AUTOPLAY',\n    SCRATCH_BOARD_GAME = 'SCRATCH_BOARD_GAME',\n    SCRATCH_BOARD_DICE_BACK = 'SCRATCH_BOARD_DICE_BACK',\n    SCRATCH_PLAYER_SYMBOLS = 'SCRATCH_PLAYER_SYMBOLS',\n    SCRATCH_MIN_SPIN_TIME = 'SCRATCH_MIN_SPIN_TIME',\n    SCRATCH_WINNING_SYMBOLS = 'SCRATCH_WINNING_SYMBOLS',\n    SCRATCH_BIG_WIN = 'SCRATCH_BIG_WIN',\n    SCRATCH_MESSAGE_BAR = 'SCRATCH_MESSAGE_BAR',\n    SCRATCH_MAX_WIN = 'SCRATCH_MAX_WIN',\n    SCRATCH_GIFT_SPINS = 'SCRATCH_GIFT_SPINS',\n    SCRATCH_TOURNAMENTS = 'SCRATCH_TOURNAMENTS',\n    // Backend load/wire identity for the scratch prize-pop campaign.\n    SCRATCH_PRIZE_POPS = 'SCRATCH_PRIZE_POPS',\n    // The always-on ScratchCampaignManager feature: its load key (venom slug scratch-campaign-manager)\n    // and the campaign chain slot (featuresPriority, chainSubscribe).\n    SCRATCH_CAMPAIGN_MANAGER = 'SCRATCH_CAMPAIGN_MANAGER',\n    SCRATCH_AUTOPLAY_NUMERIC_INPUT_FEATURE = 'SCRATCH_AUTOPLAY_NUMERIC_INPUT_FEATURE',\n}\n\nexport default ScratchFeatures;\n","import { BaseComponent } from '@egt/core';\nimport { SlotComponents } from '@egt/slot';\nimport { Lifecycle } from 'tsyringe';\nimport ReelsOverlayComponentConfiguration, {\n    ReelsOverlayComponentConfigurationFactory,\n} from './configuration/ReelsOverlayComponentConfiguration';\nimport ReelsOverlayView from './views/ReelsOverlayView';\n\nexport default class ReelsOverlayComponent extends BaseComponent {\n    public static configurationName = 'ReelsOverlayComponent';\n\n    public reelsOverlayView: ReelsOverlayView;\n    public componentType = SlotComponents.REELS_OVERLAY;\n    public configuration: ReelsOverlayComponentConfiguration;\n    public rootView;\n\n    constructor(\n        private config?: (\n            ClassType?: typeof ReelsOverlayComponentConfiguration,\n        ) => typeof ReelsOverlayComponentConfiguration,\n    ) {\n        super();\n        // console.log('LOAD MAIN PANEL')\n    }\n\n    public destroy(): void {\n        // this.reelsOverlayView.destroy();\n        // @ts-ignore\n        this.reelsOverlayView = null;\n\n        this.configuration.destroy();\n        // @ts-ignore\n        this.configuration = null;\n        // @ts-ignore\n        this.rootView = null;\n\n        // @ts-ignore\n        this.config = null;\n\n        super.destroy();\n    }\n\n    public onAfterGameConfigurationCreated(): void {\n        super.onAfterGameConfigurationCreated();\n        // const slotConfig: ISlotConfiguration = this.dependencyContainer.resolve('ISlotConfiguration');\n        this.configuration = this.dependencyContainer.resolve('ReelsOverlayComponentConfiguration');\n        // if (slotConfig.componentsConfiguration.hasOwnProperty(ReelsOverlayComponent.configurationName)) {\n        //     Object.keys(slotConfig.componentsConfiguration[ReelsOverlayComponent.configurationName]).forEach(key => {\n        //         config[key] = slotConfig.componentsConfiguration[ReelsOverlayComponent.configurationName][key];\n        //     });\n        // }\n    }\n\n    public onRegisterDependencies(container: any): void {\n        super.onRegisterDependencies(container);\n        this.dependencyContainer.register(\n            'ReelsOverlay',\n            { useClass: ReelsOverlayView },\n            { lifecycle: Lifecycle.Singleton },\n        );\n\n        if (this.config) {\n            this.dependencyContainer.register(\n                'ReelsOverlayComponentConfiguration',\n                { useClass: this.config(ReelsOverlayComponentConfigurationFactory()) },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        } else {\n            this.dependencyContainer.register(\n                'ReelsOverlayComponentConfiguration',\n                { useClass: ReelsOverlayComponentConfigurationFactory() },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n    }\n\n    public onResolveDependencies(container: any): void {\n        super.onResolveDependencies(container);\n\n        this.rootView = this.dependencyContainer.resolve('RootView');\n        this.reelsOverlayView = this.dependencyContainer.resolve('ReelsOverlay');\n        // this.reelsOverlayView.zIndex = ZOrders.UI_LEVEL + 1;\n        // this.rootView.addChild(this.reelsOverlayView);\n    }\n}\n","import { BaseComponentConfiguration } from '@egt/core';\nimport { IReelsOverlayComponentConfiguration } from './IReelsOverlayComponentConfiguration';\n\nexport default class ReelsOverlayComponentConfiguration extends BaseComponentConfiguration {}\n\nexport function ReelsOverlayComponentConfigurationFactory(\n    ClassType: typeof ReelsOverlayComponentConfiguration = ReelsOverlayComponentConfiguration,\n): typeof ReelsOverlayComponentConfiguration {\n    class ReelsOverlayComponentConfigurationInternal extends ClassType implements IReelsOverlayComponentConfiguration {\n        public x: number = 0;\n        public y: number = 0;\n    }\n\n    return ReelsOverlayComponentConfigurationInternal;\n}\n","enum ReelsOverlayZOrders {\n    // ----------------------------------------------\n    LINES = -100,\n    BASE_LEVEL = 0,\n    BACKGROUND_ANIMATIONS = 100,\n    BELL_LINK_ELEMENTS = 150,\n    PANEL_BACKGROUND = 150,\n    REELS_FRAMES = 200,\n}\n\nexport default ReelsOverlayZOrders;\n","import ReelsOverlayComponent from './ReelsOverlayComponent';\n\nimport { IReelsOverlayComponentConfiguration } from './configuration/IReelsOverlayComponentConfiguration';\nimport ReelsOverlayComponentConfiguration, {\n    ReelsOverlayComponentConfigurationFactory,\n} from './configuration/ReelsOverlayComponentConfiguration';\nimport ReelsOverlayZOrders from './enums/ReelsOverlayZOrders';\nimport ReelsOverlayView from './views/ReelsOverlayView';\n\nexport {\n    IReelsOverlayComponentConfiguration,\n    ReelsOverlayComponentConfiguration,\n    ReelsOverlayComponentConfigurationFactory,\n    ReelsOverlayView,\n    ReelsOverlayZOrders,\n};\nexport default ReelsOverlayComponent;\n","import { ViewContainer } from '@egt/ui-lib';\nimport { injectable } from 'tsyringe';\n\n@injectable()\nexport default class ReelsOverlayView extends ViewContainer {\n    constructor() {\n        super();\n        this.sortableChildren = true;\n        this.name = 'ReelsOverlay';\n    }\n}\n","import Core, { BaseComponent, FeatureFlags } from '@egt/core';\nimport { InitialSettings, RootStore, ServerState, SlotComponents, ZOrders } from '@egt/slot';\nimport { Lifecycle } from 'tsyringe';\nimport SettingsPopupComponentConfiguration, {\n    settingsPopUpConfigFactory,\n} from './configuration/SettingsPopupComponentConfiguration';\nimport SettingsPopupController from './controllers/SettingsPopupController';\nimport SettingsPopupControllerDesktop from './controllers/SettingsPopupControllerDesktop';\nimport BetSettingsView from './settings-views/bet/BetSettingsView';\nimport BetSettingsViewDesktop from './settings-views/bet/BetSettingsViewDesktop';\nimport GeneralSettingsView from './settings-views/general/GeneralSettingsView';\nimport GeneralSettingsViewDesktop from './settings-views/general/GeneralSettingsViewDesktop';\nimport HelpView from './settings-views/help/HelpView';\nimport PaytableHTMLView from './settings-views/paytableHTML/PaytableHTMLView';\nimport PaytableScript from './settings-views/paytableHTML/PaytableScript';\nimport SpinSettingsView from './settings-views/spin/SpinSettingsView';\nimport SpinSettingsViewDesktop from './settings-views/spin/SpinSettingsViewDesktop';\nimport SettingsPopupSubjects from './subjects/SettingsPopupSubjects';\nimport SettingsPopup from './views/SettingsPopup';\nimport SettingsPopupDesktop from './views/SettingsPopupDesktop';\nimport SettingsTab from './enums/SettingsTab';\nimport { BetButtonsViewOneDenom } from '@egt/bet-buttons';\nimport OneDenomBetSettingsView from './settings-views/bet/OneDenomBetSettingsView';\nimport { BetCalculatorViewDefault } from '@egt/bet-calculator';\nimport { ISettingsPopupComponentConfiguration } from './interfaces/SettingsInterfaces';\nimport { SpinSettingsNumericInputView } from '.';\nimport { DenominationPopupModes } from '@egt/denomination-popup';\nimport { AutoplayPopupModes } from '@egt/autoplay-popup';\n\nexport default class SettingsPopupComponent extends BaseComponent {\n    public static configurationName = 'SettingsPopupComponent';\n\n    public settingsPopup: SettingsPopup;\n    public betCalculator: BetCalculatorViewDefault;\n    public generalSettingsView: GeneralSettingsView;\n    public betSettingsView: BetSettingsView | BetButtonsViewOneDenom;\n    public spinSettingsView: SpinSettingsView;\n    public paytableView: PaytableHTMLView;\n    public paytableScript: PaytableScript;\n    public settingsPopupController: SettingsPopupController;\n    public componentType = SlotComponents.SETTINGS_POPUP;\n    public configuration: ISettingsPopupComponentConfiguration;\n    public rootView;\n    private rootStore: RootStore;\n    private initialSettings: InitialSettings;\n\n    constructor(private config?: any) {\n        super();\n    }\n\n    public onAfterInitialRender(container: any): void {\n        super.onAfterInitialRender(container);\n\n        const hasPaytableOnLoadRequirement: boolean = Core.flags.isActive(FeatureFlags.USE_PAYTABLE_ON_LOAD);\n\n        if (this.initialSettings.state === ServerState.IDLE && hasPaytableOnLoadRequirement) {\n            this.rootStore.uiStore.SELECTED_SETTINGS_TAB.next(SettingsTab.INFO);\n            this.rootStore.subjects.OPEN_SETTINGS_POPUP.next();\n        }\n    }\n\n    public destroy(): void {\n        this.settingsPopupController.destroy();\n        // @ts-ignore\n        this.settingsPopupController = null;\n        // @ts-ignore\n        this.settingsPopup = null;\n        // @ts-ignore\n        this.generalSettingsView = null;\n        // @ts-ignore\n        this.betSettingsView = null;\n        // @ts-ignore\n        this.spinSettingsView = null;\n        // @ts-ignore\n        this.paytableView = null;\n        // @ts-ignore\n        this.paytableScript = null;\n        // @ts-ignore\n        this.betCalculator = null;\n        // Object.keys(this.configuration).forEach((key: string) => {\n        //     this.configuration[key] = null;\n        // });\n        (this.configuration as unknown as SettingsPopupComponentConfiguration).destroy();\n        // @ts-ignore\n        this.configuration = null;\n        // @ts-ignore\n        this.config = null;\n        // @ts-ignore\n        this.dependencyContainer = null;\n        // @ts-ignore\n        this.rootView = null;\n\n        super.destroy();\n    }\n\n    public onAfterGameConfigurationCreated(): void {\n        super.onAfterGameConfigurationCreated();\n        // const slotConfig: ISlotConfiguration = this.dependencyContainer.resolve('ISlotConfiguration');\n        this.configuration = this.dependencyContainer.resolve('SettingsPopupComponentConfiguration');\n        // if (slotConfig.componentsConfiguration.hasOwnProperty(SettingsPopupComponent.configurationName)) {\n        //     Object.keys(slotConfig.componentsConfiguration[SettingsPopupComponent.configurationName]).forEach(key => {\n        //         this.configuration[key] = slotConfig.componentsConfiguration[SettingsPopupComponent.configurationName][key];\n        //     });\n        // }\n    }\n\n    public onRegisterDependencies(container: any): void {\n        super.onRegisterDependencies(container);\n\n        this.dependencyContainer.register(\n            'SettingsPopupSubjects',\n            { useClass: SettingsPopupSubjects },\n            { lifecycle: Lifecycle.Singleton },\n        );\n\n        if (!this.dependencyContainer.isRegistered('PaytableSpecificScript')) {\n            this.dependencyContainer.register(\n                'PaytableSpecificScript',\n                { useClass: PaytableScript },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n\n        if (!this.dependencyContainer.isRegistered('PaytableHTMLView')) {\n            this.dependencyContainer.register(\n                'PaytableHTMLView',\n                { useClass: PaytableHTMLView },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n        if (!this.dependencyContainer.isRegistered('HelpView')) {\n            this.dependencyContainer.register('HelpView', { useClass: HelpView }, { lifecycle: Lifecycle.Singleton });\n        }\n\n        if (this.config) {\n            this.dependencyContainer.register(\n                'SettingsPopupComponentConfiguration',\n                this.config(settingsPopUpConfigFactory()),\n            );\n        } else {\n            this.dependencyContainer.register('SettingsPopupComponentConfiguration', settingsPopUpConfigFactory());\n        }\n\n        if (Core.hasComponent(SlotComponents.AUTOPLAY_POPUP, AutoplayPopupModes.NUMERIC)) {\n            this.dependencyContainer.register(\n                'SpinSettingsView',\n                { useClass: SpinSettingsNumericInputView },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n    }\n\n    public onRegisterMobileDependencies(container: any): void {\n        super.onRegisterMobileDependencies(container);\n        if (!this.dependencyContainer.isRegistered('SettingsPopup')) {\n            this.dependencyContainer.register(\n                'SettingsPopup',\n                { useClass: SettingsPopup },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n        if (!this.dependencyContainer.isRegistered('SpinSettingsView')) {\n            this.dependencyContainer.register(\n                'SpinSettingsView',\n                { useClass: SpinSettingsView },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n\n        if (!this.dependencyContainer.isRegistered('GeneralSettingsView')) {\n            this.dependencyContainer.register(\n                'GeneralSettingsView',\n                { useClass: GeneralSettingsView },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n\n        this.registerBetSettingsView(BetSettingsView);\n\n        if (!this.dependencyContainer.isRegistered('SettingsPopupController')) {\n            this.dependencyContainer.register(\n                'SettingsPopupController',\n                { useClass: SettingsPopupController },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n    }\n\n    public onRegisterDesktopDependencies(container: any): void {\n        super.onRegisterDesktopDependencies(container);\n        if (!this.dependencyContainer.isRegistered('SettingsPopup')) {\n            this.dependencyContainer.register(\n                'SettingsPopup',\n                { useClass: SettingsPopupDesktop },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n\n        if (!this.dependencyContainer.isRegistered('SpinSettingsView')) {\n            this.dependencyContainer.register(\n                'SpinSettingsView',\n                { useClass: SpinSettingsViewDesktop },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n        if (!this.dependencyContainer.isRegistered('GeneralSettingsView')) {\n            this.dependencyContainer.register(\n                'GeneralSettingsView',\n                { useClass: GeneralSettingsViewDesktop },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n\n        this.registerBetSettingsView(BetSettingsViewDesktop);\n\n        if (!this.dependencyContainer.isRegistered('SettingsPopupController')) {\n            this.dependencyContainer.register(\n                'SettingsPopupController',\n                { useClass: SettingsPopupControllerDesktop },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n    }\n\n    public onResolveDependencies(container: any): void {\n        super.onResolveDependencies(container);\n\n        // to do: remove this - this view component must be injected dynamicaly on popup component\n        this.rootView = this.dependencyContainer.resolve('RootView');\n        this.generalSettingsView = this.dependencyContainer.resolve('GeneralSettingsView');\n        this.betSettingsView = this.dependencyContainer.resolve('BetSettingsView');\n        this.spinSettingsView = this.dependencyContainer.resolve('SpinSettingsView');\n        this.paytableView = this.dependencyContainer.resolve('PaytableHTMLView');\n        this.settingsPopup = this.dependencyContainer.resolve('SettingsPopup');\n        this.settingsPopupController = this.dependencyContainer.resolve('SettingsPopupController');\n        this.settingsPopup.zIndex = ZOrders.POPUP_LEVEL;\n        this.rootView.addChild(this.settingsPopup);\n        this.rootStore = this.dependencyContainer.resolve('RootStore');\n        this.initialSettings = this.dependencyContainer.resolve('InitialSettings');\n    }\n\n    public onInit(): void {\n        this.settingsPopup.init();\n        this.settingsPopupController.init();\n    }\n\n    public onInitComplete(): void {\n        this.settingsPopup.initComplete();\n    }\n\n    private registerBetSettingsView(view: any): void {\n        if (!this.dependencyContainer.isRegistered('BetSettingsView')) {\n            if (Core.gameDependencyContainer.isRegistered('InitialSettings')) {\n                const initialSettings: InitialSettings = this.dependencyContainer.resolve('InitialSettings');\n\n                this.configuration = this.dependencyContainer.resolve('SettingsPopupComponentConfiguration');\n\n                if (\n                    initialSettings.bets.length > this.configuration.betCalculatorProps.betPerRow ||\n                    Core.hasComponent(SlotComponents.DENOMINATION_POPUP, DenominationPopupModes.EXTENDED)\n                ) {\n                    this.dependencyContainer.register(\n                        'BetSettingsView',\n                        { useClass: OneDenomBetSettingsView },\n                        { lifecycle: Lifecycle.Singleton },\n                    );\n                } else {\n                    this.dependencyContainer.register(\n                        'BetSettingsView',\n                        { useClass: view },\n                        { lifecycle: Lifecycle.Singleton },\n                    );\n                }\n            }\n        }\n    }\n\n    // public onInitialRender(container: any): void {\n    //     super.onInitialRender(container);\n    // }\n}\n","import Core, { AddPriority, BaseComponentConfiguration, DefaultValue, DynamicPositionObject } from '@egt/core';\nimport { FooterBackgroundModes } from '@egt/footer-background';\nimport { SlotComponents, SlotGameLayouts } from '@egt/slot';\nimport {\n    AutoAlign,\n    IBalanceAndBetTextNumeric,\n    IBetButtonsBuyBonusConfig,\n    IBetButtonsConfig,\n    IContainerGraphicsInterfaceNumeric,\n    IInputFieldObject,\n    IKeyboardButtonPositionNumeric,\n    IKeyboardButtonsContainerPositionNumeric,\n    IKeyboardButtonTextConfigNumeric,\n    IKeyboardContainerPositionNumeric,\n    IKeyboardRowPositionNumeric,\n    IKeyboardScaleConfigNumeric,\n    IKeyboardShadowBackgroundConfigNumeric,\n    IPopUpCancelButtonInterface,\n    IPopUpDoneButtonInterface,\n    TextAlign,\n} from '@egt/ui-lib';\nimport { UIViewModes } from '@egt/ui-view';\nimport { IPointData, TextStyle } from 'pixi.js';\nimport {\n    IAutoplayNumericInputsViewProps,\n    IAutoplayViewInterface,\n    IBetCalculatorInterface,\n    IBetViewInterface,\n    IButtonsBlockerInterface,\n    IGeneralSettingsInterface,\n    IHelpViewInterface,\n    IMenuBetButton,\n    IOneDenomBetViewInterface,\n    IPaytableViewInterface,\n    ISettingsBackgroundInterface,\n    ISettingsBarInterface,\n    ISettingsHeaderBackgroundInterface,\n    ISettingsHeaderBottomLineInterface,\n    ISettingsHeaderTopLineInterface,\n    ISettingsMenuCover,\n    ISettingsPopupComponentConfiguration,\n    ISettingsPopupInterface,\n    ISettingsTabNameInterface,\n    IValueField,\n} from '../interfaces/SettingsInterfaces';\n\nexport default class SettingsPopupComponentConfiguration extends BaseComponentConfiguration {\n    public betButtonsConfigs: DynamicPositionObject<IBetButtonsConfig> & IBetButtonsConfig;\n}\n\nexport function settingsPopUpConfigFactory(): any {\n    class SettingsPopupComponentConfigurationInternalClass\n        extends SettingsPopupComponentConfiguration\n        implements ISettingsPopupComponentConfiguration\n    {\n        /////// MAIN SETTINGS POPUP PROPS ///////\n        @AddPriority<ISettingsPopupInterface>([\n            {\n                priorityType: { feature: SlotComponents.FOOTER_BACKGROUND, mode: FooterBackgroundModes.BLURRED },\n                priority: 3,\n                value: {\n                    defaults: {\n                        backgroundOverlay: {\n                            enabled: true,\n                            texture: 'menuSettingsPortraitInner.png',\n                            x: 235,\n                            y: 1275,\n                            visible: true,\n                        },\n                        menuTopOffset: 214,\n                    },\n                },\n            },\n        ])\n        @DefaultValue<ISettingsPopupInterface>({\n            defaults: {\n                bottomHeight: 122,\n                topOffset: 0,\n                bottomOffset: 100,\n                menuTopOffset: 214,\n                assetId: 'miscellaneous',\n                isInteractive: false,\n                backgroundOverlay: { enabled: false, texture: '', x: 0, y: 0, visible: false },\n            },\n            landscape: {\n                topOffset: 96,\n            },\n            desktop: {\n                isInteractive: true,\n            },\n        })\n        public popupProps: DynamicPositionObject<ISettingsPopupInterface> & ISettingsPopupInterface;\n\n        @DefaultValue<ISettingsBackgroundInterface>({\n            defaults: {\n                x: 0,\n                y: -30,\n                backgroundColor: 0x000000,\n                backgroundAlpha: 1,\n            },\n            landscape: {\n                y: -96,\n            },\n        })\n        public backgroundProps: DynamicPositionObject<ISettingsBackgroundInterface> & ISettingsBackgroundInterface;\n\n        @DefaultValue<ISettingsHeaderBackgroundInterface>({\n            defaults: {\n                useTexture: false,\n                backgroundTexture: 'settingsTitleBackgroundPortrait.png',\n                headerColor: 0x141414,\n                headerHeight: 55,\n                headerBoundsWidthOffset: 200,\n                headerBoundsHeightOffset: 20,\n            },\n            landscape: {\n                backgroundTexture: 'settingsTitleBackgroundLandscape.png',\n                headerBoundsWidthOffset: 0,\n                headerBoundsHeightOffset: 0,\n            },\n            desktop: {\n                backgroundTexture: 'settingsTitleBackgroundLandscape.png',\n                headerHeight: 48,\n            },\n        })\n        public headerBackgroundProps: DynamicPositionObject<ISettingsHeaderBackgroundInterface> &\n            ISettingsHeaderBackgroundInterface;\n\n        @DefaultValue<ISettingsHeaderTopLineInterface>({\n            defaults: {\n                height: 1,\n                color: 0x666666,\n            },\n        })\n        public headerTopLineProps: DynamicPositionObject<ISettingsHeaderTopLineInterface> &\n            ISettingsHeaderTopLineInterface;\n\n        @DefaultValue<ISettingsHeaderBottomLineInterface>({\n            defaults: {\n                height: 1,\n                color: 0x3f3f3f,\n            },\n        })\n        public headerBottomLineProps: DynamicPositionObject<ISettingsHeaderBottomLineInterface> &\n            ISettingsHeaderBottomLineInterface;\n\n        @DefaultValue<ISettingsTabNameInterface>({\n            defaults: {\n                textStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fontSize: 32,\n                    padding: 5,\n                }),\n                minFontSize: 12,\n                useTextConfig: true,\n            },\n            desktop: {\n                textStyle: new TextStyle({\n                    fill: '#CFCFCF',\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fontSize: 24,\n                }),\n            },\n        })\n        public tabNameProps: DynamicPositionObject<ISettingsTabNameInterface> & ISettingsTabNameInterface;\n\n        @AddPriority<ISettingsBarInterface>([\n            {\n                priorityType: { feature: SlotComponents.FOOTER_BACKGROUND, mode: FooterBackgroundModes.BLURRED },\n                priority: 3,\n                value: {\n                    defaults: {\n                        settingsSpriteYOffset: 24,\n                        yOffset: 24,\n                    },\n                },\n            },\n            {\n                priorityType: { feature: SlotComponents.UI_VIEW, mode: UIViewModes.TURTLE },\n                priority: 4,\n                value: {\n                    defaults: {\n                        settingsSpriteYOffset: 24,\n                        yOffset: 24,\n                        haveBetButton: false,\n                        haveSpinButton: false,\n                    },\n                },\n            },\n        ])\n        @DefaultValue<ISettingsBarInterface>({\n            defaults: {\n                yOffset: 22,\n                settingsBackgroundTexture: 'menuSettingsPortrait.png',\n                settingsBackgroundInteractive: true,\n                settingsSpriteYOffset: 20,\n                buttonsSpacing: 150,\n                betButtonTextures: { onTexture: 'svgBetSettingsOn', offTexture: 'svgBetSettingsOff' },\n                generalButtonTextures: { onTexture: 'svgGeneralSettingsOn', offTexture: 'svgGeneralSettingsOff' },\n                spinButtonTextures: { onTexture: 'svgAutoPlaySettingsOn', offTexture: 'svgAutoPlaySettingsOff' },\n                helpButtonTextures: { onTexture: 'svgHelpOn', offTexture: 'svgHelpOff' },\n                infoButtonTextures: { onTexture: 'svgInfoOn', offTexture: 'svgInfoOff' },\n                haveBetButton: true,\n                haveGeneralButton: true,\n                haveSpinButton: true,\n                haveHelpButton: true,\n                haveInfoButton: true,\n            },\n            landscape: {\n                yOffset: 0,\n                settingsBackgroundTexture: 'menuSettingsLandscape.png',\n                settingsBackgroundInteractive: false,\n                settingsSpriteYOffset: 0,\n            },\n        })\n        public settingsBarProps: DynamicPositionObject<ISettingsBarInterface> & ISettingsBarInterface;\n\n        @DefaultValue<IButtonsBlockerInterface>({\n            defaults: {\n                blockerOffset: 150,\n                backgroundColor: 0x000000,\n                backgroundAlpha: 0.0001,\n            },\n        })\n        public blockerProps: DynamicPositionObject<IButtonsBlockerInterface> & IButtonsBlockerInterface;\n\n        /////// GENERAL SETTINGS PROPS ///////\n        @AddPriority<IGeneralSettingsInterface>([\n            {\n                priorityType: { feature: SlotComponents.BACKGROUND_SOUND },\n                priority: 0,\n                value: {\n                    defaults: {\n                        hasBackgroundMusicContainer: true,\n                    },\n                },\n            },\n        ])\n        @DefaultValue<IGeneralSettingsInterface>({\n            defaults: {\n                x: -18,\n                y: 10,\n                // Container\n                containersInitialY: 100,\n                containersYOffset: 12,\n                containerBaseWidth: 729,\n                containerBaseHeight: 122,\n                containerPadding: 13,\n                leftContainerInitialXOffset: 50,\n                rightContainerInitialXOffset: 50,\n                // Button\n                buttonsXOffset: 560,\n                buttonsYOffset: 0,\n                toggleButtonTextures: ['svgToggleActive', 'svgToggleInactive'],\n                // Texts\n                textStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fontSize: 31,\n                }),\n                italicTextStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'FuturaPT-Book, Arial, sans-serif',\n                    fontSize: 28,\n                    lineHeight: 30,\n                    wordWrap: true,\n                }),\n                textsWrapBounds: 460,\n                titleTextWrapBounds: 500,\n                explainTextsWrapBounds: 500,\n                explainTextsYOffset: 10,\n                // Optional Containers\n                hasBackgroundMusicContainer: false,\n                hasLeftHandModeContainer: Core.gameLayout === SlotGameLayouts.TURTLE ? false : true,\n                hasDesktopView: true,\n                // History\n                historyButtonTexture: 'historyOn',\n                // Icon\n                iconXOffset: 8,\n                iconWidth: 54,\n                iconHeight: 54,\n                // Background\n                backgroundFillXOffset: 10,\n                backgroundFillYOffset: 18,\n                generalXOffset: 10,\n            },\n            landscape: {\n                x: 13,\n                y: -6,\n                // Container\n                containersInitialY: 0,\n                containersYOffset: 8,\n                containerBaseWidth: 658,\n                leftContainerInitialXOffset: 18,\n                rightContainerInitialXOffset: 684,\n                // Button\n                buttonsXOffset: 470,\n                // Texts\n                textsWrapBounds: 480,\n                titleTextWrapBounds: 430,\n                explainTextsWrapBounds: 440,\n            },\n            desktop: {\n                // Container\n                containersInitialY: 70,\n                containersYOffset: 8,\n                containerBaseWidth: 768,\n                containerBaseHeight: 68,\n                leftContainerInitialXOffset: 31,\n                // Texts\n                textStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fontSize: 21,\n                }),\n                italicTextStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'FuturaPT-Book, Arial, sans-serif',\n                    fontSize: 19,\n                    lineHeight: 20,\n                    wordWrap: true,\n                }),\n                textsWrapBounds: 600,\n                titleTextWrapBounds: 560,\n                explainTextsWrapBounds: 560,\n                explainTextsYOffset: 6,\n                // Optional Containers\n                hasLeftHandModeContainer: false,\n                // Icon\n                iconWidth: 36,\n                iconHeight: 36,\n            },\n        })\n        public generalSettingsProps: DynamicPositionObject<IGeneralSettingsInterface> & IGeneralSettingsInterface;\n\n        /////// HELP VIEW ///////\n        @AddPriority<IHelpViewInterface>([\n            {\n                priorityType: { feature: SlotComponents.BACKGROUND_SOUND },\n                priority: 0,\n                value: {\n                    defaults: { hasBackgroundMusic: true },\n                },\n            },\n            {\n                priorityType: { feature: SlotComponents.FOOTER_BACKGROUND, mode: FooterBackgroundModes.BLURRED },\n                priority: 3,\n                value: {\n                    defaults: {\n                        hasBackgroundMusic: Core.hasComponent(SlotComponents.BACKGROUND_SOUND),\n                        buttonsHeight: 124,\n                    },\n                    landscape: {\n                        buttonsHeight: 104,\n                    },\n                    desktop: {\n                        buttonsHeight: 104,\n                    },\n                },\n            },\n        ])\n        @DefaultValue<IHelpViewInterface>({\n            defaults: {\n                showDesktopVersion: false,\n                widthBounds: 0,\n                heightBounds: 0,\n                viewTopOffset: 0,\n                headerHeight: 60,\n                buttonsHeight: 122,\n                bottomHeight: 120,\n                offsetX: 6,\n                fontSize: 28,\n                offsetY: 0,\n                heightReduce: 0,\n                widthReduce: 0,\n                hasBackgroundMusic: false,\n                additionalHeaderHeightOffsetY: 0,\n                useNonLinearBetTitles: false,\n            },\n            landscape: {\n                bottomHeight: 0,\n                fontSize: 18,\n            },\n            desktop: {\n                showDesktopVersion: true,\n                widthBounds: 804,\n                heightBounds: 546,\n                viewTopOffset: 84,\n                headerHeight: 48,\n                fontSize: 12,\n                offsetY: 2,\n                widthReduce: 4,\n                heightReduce: 12,\n                additionalHeaderHeightOffsetY: 2,\n            },\n        })\n        public helpViewProps: DynamicPositionObject<IHelpViewInterface> & IHelpViewInterface;\n\n        @AddPriority<IPaytableViewInterface>([\n            {\n                priorityType: { feature: SlotComponents.FOOTER_BACKGROUND, mode: FooterBackgroundModes.BLURRED },\n                priority: 3,\n                value: {\n                    defaults: {\n                        buttonsHeight: 126,\n                    },\n                    landscape: {\n                        buttonsHeight: 104,\n                    },\n                    desktop: {\n                        buttonsHeight: 104,\n                    },\n                },\n            },\n        ])\n        @DefaultValue<IPaytableViewInterface>({\n            defaults: {\n                showDesktopVersion: false,\n                widthBounds: 0,\n                heightBounds: 0,\n                viewTopOffset: 0,\n                headerHeight: 57,\n                additionalHeaderHeightOffsetY: 0,\n                buttonsHeight: 122,\n                bottomHeight: 120,\n                fontSize: 18,\n                // offsetY: 0,\n                heightReduce: 0,\n                widthReduce: 0,\n            },\n            landscape: {\n                bottomHeight: 0,\n            },\n            desktop: {\n                showDesktopVersion: true,\n                widthBounds: 804,\n                heightBounds: 546,\n                viewTopOffset: 84,\n                headerHeight: 48,\n                additionalHeaderHeightOffsetY: 2,\n                heightReduce: 12,\n                widthReduce: 4,\n                // offsetY: 2,\n                fontSize: 10.8,\n            },\n        })\n        public paytableViewProps: DynamicPositionObject<IPaytableViewInterface> & IPaytableViewInterface;\n\n        @DefaultValue<IAutoplayViewInterface>({\n            defaults: {\n                sliderContainerWidth: 600,\n                sliderContainerHeight: 60,\n                sliderWidth: 540,\n                sliderHeight: 6,\n                sliderTopOffset: 20,\n                textTopOffset: 80,\n                slidersValuesColor: 0x7cc810,\n                slidersNotSelectedColor: 0x585858,\n                slidersSelectedColor: 0x6ba717,\n                useTexturesForDots: false,\n                useCanvasForSliders: false,\n                canvasSlidersNumberOfStops: 0,\n                canvasNotSelectedSliderStops: [],\n                canvasSelectedSliderStops: [],\n                canvasNotSelectedSlidersColors: [],\n                canvasSelectedSlidersColors: [],\n                inactiveDotTexture: '',\n                activeDotTexture: '',\n                inactiveHandleTexture: ['svgRedAuto', 'svgGreyAuto'],\n                activeHandleTexture: 'svgGreenAuto',\n                valuesWidthDevider: 5.5,\n                headersWidthDevider: 2,\n                ///// TEXT STYLES /////\n                zeroValueStyle: new TextStyle({\n                    fill: '#595959',\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fontSize: 22,\n                }),\n                mandatorySignStyle: new TextStyle({\n                    fill: '#FF0000',\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fontSize: 48,\n                }),\n                spinsStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fontSize: 36,\n                }),\n                spinsValueStyle: new TextStyle({\n                    fill: '#6AAF08',\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fontSize: 36,\n                }),\n                decreaseStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'FuturaPT-Book, Arial, sans-serif',\n                    fontSize: 34,\n                }),\n                decreaseValueStyle: new TextStyle({\n                    fill: '#6AAF08',\n                    fontFamily: 'FuturaPT-Book, Arial, sans-serif',\n                    fontSize: 34,\n                }),\n                increaseStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'FuturaPT-Book, Arial, sans-serif',\n                    fontSize: 34,\n                }),\n                increaseValueStyle: new TextStyle({\n                    fill: '#6AAF08',\n                    fontFamily: 'FuturaPT-Book, Arial, sans-serif',\n                    fontSize: 34,\n                }),\n                singleWinStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'FuturaPT-Book, Arial, sans-serif',\n                    fontSize: 34,\n                }),\n                singleWinValueStyle: new TextStyle({\n                    fill: '#6AAF08',\n                    fontFamily: 'FuturaPT-Book, Arial, sans-serif',\n                    fontSize: 34,\n                }),\n                startButtonTextStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fontSize: 50,\n                }),\n                balanceTextStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fontSize: 22,\n                    padding: 3,\n                }),\n                betTextStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fontSize: 22,\n                    padding: 3,\n                }),\n                betValueStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fontSize: 22,\n                }),\n                balanceValueStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fontSize: 22,\n                }),\n                stopOnStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fontSize: 35,\n                }),\n\n                ///// TEXT CONFIGS /////\n                mandatorySignConfig: {\n                    boundsWidth: 40,\n                    shouldFitInBounds: true,\n                    align: TextAlign.CENTER,\n                },\n                spinsConfig: {\n                    boundsWidth: 0,\n                    boundsHeight: 36,\n                    minFontSize: 16,\n                    shouldFitInBounds: true,\n                },\n                spinsValueConfig: {\n                    boundsWidth: 0,\n                    boundsHeight: 36,\n                    minFontSize: 17,\n                    shouldFitInBounds: true,\n                    align: TextAlign.RIGHT,\n                },\n                decreaseConfig: {\n                    boundsWidth: 0,\n                    boundsHeight: 34,\n                    minFontSize: 16,\n                    shouldFitInBounds: true,\n                },\n                increaseConfig: {\n                    boundsWidth: 0,\n                    boundsHeight: 34,\n                    minFontSize: 16,\n                    shouldFitInBounds: true,\n                },\n                singleWinConfig: {\n                    boundsWidth: 0,\n                    boundsHeight: 34,\n                    minFontSize: 16,\n                    shouldFitInBounds: true,\n                },\n                noLimitConfig: {\n                    boundsWidth: 0,\n                    boundsHeight: 22,\n                    minFontSize: 14,\n                    moneyFontSize: 30,\n                    align: TextAlign.RIGHT,\n                },\n                startButtonTextConfig: {\n                    boundsWidth: 20,\n                    boundsHeight: 50,\n                    minFontSize: 30,\n                    shouldFitInBounds: true,\n                    align: TextAlign.CENTER,\n                },\n                limitsValuesConfig: {\n                    boundsWidth: 0,\n                    boundsHeight: 28,\n                    minFontSize: 14,\n                    shouldFitInBounds: true,\n                    align: TextAlign.RIGHT,\n                    shouldHideWhenMoneyValueIsZero: true,\n                    useMoneyMode: true,\n                    moneyFontSize: 28,\n                    centsFontSize: 28,\n                    currencyFontSize: 14,\n                },\n                balanceValueConfig: {\n                    boundsWidth: 0,\n                },\n                betValueConfig: {\n                    boundsWidth: 0,\n                },\n\n                stopOnTextX: 90,\n                stopOnTextY: 80,\n                balanceDecreaseTextX: 100,\n                balanceDecreaseTextY: 140,\n                balanceDecreaseValueX: 520,\n                balanceDecreaseValueY: 140,\n                sliderContainersX: 0,\n                // lossSliderContainerX: 0,\n                balanceIncreaseTextX: 100,\n                balanceIncreaseValueX: 520,\n                // winsSliderContainerX: 0,\n                singleWinLimitTextX: 100,\n                singleWinLimitValueX: 520,\n                // singleWinSliderContainerX: 0,\n                numberOfSpinsTextX: 90,\n                numberOfSpinsTextY: 130,\n                numberOfSpinsValueDevider: 5,\n                numberOfSpinsValueX: 500,\n                numberOfSpinsValueY: 130,\n                infinityValueTextureX: 160,\n                infinityValueTextureY: -4,\n                // spinsSliderContainerX: 0,\n                spinsSliderContainerY: 30,\n                startAutoplayButtonX: 0,\n                startAutoplayButtonY: 48,\n                startButtonTextX: 10,\n                // startButtonTextY: 8,\n                startButtonTextActiveAlpha: 1,\n                startButtonTextInactiveAlpha: 0.6,\n                balanceTextX: 0,\n                balanceTextY: 0,\n                balanceValueX: 0,\n                balanceValueY: 0,\n                balanceContainerX: 50,\n                balanceContainerY: 1060,\n                betTextX: 0,\n                betTextY: 0,\n                betValueX: 0,\n                betValueY: 0,\n                betContainerX: 715,\n                betContainerY: 0,\n                balanceDecreaseZeroValueX: 0,\n                balanceDecreaseZeroValueY: 0,\n                balanceIncreaseZeroValueX: 0,\n                balanceIncreaseZeroValueY: 0,\n                singleWinZeroValueX: 0,\n                singleWinZeroValueY: 0,\n                decreaseMandatorySignX: 0,\n                decreaseMandatorySignY: -5,\n                increaseMandatorySignX: 0,\n                increaseMandatorySignY: -5,\n                winMandatorySignX: 0,\n                winMandatorySignY: -5,\n                startAutoplayButtonTextures: [\n                    'svgStartButton',\n                    'svgStartButton',\n                    'svgStartButton',\n                    'svgStartButtonInactive',\n                ],\n                infinityValueTexture: 'svgInfinityBoldedSelected',\n                valueButtonsTextStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fontSize: 23,\n                }),\n                // windowTitleTextStyleDesktop: new TextStyle({\n                //     fill: '#CFCFCF',\n                //     fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                //     fontSize: 24,\n                // }),\n            },\n            landscape: {\n                valuesWidthDevider: 8.5,\n                headersWidthDevider: 3.5,\n                noLimitConfig: {\n                    boundsWidth: 0,\n                    boundsHeight: 22,\n                    minFontSize: 14,\n                    moneyFontSize: 28,\n                    align: TextAlign.RIGHT,\n                },\n                stopOnTextX: 65,\n                stopOnTextY: -20,\n                balanceDecreaseTextX: 65,\n                balanceDecreaseTextY: 30,\n                balanceDecreaseValueX: 480,\n                balanceDecreaseValueY: 30,\n                sliderContainersX: 55,\n                // lossSliderContainerX: 55,\n                balanceIncreaseTextX: 65,\n                balanceIncreaseValueX: 480,\n                // winsSliderContainerX: 55,\n                singleWinLimitTextX: 65,\n                singleWinLimitValueX: 480,\n                // singleWinSliderContainerX: 55,\n                numberOfSpinsTextX: 45,\n                numberOfSpinsTextY: 30,\n                numberOfSpinsValueDevider: 10,\n                numberOfSpinsValueX: 215,\n                numberOfSpinsValueY: 30,\n                infinityValueTextureX: 130,\n                // spinsSliderContainerX: 55,\n                startAutoplayButtonX: 865,\n                startAutoplayButtonY: 106,\n                balanceContainerX: 45,\n                balanceContainerY: 0,\n                betContainerX: 1280,\n            },\n            desktop: {\n                textTopOffset: 52,\n                zeroValueStyle: new TextStyle({\n                    fill: '#595959',\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fontSize: 20,\n                }),\n                mandatorySignStyle: new TextStyle({\n                    fill: '#FF0000',\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fontSize: 22,\n                }),\n                spinsStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'FuturaPT-Book, Arial, sans-serif',\n                    fontSize: 16,\n                }),\n                decreaseStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'FuturaPT-Book, Arial, sans-serif',\n                    fontSize: 16,\n                }),\n                decreaseValueStyle: new TextStyle({\n                    fill: '#6AAF08',\n                    fontFamily: 'FuturaPT-Book, Arial, sans-serif',\n                    fontSize: 16,\n                }),\n                increaseStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'FuturaPT-Book, Arial, sans-serif',\n                    fontSize: 16,\n                }),\n                increaseValueStyle: new TextStyle({\n                    fill: '#6AAF08',\n                    fontFamily: 'FuturaPT-Book, Arial, sans-serif',\n                    fontSize: 16,\n                }),\n                singleWinStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'FuturaPT-Book, Arial, sans-serif',\n                    fontSize: 16,\n                }),\n                singleWinValueStyle: new TextStyle({\n                    fill: '#6AAF08',\n                    fontFamily: 'FuturaPT-Book, Arial, sans-serif',\n                    fontSize: 16,\n                }),\n                startButtonTextStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fontSize: 26,\n                }),\n            },\n        })\n        public autoplayViewProps: DynamicPositionObject<IAutoplayViewInterface> & IAutoplayViewInterface;\n\n        @DefaultValue<IAutoplayNumericInputsViewProps>({\n            defaults: {\n                mandatorySignStyle: new TextStyle({\n                    fill: '#FF0000',\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fontSize: 48,\n                }),\n                mandatorySignPosition: new DynamicPositionObject<IPointData>({\n                    defaults: { x: 5, y: -13 },\n                }),\n                sliderHandleDimensions: { width: 50, height: 50 },\n                spinSliderTopOffset: 22,\n                stopOnText: new DynamicPositionObject<IPointData>({\n                    defaults: { x: 47, y: -22 },\n                    portrait: { x: 48, y: 85 },\n                }),\n                spinsSliderContainerPosition: new DynamicPositionObject<IPointData>({\n                    defaults: { x: 765, y: -22 },\n                    portrait: { x: 94, y: 669 },\n                }),\n                startAutoplayButton: new DynamicPositionObject<IPointData>({\n                    defaults: { x: 909, y: 257 },\n                    portrait: { x: 238, y: 880 },\n                }),\n                inputFieldsContainer: new DynamicPositionObject<IPointData>({\n                    defaults: { x: 47, y: 43 },\n                    portrait: { x: 50, y: 149 },\n                }),\n                balanceField: new DynamicPositionObject<IValueField>({\n                    defaults: {\n                        textPosition: { x: 0, y: 0 },\n                        valuePostion: { x: 0, y: 0 },\n                        containerPosition: { x: 768, y: 488 },\n                    },\n                    portrait: {\n                        textPosition: { x: 0, y: 0 },\n                        valuePostion: { x: 0, y: 0 },\n                        containerPosition: { x: 50, y: 1060 },\n                    },\n                }),\n                betField: new DynamicPositionObject<IValueField>({\n                    defaults: {\n                        textPosition: { x: 0, y: 0 },\n                        valuePostion: { x: 0, y: 0 },\n                        containerPosition: { x: 1341, y: 488 },\n                    },\n                    portrait: {\n                        textPosition: { x: 0, y: 0 },\n                        valuePostion: { x: 0, y: 0 },\n                        containerPosition: { x: 715, y: 1060 },\n                    },\n                }),\n                settingsMenuCover: new DynamicPositionObject<ISettingsMenuCover>({\n                    defaults: {\n                        width: 765,\n                        height: 103,\n                        color: 0x000000,\n                        x: 0,\n                        y: 569,\n                    },\n                }),\n                maxLossAmountContainerConfig: new DynamicPositionObject<IInputFieldObject>({\n                    defaults: {\n                        containerX: 0,\n                        containerY: 0,\n                        fieldWidth: 235,\n                        fieldHeight: 60,\n                        fieldX: 427,\n                        fieldY: 2,\n                        titleX: 0,\n                        titleY: 9,\n                        underTitleX: -1,\n                        underTitleY: -7,\n                        errorFill: '#FF0000',\n                        titleTextStyle: new TextStyle({\n                            fontFamily: 'FuturaPT-Book, RobotoCondensed-Bold, Arial',\n                            fontSize: 30,\n                            fill: '#FFFFFF',\n                            trim: true,\n                        }),\n                        underTitleTextStyle: new TextStyle({\n                            fontFamily: 'FuturaPT-Book, RobotoCondensed-Bold, Arial',\n                            fontSize: 20,\n                            fill: '#8A8A8A',\n                            trim: true,\n                        }),\n                        fieldNormalTextStyle: new TextStyle({\n                            fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                            fontSize: 28,\n                            fill: '#FFFFFF',\n                        }),\n                        fieldHilightedTextStyle: new TextStyle({\n                            fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                            fontSize: 28,\n                            fill: '#FFD200',\n                        }),\n                        currencyNormaTextStyle: new TextStyle({\n                            fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                            fontSize: 20,\n                            fill: '#FFFFFF',\n                        }),\n                        currencyHilightedTextStyle: new TextStyle({\n                            fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                            fontSize: 20,\n                            fill: '#FFD200',\n                        }),\n                        titleTextMaxWidth: 425,\n                    },\n                }),\n\n                balanceLessThanContainerConfig: new DynamicPositionObject<IInputFieldObject>({\n                    defaults: {\n                        containerX: 0,\n                        containerY: 120,\n                        fieldWidth: 235,\n                        fieldHeight: 60,\n                        fieldX: 427,\n                        fieldY: 2,\n                        titleX: 0,\n                        titleY: 9,\n                        underTitleX: -1,\n                        underTitleY: -7,\n                        errorFill: '#FF0000',\n                        titleTextStyle: new TextStyle({\n                            fontFamily: 'FuturaPT-Book, RobotoCondensed-Bold, Arial',\n                            fontSize: 30,\n                            fill: '#FFFFFF',\n                            trim: true,\n                        }),\n                        underTitleTextStyle: new TextStyle({\n                            fontFamily: 'FuturaPT-Book, RobotoCondensed-Bold, Arial',\n                            fontSize: 20,\n                            fill: '#8A8A8A',\n                            trim: true,\n                        }),\n                        fieldNormalTextStyle: new TextStyle({\n                            fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                            fontSize: 28,\n                            fill: '#FFFFFF',\n                        }),\n                        fieldHilightedTextStyle: new TextStyle({\n                            fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                            fontSize: 28,\n                            fill: '#FFD200',\n                        }),\n                        currencyNormaTextStyle: new TextStyle({\n                            fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                            fontSize: 20,\n                            fill: '#FFFFFF',\n                        }),\n                        currencyHilightedTextStyle: new TextStyle({\n                            fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                            fontSize: 20,\n                            fill: '#FFD200',\n                        }),\n                        titleTextMaxWidth: 425,\n                    },\n                    portrait: {\n                        containerY: 120,\n                    },\n                }),\n\n                balanceMoreThanContainerConfig: new DynamicPositionObject<IInputFieldObject>({\n                    defaults: {\n                        containerX: 0,\n                        containerY: 240,\n                        fieldWidth: 235,\n                        fieldHeight: 60,\n                        fieldX: 427,\n                        fieldY: 2,\n                        titleX: 0,\n                        titleY: 9,\n                        underTitleX: -1,\n                        underTitleY: -7,\n                        errorFill: '#FF0000',\n                        titleTextStyle: new TextStyle({\n                            fontFamily: 'FuturaPT-Book, RobotoCondensed-Bold, Arial',\n                            fontSize: 30,\n                            fill: '#FFFFFF',\n                            trim: true,\n                        }),\n                        underTitleTextStyle: new TextStyle({\n                            fontFamily: 'FuturaPT-Book, RobotoCondensed-Bold, Arial',\n                            fontSize: 20,\n                            fill: '#8A8A8A',\n                            trim: true,\n                        }),\n                        fieldNormalTextStyle: new TextStyle({\n                            fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                            fontSize: 28,\n                            fill: '#FFFFFF',\n                        }),\n                        fieldHilightedTextStyle: new TextStyle({\n                            fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                            fontSize: 28,\n                            fill: '#FFD200',\n                        }),\n                        currencyNormaTextStyle: new TextStyle({\n                            fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                            fontSize: 20,\n                            fill: '#FFFFFF',\n                        }),\n                        currencyHilightedTextStyle: new TextStyle({\n                            fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                            fontSize: 20,\n                            fill: '#FFD200',\n                        }),\n                        titleTextMaxWidth: 425,\n                    },\n                    portrait: {\n                        containerY: 240,\n                    },\n                }),\n\n                winOverContainerConfig: new DynamicPositionObject<IInputFieldObject>({\n                    defaults: {\n                        containerX: 0,\n                        containerY: 360,\n                        fieldWidth: 235,\n                        fieldHeight: 60,\n                        fieldX: 427,\n                        fieldY: 2,\n                        titleX: 0,\n                        titleY: 9,\n                        underTitleX: -1,\n                        underTitleY: -7,\n                        errorFill: '#FF0000',\n                        titleTextStyle: new TextStyle({\n                            fontFamily: 'FuturaPT-Book, RobotoCondensed-Bold, Arial',\n                            fontSize: 30,\n                            fill: '#FFFFFF',\n                            trim: true,\n                        }),\n                        underTitleTextStyle: new TextStyle({\n                            fontFamily: 'FuturaPT-Book, RobotoCondensed-Bold, Arial',\n                            fontSize: 20,\n                            fill: '#8A8A8A',\n                            trim: true,\n                        }),\n                        fieldNormalTextStyle: new TextStyle({\n                            fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                            fontSize: 28,\n                            fill: '#FFFFFF',\n                        }),\n                        fieldHilightedTextStyle: new TextStyle({\n                            fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                            fontSize: 28,\n                            fill: '#FFD200',\n                        }),\n                        currencyNormaTextStyle: new TextStyle({\n                            fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                            fontSize: 20,\n                            fill: '#FFFFFF',\n                        }),\n                        currencyHilightedTextStyle: new TextStyle({\n                            fontFamily: 'FuturaPT, RobotoCondensed-Bold, Arial',\n                            fontSize: 20,\n                            fill: '#FFD200',\n                        }),\n                        titleTextMaxWidth: 425,\n                    },\n                    portrait: {\n                        containerY: 360,\n                    },\n                }),\n            },\n        })\n        public autoplayNumericInputsViewProps: DynamicPositionObject<IAutoplayNumericInputsViewProps> &\n            IAutoplayNumericInputsViewProps;\n        // ==============================\n        // KEYBOARD START\n        // ==============================\n        @DefaultValue<IPopUpDoneButtonInterface>({\n            defaults: {\n                x: 420,\n                y: 11,\n                width: 144,\n                height: 80,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, RobotoCondensed-Bold, Arial',\n                    fontSize: 25.5,\n                    fill: '#FFFFFF',\n                    align: 'center',\n                }),\n                scale: 1.334,\n            },\n            portrait: {\n                scale: 1.334,\n                x: 592,\n                y: 10,\n            },\n        })\n        public doneBtn: DynamicPositionObject<IPopUpDoneButtonInterface> & IPopUpDoneButtonInterface;\n\n        @DefaultValue<IPopUpCancelButtonInterface>({\n            defaults: {\n                x: 316,\n                y: 11,\n                width: 60,\n                height: 60,\n                scale: 1.334,\n            },\n            portrait: {\n                scale: 1.334,\n                x: 488,\n                y: 10,\n            },\n        })\n        public cancelBtn: DynamicPositionObject<IPopUpCancelButtonInterface> & IPopUpCancelButtonInterface;\n\n        @DefaultValue<IContainerGraphicsInterfaceNumeric>({\n            defaults: {\n                width: 595,\n                height: 710,\n                x: 0,\n                y: 0,\n                lineHeight: 1,\n                topLineX: 0,\n                topLineY: 0,\n                separatorLineX: 0,\n                separatorLineY: 100,\n            },\n            portrait: {\n                height: 495,\n                x: 0,\n                y: 0,\n                topLineX: 0,\n                topLineY: 0,\n                lineHeight: 1,\n                separatorLineX: 0,\n                separatorLineY: 99,\n            },\n        })\n        public autoPlayNumericContainerGraphicsConfig: DynamicPositionObject<IContainerGraphicsInterfaceNumeric> &\n            IContainerGraphicsInterfaceNumeric;\n\n        @DefaultValue<IKeyboardButtonTextConfigNumeric>({\n            defaults: {\n                width: 100,\n                height: 51,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    fontSize: 36,\n                    fill: '#FFFFFF',\n                    align: 'center',\n                }),\n            },\n        })\n        public numericKeyboardButtonText: DynamicPositionObject<IKeyboardButtonTextConfigNumeric> &\n            IKeyboardButtonTextConfigNumeric;\n\n        public numericKeyboardRowPositions: Array<DynamicPositionObject<IKeyboardRowPositionNumeric>> = [\n            new DynamicPositionObject<IKeyboardRowPositionNumeric>({\n                defaults: { x: 0, y: 0, width: 300, height: 51 },\n            }),\n            new DynamicPositionObject<IKeyboardRowPositionNumeric>({\n                defaults: { x: 0, y: 80, width: 300, height: 51 },\n            }),\n            new DynamicPositionObject<IKeyboardRowPositionNumeric>({\n                defaults: { x: 0, y: 160, width: 300, height: 51 },\n            }),\n            new DynamicPositionObject<IKeyboardRowPositionNumeric>({\n                defaults: { x: 0, y: 246, width: 300, height: 51 },\n            }),\n        ];\n\n        public numericKeyboardBtnPositions: Array<DynamicPositionObject<IKeyboardButtonPositionNumeric>> = [\n            new DynamicPositionObject<IKeyboardButtonPositionNumeric>({\n                defaults: { x: 0 },\n            }),\n            new DynamicPositionObject<IKeyboardButtonPositionNumeric>({\n                defaults: { x: 146 },\n            }),\n            new DynamicPositionObject<IKeyboardButtonPositionNumeric>({\n                defaults: { x: 292 },\n            }),\n        ];\n\n        public numericKeyboardButtonValues: string[][] = [\n            ['1', '2', '3'],\n            ['4', '5', '6'],\n            ['7', '8', '9'],\n            ['.', '0', '<'],\n        ];\n\n        @DefaultValue<IKeyboardButtonsContainerPositionNumeric>({\n            defaults: {\n                x: 107,\n                y: 239,\n            },\n            portrait: {\n                x: 193,\n                y: 121,\n            },\n        })\n        public numericKeyboardButtonsContainerPosition: DynamicPositionObject<IKeyboardButtonsContainerPositionNumeric> &\n            IKeyboardButtonsContainerPositionNumeric;\n\n        @DefaultValue<IKeyboardShadowBackgroundConfigNumeric>({\n            defaults: {\n                x: 0,\n                y: 761,\n                width: -260,\n                height: 619,\n            },\n            portrait: {\n                x: 0,\n                y: -260,\n                width: 765,\n                height: 619,\n            },\n        })\n        public numericKeyboardShadowBackground: DynamicPositionObject<IKeyboardShadowBackgroundConfigNumeric> &\n            IKeyboardShadowBackgroundConfigNumeric;\n\n        @DefaultValue<IKeyboardContainerPositionNumeric>({\n            defaults: {\n                x: 764,\n                y: -40,\n                leftHandX: 766,\n            },\n            portrait: {\n                x: 0,\n                y: 876,\n            },\n        })\n        public numericKeyboardContainerPosition: DynamicPositionObject<IKeyboardContainerPositionNumeric> &\n            IKeyboardContainerPositionNumeric;\n\n        @DefaultValue<IBalanceAndBetTextNumeric>({\n            defaults: {\n                x: 16,\n                y: 695,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFD200',\n                    fontSize: 24,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                valueStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 36,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                currencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 22,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n            },\n            portrait: {\n                x: 30,\n                y: 464,\n            },\n        })\n        public balanceTextKeyboard: IBalanceAndBetTextNumeric;\n\n        @DefaultValue<IBalanceAndBetTextNumeric>({\n            defaults: {\n                x: 557,\n                y: 695,\n                textStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFD200',\n                    fontSize: 24,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                valueStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 36,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                currencyStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 22,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n            },\n            portrait: {\n                x: 710,\n                y: 464,\n            },\n        })\n        public betTextKeyboard: IBalanceAndBetTextNumeric;\n\n        @DefaultValue<IKeyboardScaleConfigNumeric>({\n            defaults: { scale: 1.34 },\n        })\n        public numericKeyboardScale: DynamicPositionObject<IKeyboardScaleConfigNumeric> & IKeyboardScaleConfigNumeric;\n        // ==============================\n        // KEYBOARD END\n        // ==============================\n\n        @DefaultValue<IBetButtonsConfig>({\n            defaults: {\n                currency: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, Arial, sans-serif',\n                        fontSize: 18,\n                        fill: '#C6C5C5',\n                        letterSpacing: 0.9,\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, Arial, sans-serif',\n                        fontSize: 18,\n                        fill: '#FFD200',\n                        letterSpacing: 0.9,\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 3,\n                    bounds: { width: 100, height: 30 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                amount: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                        fontSize: 47,\n                        fill: '#C6C5C5', // '#FFFFFF'\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                        fontSize: 47,\n                        fill: '#FFFFFF',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 31,\n                    bounds: { width: 100, height: 34 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                label: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, Arial, sans-serif',\n                        fontSize: 22,\n                        fill: '#FFD200',\n                        padding: 5,\n                        letterSpacing: 0.6,\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, Arial, sans-serif',\n                        fontSize: 22,\n                        fill: '#FFD200',\n                        padding: 5,\n                        letterSpacing: 0.6,\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 63,\n                    bounds: { width: 100, height: 30 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                stamp: {\n                    hasStamp: false,\n                    x: 0,\n                    y: 0,\n                    width: 0,\n                    height: 0,\n                    alpha: 0,\n                    texture: { source: '', name: '' },\n                },\n                textures: ['svgBet', 'svgBetPressed', 'svgBet', 'svgBet'],\n                selectedTextures: [\n                    'svgActiveBetPressed',\n                    'svgActiveBetPressed',\n                    'svgActiveBetPressed',\n                    'svgActiveBetPressed',\n                ],\n                fakeMaskTexture: 'maxBet',\n                width: 120,\n                height: 96,\n            },\n            desktop: {\n                currency: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, Arial, sans-serif',\n                        fontSize: 14,\n                        fill: '#C6C5C5',\n                        letterSpacing: 0.7,\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, Arial, sans-serif',\n                        fontSize: 14,\n                        fill: '#FFD200',\n                        letterSpacing: 0.7,\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 4,\n                    bounds: { width: 78, height: 20 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                amount: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                        fontSize: 37,\n                        fill: '#C6C5C5', // '#FFFFFF'\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                        fontSize: 37,\n                        fill: '#FFFFFF',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 27,\n                    bounds: { width: 78, height: 20 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                label: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, Arial, sans-serif',\n                        fontSize: 17,\n                        fill: '#FFD200',\n                        padding: 5,\n                        letterSpacing: 0.5,\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'FuturaPT, Arial, sans-serif',\n                        fontSize: 17,\n                        fill: '#FFD200',\n                        padding: 5,\n                        letterSpacing: 0.5,\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 52,\n                    bounds: { width: 78, height: 17 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                textures: ['svgBet', 'svgBetPressed', 'svgBetHover', 'svgBet'],\n                selectedTextures: ['svgActiveBet', 'svgActiveBetPressed', 'svgActiveBetHover', 'svgActiveBet'],\n                width: 94,\n                height: 75,\n            },\n        })\n        public betButtonsConfigs: DynamicPositionObject<IBetButtonsConfig> & IBetButtonsConfig;\n\n        @DefaultValue<IBetButtonsBuyBonusConfig>({\n            defaults: {\n                textures: ['svgBet', 'svgBetPressed', 'svgBet', 'svgBet'],\n            },\n            desktop: {\n                textures: ['svgBet', 'svgBetPressed', 'svgBetHover', 'svgBet'],\n            },\n        })\n        public betButtonsBuyBonusTextures: DynamicPositionObject<IBetButtonsBuyBonusConfig> & IBetButtonsBuyBonusConfig;\n\n        public betButtons: Array<DynamicPositionObject<IMenuBetButton>> = [\n            new DynamicPositionObject<IMenuBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs },\n            }),\n            new DynamicPositionObject<IMenuBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs },\n            }),\n            new DynamicPositionObject<IMenuBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs },\n            }),\n            new DynamicPositionObject<IMenuBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs },\n            }),\n            new DynamicPositionObject<IMenuBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs },\n            }),\n        ];\n\n        @DefaultValue<IBetViewInterface>({\n            defaults: {\n                winlinesTextY: 110,\n                betsTextY: 364,\n                denominationsTextY: 617,\n                linesButtonsY: 162,\n                betButtonsY: 416,\n                denominationButtonsY: 670,\n                widthBounds: 0,\n                heightBounds: 0,\n                viewTopOffset: 0,\n                buttonsOffsetX: [8, 8, 8, 8, 8, 8],\n                buttonsOffsetY: 20,\n                balanceContainerX: 50,\n                balanceContainerY: 1060,\n                betContainerX: 715,\n                betContainerY: 1060,\n                firstButtonPositionsX: [325, 260, 196, 133, 70, 4],\n                denomButtonScale: [1, 1, 1, 1, 1, 1],\n                titleTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fontSize: 28,\n                    fill: '#E1E1E1',\n                }),\n                balanceTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fontSize: 22,\n                    fill: '#F1F1F1',\n                    padding: 3,\n                }),\n                betTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fontSize: 22,\n                    fill: '#F1F1F1',\n                    padding: 3,\n                }),\n                betValueStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fontSize: 22,\n                    fill: '#F1F1F1',\n                }),\n                balanceValueStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fontSize: 22,\n                    fill: '#F1F1F1',\n                }),\n                winlineTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fontSize: 23,\n                    fill: '#FFFFFF',\n                }),\n                selectedLinesValueTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fontSize: 39,\n                    fill: '#FFFFFF',\n                }),\n                defaultLinesValueTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fontSize: 39,\n                    fill: '#C6C5C5',\n                }),\n                hasLinesSection: true,\n                denominationButtonTextures: ['svgBet', 'svgBetPressed', 'svgBet', 'svgBet'],\n                denominationButtonSelectedTextures: [\n                    'svgBetBlue',\n                    'svgBetBluePressed',\n                    'svgBetBlueHover',\n                    'svgBetBlue',\n                ],\n                allButtonsBounds: {\n                    width: 120,\n                    height: 86,\n                },\n                winlinesButtonTextures: ['svgBet', 'svgBetPressed', 'svgBet', 'svgBet'],\n                winlinesButtonSelectedTextures: [\n                    'svgActiveBetPressed',\n                    'svgActiveBetPressed',\n                    'svgActiveBetPressed',\n                    'svgActiveBetPressed',\n                ],\n                winlinesButtonTextOffsetX: 14,\n                winlinesButtonTextOffsetY: 15,\n                winlineTextOffsetY: 11,\n                // windowTitleTextStyleDesktop: new TextStyle({\n                //     fill: '#CFCFCF',\n                //     fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                //     fontSize: 24,\n                // }),\n            },\n            landscape: {\n                // x: 365,\n                // y: 0,\n                winlinesTextY: 0,\n                betsTextY: 168,\n                denominationsTextY: 335,\n                balanceContainerX: 50,\n                balanceContainerY: 500,\n                betContainerX: 1310,\n                betContainerY: 500,\n                firstButtonPositionsX: [620, 557, 493, 429, 365, 300],\n                linesButtonsY: 52,\n                betButtonsY: 220,\n                denominationButtonsY: 388,\n            },\n            desktop: {\n                // x: 97,\n                // y: 55,\n                // winlinesTextY: 55,\n                widthBounds: 770,\n                heightBounds: 454,\n                viewTopOffset: 117,\n                buttonsOffsetX: [27, 27, 27, 27, 27, 27],\n                buttonsOffsetY: 6,\n                balanceContainerX: 60,\n                balanceContainerY: 0,\n                betContainerX: 710,\n                betContainerY: 0,\n                titleTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fontSize: 22,\n                    lineHeight: 22,\n                    fill: '#E1E1E1',\n                }),\n                balanceTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fontSize: 18,\n                    fill: '#F1F1F1',\n                    padding: 3,\n                }),\n                betTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fontSize: 18,\n                    fill: '#F1F1F1',\n                    padding: 3,\n                }),\n                betValueStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fill: '#F1F1F1',\n                    fontSize: 18,\n                }),\n                balanceValueStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-Bold, Arial, sans-serif',\n                    fill: '#F1F1F1',\n                    fontSize: 18,\n                }),\n                denominationButtonTextures: ['svgBet', 'svgBetPressed', 'svgBetHover', 'svgBet'],\n                denominationButtonSelectedTextures: [\n                    'svgBetBlue',\n                    'svgBetBluePressed',\n                    'svgBetBlueHover',\n                    'svgBetBlue',\n                ],\n                allButtonsBounds: {\n                    width: 94,\n                    height: 75,\n                },\n                winlineTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT, Arial, sans-serif',\n                    fontSize: 18,\n                    fill: '#FFFFFF',\n                }),\n                selectedLinesValueTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fontSize: 31,\n                    fill: '#FFFFFF',\n                }),\n                defaultLinesValueTextStyle: new TextStyle({\n                    fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n                    fontSize: 31,\n                    fill: '#C6C5C5',\n                }),\n            },\n        })\n        public betViewProps: DynamicPositionObject<IBetViewInterface> & IBetViewInterface;\n\n        @DefaultValue<IBetCalculatorInterface>({\n            defaults: {\n                x: 679,\n                y: 15,\n                betPerRow: 5,\n                maxHeight: 505,\n            },\n            portrait: {\n                x: 384,\n                y: 380,\n                maxHeight: Infinity,\n            },\n        })\n        public betCalculatorProps: DynamicPositionObject<IBetCalculatorInterface> & IBetCalculatorInterface;\n\n        @DefaultValue<IOneDenomBetViewInterface>({\n            defaults: {\n                betsTextY: -25,\n                winlinesTextX: 163,\n                winlinesTextY: 185,\n                linesButtonsY: 228,\n                firstLinesButtonPositionsX: [161], // [1 line, 2 line, 3 line ...]\n                winlinesTextWordWrap: false,\n                winlinesTextWordWrapWidth: 220,\n                balanceValueWidthBounds: 165,\n            },\n            portrait: {\n                betsTextY: 332,\n                winlinesTextX: 382,\n                winlinesTextY: 119,\n                linesButtonsY: 169,\n                firstLinesButtonPositionsX: [382], // [1 line, 2 line, 3 line ...]\n                balanceValueWidthBounds: Infinity,\n            },\n        })\n        public oneDenomBetViewProps: DynamicPositionObject<IOneDenomBetViewInterface> & IOneDenomBetViewInterface;\n\n        public haveGuaranteedWinToggleDescription: boolean = false;\n    }\n    return SettingsPopupComponentConfigurationInternalClass;\n}\n","import Core, { BaseController, FeatureFlags } from '@egt/core';\nimport { InitialSettings, RootStore, ServerState, UIState } from '@egt/slot';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport SettingsTab from '../enums/SettingsTab';\nimport SettingsPopupSubjects from '../subjects/SettingsPopupSubjects';\nimport SettingsPopup from '../views/SettingsPopup';\n\n@injectable()\nexport default class SettingsPopupController extends BaseController {\n    public eventsAtached: boolean = false;\n    protected currentUIState: string | undefined = undefined;\n    private initialSettings: InitialSettings;\n    protected hasPaytableOnLoadRequirement: boolean = false;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('SettingsPopup') protected view: SettingsPopup,\n        @inject('SettingsPopupSubjects') protected subjects: SettingsPopupSubjects,\n    ) {\n        super(view);\n    }\n\n    public init(): void {\n        this.initialSettings = Core.gameDependencyContainer.resolve('InitialSettings');\n        this.hasPaytableOnLoadRequirement =\n            Core.flags.isActive(FeatureFlags.USE_PAYTABLE_ON_LOAD) && this.initialSettings.state === ServerState.IDLE;\n\n        this.rootStore.subjects.OPEN_SETTINGS_POPUP.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.showSettings.bind(this),\n        );\n\n        this.subjects.BEFORE_OPEN.pipe(takeUntil(this.DESTROY)).subscribe(this.onBeforeOpen.bind(this));\n\n        this.subjects.AFTER_OPEN.pipe(takeUntil(this.DESTROY)).subscribe(this.onAfterSettingsOpen.bind(this));\n\n        this.subjects.BEFORE_CLOSE.pipe(takeUntil(this.DESTROY)).subscribe(this.onBeforeClose.bind(this));\n\n        this.subjects.AFTER_CLOSE.pipe(takeUntil(this.DESTROY)).subscribe(this.onAfterSettingsClose.bind(this));\n\n        this.rootStore.subjects.CLOSE_SETTINGS_POPUP.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.closePopup.bind(this),\n        );\n\n        this.rootStore.subjects.MODAL_PRESSED.pipe(takeUntil(this.DESTROY)).subscribe(this.closePopup.bind(this, true));\n\n        this.rootStore.subjects.CLOSE_ALL_POPUPS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.closePopup.bind(this, false),\n        );\n    }\n\n    protected closePopup(animation: boolean = true): void {\n        if (this.view.isOpened) {\n            this.view.close(animation);\n            this.view.clearTabSelection();\n        } else {\n            this.subjects.BEFORE_CLOSE.next();\n        }\n    }\n\n    protected openPopup(animation: boolean = true): void {\n        if (!this.view.isOpened) {\n            this.rootStore.subjects.CLOSE_ALL_POPUPS.next();\n            this.view.open(animation);\n        }\n    }\n\n    protected attachEventListeners(): void {\n        if (this.eventsAtached) {\n            return;\n        }\n        this.eventsAtached = true;\n        if (this.view.betButton) {\n            this.view.betButton.SWITCH.pipe(takeUntil(this.DESTROY)).subscribe(\n                this.onTabChange.bind(this, SettingsTab.BET),\n            );\n        }\n\n        if (this.view.generalButton) {\n            this.view.generalButton.SWITCH.pipe(takeUntil(this.DESTROY)).subscribe(\n                this.onTabChange.bind(this, SettingsTab.GENERAL),\n            );\n        }\n\n        if (this.view.spinButton) {\n            this.view.spinButton.SWITCH.pipe(takeUntil(this.DESTROY)).subscribe(\n                this.onTabChange.bind(this, SettingsTab.AUTOPLAY),\n            );\n        }\n\n        if (this.view.infoButton) {\n            this.view.infoButton.SWITCH.pipe(takeUntil(this.DESTROY)).subscribe(\n                this.onTabChange.bind(this, SettingsTab.INFO),\n            );\n        }\n\n        if (this.view.helpButton) {\n            this.view.helpButton.SWITCH.pipe(takeUntil(this.DESTROY)).subscribe(\n                this.onTabChange.bind(this, SettingsTab.HELP),\n            );\n        }\n    }\n\n    protected showSettings(): void {\n        // this.rootStore.uiStore.SHOW_SETTINGS.next(true);\n        this.openPopup();\n        this.attachEventListeners();\n    }\n\n    protected onBeforeOpen(): void {\n        this.currentUIState = this.rootStore.uiStore.STATE.value;\n        this.rootStore.uiStore.STATE.next(UIState.DISABLED);\n        this.rootStore.subjects.MODAL_LAYER_ENABLED.next(false);\n        this.rootStore.uiStore.SHOW_SETTINGS.next(true);\n        // this.modalLayer.enabled(false);\n    }\n\n    protected onAfterSettingsOpen(): void {\n        this.rootStore.subjects.SETTINGS_POPUP_OPENED.next();\n        this.restoreUIState();\n    }\n\n    private onTabChange(selectedTabId: SettingsTab): void {\n        this.rootStore.uiStore.SELECTED_SETTINGS_TAB.next(selectedTabId);\n        Core.sounds.play('menuSound');\n    }\n\n    protected onBeforeClose(): void {\n        this.rootStore.subjects.MODAL_LAYER_ENABLED.next(true);\n        // this.modalLayer.enabled(true);\n    }\n\n    protected onAfterSettingsClose(): void {\n        this.rootStore.subjects.SETTINGS_POPUP_CLOSED.next();\n        this.rootStore.uiStore.SHOW_SETTINGS.next(false);\n        this.restoreUIState();\n    }\n\n    private restoreUIState(): void {\n        if (this.currentUIState) {\n            this.rootStore.uiStore.STATE.next(this.currentUIState);\n            this.currentUIState = undefined;\n        }\n    }\n}\n","import Core, { PostMessageDispatcher } from '@egt/core';\nimport { RootStore } from '@egt/slot';\nimport { fromEvent } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport SettingsTab from '../enums/SettingsTab';\nimport SettingsPopupSubjects from '../subjects/SettingsPopupSubjects';\nimport SettingsPopupDesktop from '../views/SettingsPopupDesktop';\nimport SettingsPopupController from './SettingsPopupController';\nimport { IUIMainPanelView } from '@egt/ui-main-panel';\n\n@injectable()\nexport default class SettingsPopupControllerDesktop extends SettingsPopupController {\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('SettingsPopup') protected view: SettingsPopupDesktop,\n        @inject('UIMainView') protected uiMainView: IUIMainPanelView,\n        @inject('SettingsPopupSubjects') protected subjects: SettingsPopupSubjects,\n    ) {\n        super(rootStore, view, subjects);\n    }\n\n    protected showSettings(): void {\n        this.rootStore.uiStore.SHOW_SETTINGS.next(true);\n        this.view.setDimensions(this.rootStore.uiStore.SELECTED_SETTINGS_TAB.value);\n        if (this.rootStore.uiStore.SELECTED_SETTINGS_TAB.value !== SettingsTab.INFO) {\n            Core.sounds.play('showDenominationsSound');\n        } else {\n            if (!this.hasPaytableOnLoadRequirement) {\n                Core.sounds.play('paytableSound');\n            }\n            this.hasPaytableOnLoadRequirement = false;\n        }\n        this.attachEventListeners();\n        this.openPopup();\n    }\n\n    protected onBeforeOpen(): void {\n        this.rootStore.subjects.MODAL_LAYER_ENABLED.next(false);\n        this.rootStore.uiStore.SHOW_SETTINGS.next(true);\n        // this.modalLayer.enabled(false);\n    }\n\n    protected onAfterSettingsOpen(): void {\n        this.rootStore.subjects.SETTINGS_POPUP_OPENED.next();\n        this.uiMainView.paytableButton.enabled = true;\n    }\n\n    protected attachEventListeners(): void {\n        if (this.eventsAtached) {\n            return;\n        }\n        this.eventsAtached = true;\n        this.view.find('close_button').CLICK.pipe(takeUntil(this.DESTROY)).subscribe(this.closeSettings.bind(this));\n        fromEvent(this.view.find('dark_layer'), 'pointerdown')\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.closeSettings.bind(this));\n    }\n\n    private closeSettings(): void {\n        if (this.view.isOpened) {\n            PostMessageDispatcher.toggleMenu(false);\n            this.rootStore.subjects.RESET_AUTOPLAY_RESTRICTIONS.next();\n            this.rootStore.subjects.CLOSE_SETTINGS_POPUP.next();\n            Core.sounds.play('hideDenominationsSound');\n        }\n    }\n}\n","const enum SettingsTab {\n    BET = 'BET',\n    GENERAL = 'GENERAL',\n    AUTOPLAY = 'SPIN',\n    INFO = 'INFO',\n    HELP = 'HELP',\n}\nexport default SettingsTab;\n","import SettingsPopupComponent from './SettingsPopupComponent';\nimport SettingsPopupComponentConfiguration from './configuration/SettingsPopupComponentConfiguration';\nimport SettingsPopupController from './controllers/SettingsPopupController';\nimport SettingsTab from './enums/SettingsTab';\nimport {\n    IAutoplayViewInterface,\n    IBetCalculatorInterface,\n    IBetViewInterface,\n    IButtonsBlockerInterface,\n    IGeneralSettingsInterface,\n    IHelpViewInterface,\n    IMenuBetButton,\n    IOneDenomBetViewInterface,\n    IPaytableViewInterface,\n    ISettingsBackgroundInterface,\n    ISettingsBarInterface,\n    ISettingsHeaderBackgroundInterface,\n    ISettingsHeaderBottomLineInterface,\n    ISettingsHeaderTopLineInterface,\n    ISettingsPopupComponentConfiguration,\n    ISettingsPopupInterface,\n    ISettingsTabNameInterface,\n    IValueField,\n    IAutoplayNumericInputsViewProps,\n    ISettingsMenuCover,\n} from './interfaces/SettingsInterfaces';\nimport BetSettingsView from './settings-views/bet/BetSettingsView';\nimport BetSettingsViewDesktop from './settings-views/bet/BetSettingsViewDesktop';\nimport OneDenomBetSettingsView from './settings-views/bet/OneDenomBetSettingsView';\nimport WaysPayBetSettingsView from './settings-views/bet/WaysPayBetSettingsView';\nimport WaysPayBetSettingsViewDesktop from './settings-views/bet/WaysPayBetSettingsViewDesktop';\nimport WaysPayOneDenomBetSettingsView from './settings-views/bet/WaysPayOneDenomBetSettingsView';\nimport GeneralSettingsView from './settings-views/general/GeneralSettingsView';\nimport GeneralSettingsViewDesktop from './settings-views/general/GeneralSettingsViewDesktop';\nimport HelpView from './settings-views/help/HelpView';\nimport PaytableHTMLView from './settings-views/paytableHTML/PaytableHTMLView';\nimport PaytableScript from './settings-views/paytableHTML/PaytableScript';\nimport SpinSettingsView from './settings-views/spin/SpinSettingsView';\nimport SpinSettingsNumericInputView from './settings-views/spin/SpinSettingsNumericInputView';\nimport SpinSettingsViewDesktop from './settings-views/spin/SpinSettingsViewDesktop';\nimport SettingsPopupSubjects from './subjects/SettingsPopupSubjects';\nimport SettingsPopup from './views/SettingsPopup';\nimport SettingsPopupDesktop from './views/SettingsPopupDesktop';\n\nexport {\n    SettingsTab,\n    BetSettingsView,\n    BetSettingsViewDesktop,\n    WaysPayBetSettingsView,\n    WaysPayBetSettingsViewDesktop,\n    GeneralSettingsView,\n    GeneralSettingsViewDesktop,\n    HelpView,\n    PaytableHTMLView,\n    PaytableScript,\n    SpinSettingsView,\n    SpinSettingsNumericInputView,\n    SpinSettingsViewDesktop,\n    SettingsPopup,\n    SettingsPopupDesktop,\n    SettingsPopupSubjects,\n    SettingsPopupController,\n    ISettingsPopupComponentConfiguration,\n    ISettingsPopupInterface,\n    ISettingsBackgroundInterface,\n    ISettingsHeaderBackgroundInterface,\n    ISettingsHeaderTopLineInterface,\n    ISettingsHeaderBottomLineInterface,\n    ISettingsTabNameInterface,\n    ISettingsBarInterface,\n    IAutoplayNumericInputsViewProps,\n    ISettingsMenuCover,\n    IButtonsBlockerInterface,\n    IGeneralSettingsInterface,\n    IHelpViewInterface,\n    IPaytableViewInterface,\n    IAutoplayViewInterface,\n    IBetViewInterface,\n    IMenuBetButton,\n    SettingsPopupComponentConfiguration,\n    OneDenomBetSettingsView,\n    WaysPayOneDenomBetSettingsView,\n    IOneDenomBetViewInterface,\n    IBetCalculatorInterface,\n    IValueField,\n};\nexport default SettingsPopupComponent;\n","import { BuyBonusModes } from '@egt/buy-bonus';\nimport Core, { GameTypes, IOrientation, ITranslator } from '@egt/core';\nimport { FeatureController, ISlotConfiguration, RootStore, SlotComponents, UIState } from '@egt/slot';\nimport {\n    BetButton,\n    Button,\n    ButtonStates,\n    DenominationButton,\n    IViewVisibilityContainer,\n    MoneyText,\n    MoneyTextConfig,\n    Text,\n    TextConfig,\n    ViewContainer,\n    ViewVisibilityContainer,\n    WinlinesButton,\n} from '@egt/ui-lib';\nimport { gsap } from 'gsap';\nimport { Text as PixiText, TextStyle, Texture } from 'pixi.js';\nimport { merge } from 'rxjs';\nimport { filter, takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { ISettingsPopupComponentConfiguration } from '../../interfaces/SettingsInterfaces';\n@injectable()\nexport default class BetSettingsView extends ViewVisibilityContainer implements IViewVisibilityContainer {\n    protected translator: ITranslator = Core.translator;\n    protected denominations: any[] = [];\n    protected linesButtons: WinlinesButton[] = [];\n    protected betButtons: BetButton[] = [];\n    protected denominationText: PixiText = new PixiText('');\n    protected winlinesOptions: number[] = [5, 10, 15, 20, 30];\n    protected winlinesButtons: WinlinesButton[] = [];\n    protected winlinesText: PixiText = new PixiText('');\n    protected titleTextStyle: TextStyle = new TextStyle();\n    protected betsText: PixiText = new PixiText('');\n    // protected winlineButtonWidth: number = 113;\n    // protected winlineButtonHeight: number = 90;\n    // protected denominationBreakLine: Sprite;\n    // protected winlinesBreakLine: Sprite;\n    protected buttonsDisabled = false;\n\n    protected balanceContainer: ViewContainer;\n    protected betContainer: ViewContainer;\n    protected balanceTextStyle: TextStyle = new TextStyle();\n    protected balanceTextConfig: TextConfig = new TextConfig();\n    protected betTextStyle: TextStyle = new TextStyle();\n    protected betTextConfig: TextConfig = new TextConfig();\n    protected balanceValueConfig: MoneyTextConfig = new MoneyTextConfig();\n    protected betValueConfig: MoneyTextConfig = new MoneyTextConfig();\n    protected betValueStyle: TextStyle = new TextStyle();\n    protected balanceValueStyle: TextStyle = new TextStyle();\n    protected balanceText: Text;\n    protected betText: Text;\n    protected balanceValue: MoneyText;\n    protected betValue: MoneyText;\n    protected initialValueFontSize: number = 0;\n    protected balanceTween: any;\n    protected collectDuration: number = this.configuration.collectBangupDuration;\n\n    // protected labelFontStyle: string = 'Arial';\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected configuration: ISlotConfiguration,\n        @inject('SettingsPopupComponentConfiguration')\n        protected componentConfiguration: ISettingsPopupComponentConfiguration,\n        @inject('FeatureController') protected feature: FeatureController,\n    ) {\n        super();\n        this.init();\n    }\n\n    public init(): void {\n        this.winlinesOptions = this.rootStore.settings.multipleLinesGameAvailableLines\n            ? this.rootStore.settings.multipleLinesGameAvailableLines\n            : this.rootStore.settings.linesOptions;\n        this.initialValueFontSize = Number(this.componentConfiguration.betButtonsConfigs.amount.defaultStyle.fontSize);\n        // this.balanceMoney = new Money(Core.PLAYER_BALANCE.value.balance);\n        this.initialRender();\n        // Core.PLAYER_BALANCE.pipe(takeUntil(this.DESTROY)).subscribe(this.onBalanceChanged.bind(this));\n        this.rootStore.uiStore.BALANCE.pipe(takeUntil(this.DESTROY)).subscribe(this.onBalanceChanged.bind(this));\n        this.rootStore.subjects.DENOMINATIONS_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onDenominationsChanged.bind(this),\n        );\n\n        if (Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS)) {\n            this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.pipe(takeUntil(this.DESTROY)).subscribe(\n                this.onBuyBonusActivated.bind(this),\n            );\n        }\n        this.rootStore.subjects.BET_SETTINGS_TITLE.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onTitleChanged.bind(this),\n        );\n\n        merge(Core.ORIENTATION, this.rootStore.uiStore.SELECTED_SETTINGS_TAB)\n            .pipe(\n                takeUntil(this.DESTROY),\n                filter(() => this.rootStore.uiStore.SHOW_SETTINGS.value),\n            )\n            .subscribe(this.redrawView.bind(this));\n\n        Core.MONEY_MODE_IN_CREDITS.pipe(takeUntil(Core.ON_GAME_UNLOADED)).subscribe(this.onMoneyModeChanged.bind(this));\n        Core.SELECTED_DENOMINATION.pipe(takeUntil(Core.ON_GAME_UNLOADED)).subscribe((denomination) => {\n            this.denominationChanged(denomination);\n            if (\n                this.rootStore.settings.numberOfLinesPerDenomination &&\n                this.rootStore.settings.numberOfLinesPerDenomination.length\n            ) {\n                this.changeDenominationAndNumberOfLines(denomination);\n                this.linesChanged(this.rootStore.uiStore.LINES.value);\n            }\n        });\n        this.rootStore.domainStore.COLLECT_RESPONSE.pipe(takeUntil(this.DESTROY)).subscribe(this.onCollect.bind(this));\n        this.rootStore.uiStore.STATE.pipe(takeUntil(this.DESTROY)).subscribe(this.stateChanged.bind(this));\n        this.rootStore.uiStore.SELECTED_BET.pipe(takeUntil(this.DESTROY)).subscribe(this.updateBetButtons.bind(this));\n        this.rootStore.subjects.FACTOR_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(this.onFactorChanged.bind(this));\n        this.show = false;\n        this.redrawView();\n\n        this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onExtendedMultipleBuyBonusActivated.bind(this),\n        );\n    }\n\n    public redrawView(): void {\n        this.setOrientation(Core.ORIENTATION.value);\n    }\n\n    public destroy(): void {\n        if (this.denominations) {\n            this.denominations.forEach((denominationButton) => {\n                denominationButton.destroy();\n                // @ts-ignore\n                denominationButton = null;\n            });\n            // @ts-ignore\n            this.denominations = null;\n        }\n        super.destroy();\n    }\n\n    public onDenominationsChanged() {\n        this.removeChildren();\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        this.denominations.forEach((denominationButton) => {\n            // @ts-ignore\n            denominationButton = null;\n        });\n        this.denominations.length = 0;\n\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        this.betButtons.forEach((betButton: BetButton) => {\n            // @ts-ignore\n            betButton = null;\n        });\n        this.betButtons = [];\n\n        this.winlinesButtons.length = 0;\n\n        this.initialRender();\n        this.redrawView();\n    }\n\n    protected onExtendedMultipleBuyBonusActivated(value: boolean): void {\n        if (\n            this.rootStore.settings.haveGameMode('DOUBLE_CHANCE') &&\n            this.rootStore.settings.factor === this.rootStore.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE')\n        ) {\n            value = false;\n        }\n        for (const betButton of this.betButtons) {\n            betButton.buyBonusActivated = value;\n        }\n        this.maxBetBuyBonusCheck();\n    }\n\n    protected updateBetButtons(bet: number): void {\n        const betButton: BetButton = this.betButtons.filter((button) => {\n            return button.betPerLine === bet;\n        })[0];\n        this.clearBetSelection();\n        betButton.selected = true;\n\n        this.onBetOrDenominationChanged();\n    }\n\n    protected onMoneyModeChanged(): void {\n        this.denominationText.text = Core.MONEY_MODE_IN_CREDITS.value\n            ? this.translator.translate('DENOMINATION')\n            : this.translator.translate('BET LEVELS');\n        this.onBalanceChanged();\n        this.onBetOrDenominationChanged();\n    }\n\n    /**\n     * Sets the orientation of the component, adjusting positions of text and buttons based on the provided orientation.\n     * @param {IOrientation} orientation - The current orientation configuration, which includes width and possibly other properties.\n     */\n    protected setOrientation(orientation: IOrientation): void {\n        const widthBounds = this.getWidthBounds(orientation.width);\n        this.updateWinlinesTextPosition(widthBounds);\n        this.updateWinlinesButtonsPosition();\n        this.updateBetsTextPosition(widthBounds);\n        this.updateBetButtonsPosition();\n        this.updateDenominationTextPosition(widthBounds);\n        this.updateDenominationButtonsPosition(orientation);\n        this.updateBalanceContainerPosition();\n        this.updateBetContainerPosition();\n    }\n    /**\n     * Retrieves the width bounds from configuration or defaults to the provided width if not set.\n     * @param {number} defaultWidth - The default width to use if width bounds are not specified in the configuration.\n     * @returns {number} The calculated width bounds.\n     */\n    private getWidthBounds(defaultWidth: number): number {\n        return this.componentConfiguration.betViewProps.widthBounds || defaultWidth;\n    }\n\n    private onTitleChanged(): void {\n        this.betsText.text = Core.translator.translate(this.rootStore.subjects.BET_SETTINGS_TITLE.value);\n    }\n\n    private onBuyBonusActivated(): void {\n        const textureType: string = this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value\n            ? 'Special'\n            : '';\n        const textures: Texture[] = [\n            Core.assets.getAsset(\n                this.componentConfiguration.betButtonsBuyBonusTextures.textures[ButtonStates.Normal] + textureType,\n            ).texture,\n            Core.assets.getAsset(\n                this.componentConfiguration.betButtonsBuyBonusTextures.textures[ButtonStates.Pressed] + textureType,\n            ).texture,\n            Core.assets.getAsset(\n                this.componentConfiguration.betButtonsBuyBonusTextures.textures[ButtonStates.Over] + textureType,\n            ).texture,\n            Core.assets.getAsset(\n                this.componentConfiguration.betButtonsBuyBonusTextures.textures[ButtonStates.Disabled] + textureType,\n            ).texture,\n        ];\n\n        const selectedTextures: Texture[] = this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value\n            ? [\n                  Core.assets.getAsset('svgBetPressed' + textureType).texture,\n                  Core.assets.getAsset('svgBetPressed' + textureType).texture,\n                  Core.assets.getAsset('svgBetPressed' + textureType).texture,\n                  Core.assets.getAsset('svgBet' + textureType).texture,\n              ]\n            : this.getBetButtonsTextures(this.componentConfiguration.betButtons[0].get('betConfig').selectedTextures);\n\n        for (const betBtn of this.betButtons) {\n            betBtn.setTextures(textures);\n            betBtn.setSelectedTextures(selectedTextures);\n        }\n\n        for (const linesButton of this.linesButtons) {\n            linesButton.setTextures(textures);\n            linesButton.setSelectedTextures(selectedTextures);\n        }\n\n        const selecteDenomtTextures = this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value\n            ? selectedTextures\n            : [\n                  Core.assets.getAsset(\n                      this.componentConfiguration.betViewProps.denominationButtonSelectedTextures[ButtonStates.Normal],\n                  ).texture,\n                  Core.assets.getAsset(\n                      this.componentConfiguration.betViewProps.denominationButtonSelectedTextures[ButtonStates.Pressed],\n                  ).texture,\n                  Core.assets.getAsset(\n                      this.componentConfiguration.betViewProps.denominationButtonSelectedTextures[ButtonStates.Over],\n                  ).texture,\n                  Core.assets.getAsset(\n                      this.componentConfiguration.betViewProps.denominationButtonSelectedTextures[\n                          ButtonStates.Disabled\n                      ],\n                  ).texture,\n              ];\n\n        for (const denomination of this.denominations) {\n            denomination.setTextures(textures);\n            denomination.setSelectedTextures(selecteDenomtTextures);\n        }\n    }\n\n    /**\n     * Updates the position of winlines text based on the calculated width bounds.\n     * @param {number} widthBounds - The width bounds to use for positioning the winlines text.\n     */\n    private updateWinlinesTextPosition(widthBounds: number): void {\n        if (this.winlinesText) {\n            this.winlinesText.x = widthBounds / 2;\n            this.winlinesText.y = this.componentConfiguration.betViewProps.winlinesTextY;\n        }\n    }\n    /**\n     * Iterates over winlines buttons and updates their positions based on the component configuration.\n     */\n    private updateWinlinesButtonsPosition(): void {\n        if (this.winlinesButtons) {\n            this.winlinesButtons.forEach((button, index) => {\n                const positionX = this.getButtonXPosition(index, this.winlinesButtons.length, button.width);\n                button.x = positionX;\n                button.y = this.componentConfiguration.betViewProps.linesButtonsY;\n            });\n        }\n    }\n    /**\n     * Updates the position of bets text based on the calculated width bounds.\n     * @param {number} widthBounds - The width bounds to use for positioning the bets text.\n     */\n    private updateBetsTextPosition(widthBounds: number): void {\n        this.betsText.x = widthBounds / 2;\n        this.betsText.y = this.componentConfiguration.betViewProps.betsTextY;\n    }\n    /**\n     * Iterates over bet buttons and updates their positions based on the component configuration.\n     */\n    private updateBetButtonsPosition(): void {\n        this.betButtons.forEach((button, index) => {\n            const positionX = this.getButtonXPosition(index, this.betButtons.length, button.width);\n            button.x = positionX;\n            button.y = this.componentConfiguration.betViewProps.betButtonsY;\n        });\n    }\n    /**\n     * Updates the position of denomination text based on the calculated width bounds.\n     * @param {number} widthBounds - The width bounds to use for positioning the denomination text.\n     */\n    private updateDenominationTextPosition(widthBounds: number): void {\n        this.denominationText.x = widthBounds / 2;\n        this.denominationText.y = this.componentConfiguration.betViewProps.denominationsTextY;\n    }\n\n    /**\n     * Iterates over denomination buttons and updates their positions based on the current orientation.\n     * @param {IOrientation} orientation - The current orientation configuration to adjust the button positions.\n     */\n    private updateDenominationButtonsPosition(orientation: IOrientation): void {\n        const firstPosition = this.calculateDenominationFirstPosition(orientation.width);\n        this.denominations.forEach((button, index) => {\n            this.adjustDenominationButtonPosition(button, index, firstPosition, orientation.width);\n        });\n    }\n    /**\n     * Calculates the X position for a button based on its index and the total number of buttons.\n     * @param {number} index - The index of the button in its group.\n     * @param {number} length - The total number of buttons in the group.\n     * @param {number} buttonWidth - The width of the button.\n     * @returns {number} The calculated X position for the button.\n     */\n    private getButtonXPosition(index: number, length: number, buttonWidth: number): number {\n        const offset = this.componentConfiguration.betViewProps.buttonsOffsetX[length - 1];\n        return (\n            this.componentConfiguration.betViewProps.firstButtonPositionsX[length - 1] + index * (buttonWidth + offset)\n        );\n    }\n    /**\n     * Calculates the initial X position for the first denomination button.\n     * @param {number} totalWidth - The total width available for the buttons.\n     * @returns {number} The calculated initial X position for the first denomination button.\n     */\n    private calculateDenominationFirstPosition(totalWidth: number): number {\n        const offsetWidth = this.componentConfiguration.betViewProps.buttonsOffsetX[this.denominations.length - 1];\n        const buttonAndOffsetWidth = this.denominations[0].width + offsetWidth;\n        let firstPosition = (totalWidth - this.denominations.length * buttonAndOffsetWidth) / 2;\n\n        if (firstPosition <= 0) {\n            firstPosition += (buttonAndOffsetWidth + offsetWidth) / 2;\n        } else {\n            firstPosition =\n                this.componentConfiguration.betViewProps.firstButtonPositionsX[this.denominations.length - 1];\n        }\n\n        return firstPosition;\n    }\n    /**\n     * Adjusts the position of a denomination button, including repositioning if the button exceeds the view's width.\n     * @param {DenominationButton} button - The denomination button to adjust.\n     * @param {number} index - The index of the button.\n     * @param {number} firstPosition - The starting X position for the first button.\n     * @param {number} maxWidth - The maximum width of the view to check for overflow.\n     */\n    private adjustDenominationButtonPosition(button, index: number, firstPosition: number, maxWidth: number): void {\n        button.scale.set(this.componentConfiguration.betViewProps.denomButtonScale[this.denominations.length - 1]);\n        button.x =\n            firstPosition +\n            index *\n                (button.width + this.componentConfiguration.betViewProps.buttonsOffsetX[this.denominations.length - 1]);\n        button.y = this.componentConfiguration.betViewProps.denominationButtonsY;\n\n        if (button.x + button.width > maxWidth) {\n            button.x = (maxWidth - button.width) / 2;\n            button.y +=\n                button.height + this.componentConfiguration.betViewProps.buttonsOffsetX[this.denominations.length - 1];\n        }\n    }\n    /**\n     * Updates the position of the balance container based on the component configuration.\n     */\n    private updateBalanceContainerPosition(): void {\n        this.balanceContainer.x = this.componentConfiguration.betViewProps.balanceContainerX;\n        this.balanceContainer.y = this.componentConfiguration.betViewProps.balanceContainerY;\n    }\n    /**\n     * Updates the position of the bet container by adjusting its X and Y positions based on the component configuration.\n     */\n    private updateBetContainerPosition(): void {\n        this.betContainer.x = this.componentConfiguration.betViewProps.betContainerX - this.betContainer.width;\n        this.betContainer.y = this.componentConfiguration.betViewProps.betContainerY;\n    }\n\n    protected createTextProps(): void {\n        this.titleTextStyle = this.componentConfiguration.betViewProps.titleTextStyle;\n        this.balanceTextStyle = this.componentConfiguration.betViewProps.balanceTextStyle;\n        this.betTextStyle = this.componentConfiguration.betViewProps.betTextStyle;\n        this.betValueStyle = this.componentConfiguration.betViewProps.betValueStyle;\n        this.balanceValueStyle = this.componentConfiguration.betViewProps.balanceValueStyle;\n\n        this.balanceValueConfig.showCredits = false;\n        this.balanceValueConfig.showCurrency = true;\n\n        this.balanceValueConfig.currency = this.betValueConfig.currency = this.rootStore.uiStore.currency;\n        this.betValueConfig.shouldFitInBounds = this.balanceValueConfig.shouldFitInBounds = false;\n        this.balanceValueConfig.useMoneyMode = this.betValueConfig.useMoneyMode = false;\n        this.balanceValueConfig.bounds.width = 0;\n        this.betValueConfig.bounds.width = 0;\n        this.balanceValueConfig.moneyFontSize =\n            this.balanceValueConfig.centsFontSize =\n            this.betValueConfig.centsFontSize =\n            this.betValueConfig.moneyFontSize =\n                22;\n        this.balanceValueConfig.bounds.height =\n            this.betValueConfig.bounds.height =\n            this.betTextConfig.bounds.height =\n            this.balanceTextConfig.bounds.height =\n                50;\n        this.balanceValueConfig.spaceBetweenMoneyAndCurrency = this.betValueConfig.spaceBetweenMoneyAndCurrency = 4;\n    }\n\n    protected initialRender(): void {\n        this.createTextProps();\n\n        // ***** DENOMINATION / LEVEL SECTION *****\n        this.denominationText = new PixiText(\n            Core.MONEY_MODE_IN_CREDITS.value\n                ? this.translator.translate('DENOMINATION')\n                : this.translator.translate('BET LEVELS'),\n            this.titleTextStyle,\n        );\n        this.denominationText.anchor.x = 0.5;\n        this.addChild(this.denominationText);\n        this.rootStore.uiStore.denominations.forEach((denomination, index) => {\n            const denominationButton: DenominationButton = this.createDenomination(\n                denomination,\n                'settingsDenomination' + (index + 1),\n                index,\n            );\n\n            this.addChild(denominationButton);\n            this.denominations.push(denominationButton);\n        });\n\n        if (this.componentConfiguration.betViewProps.hasLinesSection) {\n            this.creatLinesSection();\n        } else {\n            this.createCustomSection();\n        }\n\n        // ***** BETS SECTION *****\n        this.betsText = new PixiText(\n            this.translator.translate(this.rootStore.subjects.BET_SETTINGS_TITLE.value),\n            this.titleTextStyle,\n        );\n        this.betsText.anchor.x = 0.5;\n        this.addChild(this.betsText);\n        this.createBetButtons();\n\n        // ***** BALANCE AND BET VALUES *****\n        this.balanceContainer = new ViewContainer();\n\n        this.balanceText = new Text(\n            this.balanceTextConfig,\n            Core.translator.translate('BALANCE') + ':',\n            this.balanceTextStyle,\n        );\n        this.balanceValue = new MoneyText(\n            this.balanceValueConfig,\n            this.rootStore.uiStore.BALANCE.value,\n            this.balanceValueStyle,\n        );\n\n        this.balanceContainer.addChild(this.balanceText);\n        this.balanceContainer.addChild(this.balanceValue);\n        this.balanceText.x = 0;\n        this.balanceText.y = 0;\n        this.balanceValue.pivot.set(this.balanceValue.width / 2, 0);\n        this.balanceValue.x = this.balanceText.x + this.balanceText.width + this.balanceValue.pivot.x;\n        this.balanceValue.y = this.balanceText.y;\n        this.addChild(this.balanceContainer);\n\n        this.betContainer = new ViewContainer();\n\n        this.betText = new Text(this.betTextConfig, Core.translator.translate('BET') + ':', this.betTextStyle);\n\n        this.betValue = new MoneyText(this.betValueConfig, this.getTotalBet(), this.betValueStyle);\n        this.betContainer.addChild(this.betText);\n        this.betContainer.addChild(this.betValue);\n\n        this.betText.x = 0;\n        this.betText.y = this.balanceText.y;\n\n        this.betValue.x = this.betText.x + this.betText.width;\n        this.betValue.y = this.betText.y;\n        this.addChild(this.betContainer);\n    }\n\n    protected creatLinesSection(): void {\n        // ***** LINES SECTION *****\n        this.winlinesText = new PixiText(this.translator.translate('LINES'), this.titleTextStyle);\n        this.winlinesText.anchor.x = 0.5;\n        this.addChild(this.winlinesText);\n        this.createLinesButtons();\n    }\n\n    protected createCustomSection(): void {\n        // implement in extended class\n    }\n\n    protected createLinesButtons(): void {\n        const linesButtonTextures = [\n            Core.assets.getAsset(this.componentConfiguration.betViewProps.winlinesButtonTextures[ButtonStates.Normal])\n                .texture,\n            Core.assets.getAsset(this.componentConfiguration.betViewProps.winlinesButtonTextures[ButtonStates.Pressed])\n                .texture,\n            Core.assets.getAsset(this.componentConfiguration.betViewProps.winlinesButtonTextures[ButtonStates.Over])\n                .texture,\n            Core.assets.getAsset(this.componentConfiguration.betViewProps.winlinesButtonTextures[ButtonStates.Disabled])\n                .texture,\n        ];\n        const linesButtonSelectedTextures = [\n            Core.assets.getAsset(\n                this.componentConfiguration.betViewProps.winlinesButtonSelectedTextures[ButtonStates.Disabled],\n            ).texture,\n            Core.assets.getAsset(\n                this.componentConfiguration.betViewProps.winlinesButtonSelectedTextures[ButtonStates.Disabled],\n            ).texture,\n            Core.assets.getAsset(\n                this.componentConfiguration.betViewProps.winlinesButtonSelectedTextures[ButtonStates.Disabled],\n            ).texture,\n            Core.assets.getAsset(\n                this.componentConfiguration.betViewProps.winlinesButtonSelectedTextures[ButtonStates.Disabled],\n            ).texture,\n        ];\n        const isFixed: boolean = this.winlinesOptions.length === 1;\n        this.winlinesOptions.forEach((option: number, index: number) => {\n            // our interface if for max 5 buttons\n            if (index < 5) {\n                const isCurrent = option === this.rootStore.uiStore.LINES.value;\n                const winlineButton = new WinlinesButton(\n                    'winlines',\n                    option,\n                    this.componentConfiguration.betViewProps.allButtonsBounds.width,\n                    this.componentConfiguration.betViewProps.allButtonsBounds.height,\n                    isCurrent && isFixed,\n                    linesButtonTextures,\n                    linesButtonSelectedTextures,\n                    isCurrent,\n                    this.componentConfiguration.betViewProps.winlineTextStyle,\n                    this.componentConfiguration.betViewProps.winlineTextOffsetY,\n                    this.componentConfiguration.betViewProps.winlinesButtonTextOffsetY,\n                    this.componentConfiguration.betViewProps.winlinesButtonTextOffsetX,\n                    this.componentConfiguration.betViewProps.defaultLinesValueTextStyle,\n                    this.componentConfiguration.betViewProps.selectedLinesValueTextStyle,\n                );\n                winlineButton.CLICK.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n                    if (this.rootStore.uiStore.LINES.value !== winlineButton.lines) {\n                        let linesChanged = false;\n                        if (\n                            this.rootStore.settings.numberOfLinesPerDenomination &&\n                            this.rootStore.settings.numberOfLinesPerDenomination.length\n                        ) {\n                            linesChanged = this.changeDenominationDependingOnLines(\n                                winlineButton,\n                                this.rootStore.settings.numberOfLinesPerDenomination!,\n                            );\n                        }\n                        if (linesChanged) {\n                            this.rootStore.uiStore.LINES.next(winlineButton.lines);\n                            this.linesChanged(this.rootStore.uiStore.LINES.value);\n                        }\n                    }\n                });\n                this.linesButtons.push(winlineButton);\n                // winlineButton.enabled = !isFixed;\n\n                if (this.configuration.gameType === GameTypes.WAYS_TO_PAY_SLOT) {\n                    this.winlinesText.visible = false;\n                    winlineButton.visible = false;\n                }\n\n                this.winlinesButtons.push(winlineButton);\n                this.addChild(winlineButton);\n            }\n        });\n    }\n\n    protected createBetButtons(): void {\n        this.rootStore.uiStore.bets.forEach((bet: number, index: number) => {\n            const maxBetBuyBonus =\n                this.rootStore.settings.settings.settings.clientSettings.maxBetLimits &&\n                Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS)\n                    ? this.rootStore.settings.settings.settings.clientSettings.maxBetLimits[\n                          this.rootStore.settings.currency\n                      ]\n                    : undefined;\n            const betButton: BetButton = new BetButton({\n                name: 'settingsBet' + (index + 1),\n                betPerLine: bet,\n                currency: this.rootStore.uiStore.currency,\n                units: this.rootStore.uiStore.units,\n                denomination: Core.SELECTED_DENOMINATION.value,\n                lines: this.rootStore.uiStore.LINES.value,\n                factor: this.rootStore.settings.factor,\n                width: this.componentConfiguration.betButtons[index].get('betConfig').width,\n                height: this.componentConfiguration.betButtons[index].get('betConfig').height,\n                text: this.translator.translate('BET'),\n                textures: this.getBetButtonsTextures(\n                    this.componentConfiguration.betButtons[index].get('betConfig').textures,\n                ),\n                selectedTextures: this.getBetButtonsTextures(\n                    this.componentConfiguration.betButtons[index].get('betConfig').selectedTextures,\n                ),\n                fakeMaskTexture: Core.assets.getAsset(\n                    this.componentConfiguration.betButtons[index].get('betConfig').fakeMaskTexture,\n                )?.texture,\n                selected: false,\n                // betButtonStyles: this.configuration.betButtonStyles,\n                dynamicConfig: this.componentConfiguration.betButtons[index].get('betConfig'),\n                maxBet: this.rootStore.settings.maxBet,\n                maxBetBuyBonus,\n            });\n\n            this['settingsBet' + (index + 1)] = betButton;\n\n            betButton.CLICK.pipe(takeUntil(this.DESTROY)).subscribe(\n                this.onBetChanged.bind(this, 'settingsBet' + (index + 1)),\n            );\n\n            this.betButtons.push(betButton);\n            this.addChild(betButton);\n\n            if (bet === this.rootStore.uiStore.SELECTED_BET.value) {\n                betButton.selected = true;\n            }\n            betButton.buyBonusActivated = this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value;\n        });\n        this.applyFontSize(this.initialValueFontSize);\n    }\n\n    protected applyFontSize(defaultFontSize: number): void {\n        let minFontSize: number = defaultFontSize;\n\n        for (const betButton of this.betButtons) {\n            betButton.fontSize = defaultFontSize;\n            minFontSize = Math.min(minFontSize, betButton.fontSize);\n        }\n        if (defaultFontSize > minFontSize) {\n            for (const betButton of this.betButtons) {\n                betButton.fontSize = minFontSize;\n            }\n        }\n    }\n\n    protected createDenomination(denomination: number, name: string, index: number): DenominationButton {\n        const denominationButtonTextures = [\n            Core.assets.getAsset(\n                this.componentConfiguration.betViewProps.denominationButtonTextures[ButtonStates.Normal],\n            ).texture,\n            Core.assets.getAsset(\n                this.componentConfiguration.betViewProps.denominationButtonTextures[ButtonStates.Pressed],\n            ).texture,\n            Core.assets.getAsset(this.componentConfiguration.betViewProps.denominationButtonTextures[ButtonStates.Over])\n                .texture,\n            Core.assets.getAsset(\n                this.componentConfiguration.betViewProps.denominationButtonTextures[ButtonStates.Disabled],\n            ).texture,\n        ];\n        const denominationSelectedTextures = [\n            Core.assets.getAsset(\n                this.componentConfiguration.betViewProps.denominationButtonSelectedTextures[ButtonStates.Normal],\n            ).texture,\n            Core.assets.getAsset(\n                this.componentConfiguration.betViewProps.denominationButtonSelectedTextures[ButtonStates.Pressed],\n            ).texture,\n            Core.assets.getAsset(\n                this.componentConfiguration.betViewProps.denominationButtonSelectedTextures[ButtonStates.Over],\n            ).texture,\n            Core.assets.getAsset(\n                this.componentConfiguration.betViewProps.denominationButtonSelectedTextures[ButtonStates.Disabled],\n            ).texture,\n        ];\n\n        const denominationButton: DenominationButton = new DenominationButton(\n            name,\n            '1 ' + this.translator.translate('CREDIT') + ' =',\n            denomination,\n            this.rootStore.uiStore.currency,\n            this.componentConfiguration.betViewProps.allButtonsBounds.width,\n            this.componentConfiguration.betViewProps.allButtonsBounds.height,\n            index,\n            denominationButtonTextures,\n            denominationSelectedTextures,\n            denomination === Core.SELECTED_DENOMINATION.value,\n            this.configuration.denomButtonStyles,\n        );\n\n        denominationButton.CLICK.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.updateDenomination.bind(this, denomination),\n        );\n\n        return denominationButton;\n    }\n\n    protected updateDenomination(denomination: number): void {\n        if (!denomination || Core.SELECTED_DENOMINATION.value === denomination) {\n            return;\n        }\n        Core.SELECTED_DENOMINATION.next(denomination);\n\n        this.updateBetIfDisabled('settingsBet');\n\n        this.clearDenominationSelection();\n\n        if (Core.SELECTED_DENOMINATION.value !== denomination) {\n            this.rootStore.uiStore.bets.forEach((_bet: number, index: number) => {\n                this['settingsBet' + (index + 1)].denomination = Core.SELECTED_DENOMINATION;\n            });\n        }\n\n        this.denominations.forEach((button, index) => {\n            button.enabled = true;\n            if (button.denominationValue === Core.SELECTED_DENOMINATION.value) {\n                button.selected = true;\n                this.rootStore.subjects.SETTINGS_DENOMINATION_CHANGED.next({\n                    denomination: index + 1,\n                    playDenomChangeSound: true,\n                });\n            }\n        });\n        if (\n            this.rootStore.settings.numberOfLinesPerDenomination &&\n            this.rootStore.settings.numberOfLinesPerDenomination.length\n        ) {\n            this.changeDenominationAndNumberOfLines(denomination);\n            this.linesChanged(this.rootStore.uiStore.LINES.value);\n        }\n        this.onBetOrDenominationChanged();\n        this.maxBetBuyBonusCheck();\n    }\n\n    protected updateBetIfDisabled(btnName: string) {\n        const selectedIndex = this.rootStore.uiStore.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value);\n        const currentSelectedButton: BetButton = this.find(btnName + (selectedIndex + 1));\n        if (!currentSelectedButton?.enabled) {\n            for (let i = selectedIndex - 1; i >= 0; i--) {\n                const leftButton: BetButton = this.find(btnName + (i + 1));\n                if (leftButton.enabled) {\n                    this.rootStore.uiStore.SELECTED_BET.next(this.rootStore.uiStore.bets[i]);\n                    this.rootStore.subjects.SETTINGS_BET_CHANGED.next();\n                    break;\n                }\n            }\n        }\n    }\n\n    protected clearDenominationSelection(): void {\n        this.rootStore.uiStore.denominations.forEach((_denomination, index) => {\n            this.denominations[index].selected = false;\n        });\n    }\n\n    protected denominationChanged(denomination: number): void {\n        this.clearDenominationSelection();\n\n        this.denominations.forEach((button) => {\n            button.enabled = true;\n            if (button.denominationValue === denomination) {\n                button.selected = true;\n            }\n        });\n\n        this.rootStore.uiStore.bets.forEach((_bet: number, index: number) => {\n            this['settingsBet' + (index + 1)].denomination = denomination;\n        });\n\n        this.onBetOrDenominationChanged();\n        this.maxBetBuyBonusCheck();\n    }\n\n    protected clearLinesSelection(): void {\n        this.winlinesOptions.forEach((_lines, index) => {\n            this.linesButtons[index].selected = false;\n        });\n    }\n\n    protected linesChanged(lines: number): void {\n        this.clearLinesSelection();\n\n        this.linesButtons.forEach((button: WinlinesButton) => {\n            button.selected = button.lines === lines;\n        });\n\n        this.betButtons.forEach((button: BetButton) => {\n            button.lines = this.rootStore.uiStore.LINES.value;\n        });\n    }\n\n    protected onBetChanged(betButton: string): void {\n        Core.sounds.play('changeBetSound');\n        this.rootStore.uiStore.SELECTED_BET.next(this[betButton].betPerLine);\n        this.rootStore.subjects.SETTINGS_BET_CHANGED.next();\n        this.onBetOrDenominationChanged();\n    }\n\n    protected clearBetSelection(): void {\n        this.rootStore.uiStore.bets.forEach((_bet, index) => {\n            this['settingsBet' + (index + 1)].selected = false;\n        });\n    }\n\n    protected stateChanged(): void {\n        if (this.rootStore.uiStore.STATE.value === UIState.BONUS_IDLE || this.feature.isInGiftSpins) {\n            this.betButtons.forEach((betButton) => {\n                betButton.enabled = false;\n            });\n            this.denominations.forEach((denominationButton, _index) => {\n                denominationButton.enabled = false;\n            });\n            this.linesButtons.forEach((lineButton, _index) => {\n                lineButton.enabled = lineButton.lines === this.rootStore.uiStore.LINES.value;\n            });\n            const betIndex = this.rootStore.uiStore.bets.indexOf(this.rootStore.uiStore.SELECTED_BET.value);\n            const denomIndex = this.rootStore.uiStore.denominations.indexOf(Core.SELECTED_DENOMINATION.value);\n            const bButton: BetButton = this.betButtons[betIndex];\n            bButton.enabled = true;\n            this.buttonsDisabled = true;\n            const dButton: Button = this.denominations[denomIndex];\n            dButton.enabled = true;\n        } else if (this.buttonsDisabled) {\n            this.buttonsDisabled = false;\n            this.betButtons.forEach((betButton) => {\n                betButton.enabled = true;\n            });\n            this.denominations.forEach((denominationButton) => {\n                denominationButton.enabled = true;\n            });\n            this.linesButtons.forEach((lineButton, _index) => {\n                lineButton.enabled = true;\n            });\n        }\n    }\n\n    protected onBalanceChanged(): void {\n        if (this.balanceValue) {\n            this.balanceValue.money = this.rootStore.uiStore.BALANCE.value;\n        }\n    }\n\n    protected updateBalanceFields(winValue: number): void {\n        const ceiledValue = Math.floor(winValue);\n        this.balanceValue.money = ceiledValue;\n    }\n\n    protected onCollect(response): void {\n        if (this.rootStore.uiStore.SHOW_SETTINGS.value) {\n            const winAmount = this.rootStore.uiStore.WIN.prevValue.amount;\n            const incrementValue: any = { money: 0 };\n            const currentBalance = this.rootStore.uiStore.BALANCE.value;\n            let toBalance = currentBalance;\n            let onUpdate = () => {\n                //\n            };\n\n            const duration = winAmount === 0 ? 0 : this.collectDuration;\n            toBalance += Number(winAmount);\n            onUpdate = () => {\n                const newBalance = Math.floor(currentBalance + incrementValue.money);\n                if (toBalance !== response.balance) {\n                    this.balanceValue.money = response.balance;\n                } else {\n                    this.updateBalanceFields(newBalance);\n                }\n            };\n            this.balanceTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/slot-components/settings-popup/src/egt/settings-views/bet/BetSettingsView.ts:895:33\",null]), gsap.to(incrementValue, {\n                duration,\n                money: winAmount,\n                ease: 'none',\n                onUpdate,\n            }));\n\n            (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/slot-components/settings-popup/src/egt/settings-views/bet/BetSettingsView.ts:902:13\",null]), gsap.to(this.balanceValue.scale, {\n                x: 1.05,\n                duration: (duration - 0.1) / 3,\n                repeat: 3,\n                yoyo: true,\n            }));\n        }\n    }\n\n    protected updateBetText(): void {\n        if (this.betValue) {\n            this.betValue.money = this.getTotalBet();\n        }\n    }\n\n    protected onBetOrDenominationChanged(): void {\n        this.updateBetText();\n        this.applyFontSize(this.initialValueFontSize);\n        this.betContainer.x = this.componentConfiguration.betViewProps.betContainerX - this.betContainer.width;\n    }\n\n    protected get factor(): number {\n        let factor: number;\n        if (this.rootStore.settings.factor) {\n            factor = this.rootStore.settings.factor;\n        } else {\n            factor = this.rootStore.uiStore.LINES.value;\n        }\n        return factor;\n    }\n\n    protected getTotalBet(): number {\n        const factor = this.rootStore.settings.factor\n            ? this.rootStore.settings.factor\n            : this.rootStore.uiStore.LINES.value;\n        return Core.SELECTED_DENOMINATION.value * this.rootStore.uiStore.SELECTED_BET.value * factor;\n    }\n\n    protected onFactorChanged(): void {\n        for (const betButton of this.betButtons) {\n            betButton.factor = this.rootStore.settings.factor;\n        }\n        this.updateBetText();\n\n        this.maxBetBuyBonusCheck();\n    }\n\n    protected maxBetBuyBonusCheck(): void {\n        const maxBetBuyBonus =\n            this.rootStore.settings.settings.settings.clientSettings.maxBetLimits &&\n            this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value\n                ? this.rootStore.settings.settings.settings.clientSettings.maxBetLimits[\n                      this.rootStore.settings.currency\n                  ]\n                : undefined;\n        if (!maxBetBuyBonus) {\n            this.denominations.forEach((denomination: DenominationButton) => {\n                denomination instanceof DenominationButton && denomination.enableButton(true);\n            });\n\n            return;\n        }\n\n        this.denominations.forEach((denomination: DenominationButton) => {\n            const hasActiveButtons = this.rootStore.uiStore.bets.every(\n                (bet: number) =>\n                    bet * denomination.denominationValue * this.factor >\n                    maxBetBuyBonus * Core.PLAYER_BALANCE.value.units,\n            );\n            denomination instanceof DenominationButton && denomination.enableButton(!hasActiveButtons);\n        });\n    }\n\n    protected getBetButtonsTextures(element: string[]): any[] {\n        return [\n            Core.assets.getAsset(element[ButtonStates.Normal]).texture,\n            Core.assets.getAsset(element[ButtonStates.Pressed]).texture,\n            Core.assets.getAsset(element[ButtonStates.Over]).texture,\n            Core.assets.getAsset(element[ButtonStates.Disabled]).texture,\n        ];\n    }\n\n    protected changeDenominationAndNumberOfLines(denomination: number): void {\n        if (\n            this.rootStore.settings.numberOfLinesPerDenomination &&\n            this.rootStore.settings.numberOfLinesPerDenomination.length\n        ) {\n            const [, numberOfLines] = this.rootStore.settings.numberOfLinesPerDenomination.find(\n                ([denominationConfig]) => denominationConfig === denomination,\n            )!;\n\n            if (this.rootStore.uiStore.LINES.value !== numberOfLines) {\n                this.rootStore.uiStore.LINES.next(numberOfLines!);\n            }\n        }\n    }\n\n    /**\n     * Changes the denomination depending on the number of lines.\n     * @param {WinlinesButton} winlineButton - The winline button that was clicked.\n     * @param {[number, number][]} numberOfLinesPerDenomination - The array of denomination and lines pairs.\n     * @returns {boolean} Whether the denomination was changed.\n     */\n    protected changeDenominationDependingOnLines(\n        winlineButton: WinlinesButton,\n        numberOfLinesPerDenomination: [number, number][], //[denomination, lines]\n    ): boolean {\n        const currentLinesValue = this.rootStore.uiStore.LINES.value;\n        const currentDenomination = Core.SELECTED_DENOMINATION.value;\n        const chosenLines = winlineButton.lines;\n        const linesOptions = this.rootStore.settings.linesOptions;\n\n        const linesObject: { [key: number]: number[] } = linesOptions.reduce((acc, curr) => {\n            acc[curr] = [];\n            return acc;\n        }, {});\n\n        numberOfLinesPerDenomination.forEach(([denomination, lines]) => {\n            if (this.rootStore.uiStore.denominations.indexOf(denomination) !== -1) {\n                linesObject[lines].push(denomination);\n            }\n        });\n\n        const currentDenomIndex = linesObject[currentLinesValue].indexOf(currentDenomination);\n        const nextDenomIndex =\n            currentDenomIndex + 1 > linesObject[chosenLines].length\n                ? linesObject[chosenLines].length - 1\n                : currentDenomIndex;\n\n        let nextDenominationDependingOnLines: number = linesObject[chosenLines][nextDenomIndex];\n        if (this.rootStore.uiStore.denominations.indexOf(nextDenominationDependingOnLines) === -1) {\n            nextDenominationDependingOnLines = currentDenomination;\n        }\n        const nextDenominationIndexDependingOnLines: number = this.rootStore.uiStore.denominations.indexOf(\n            nextDenominationDependingOnLines,\n        );\n\n        this.updateDenomination(this.rootStore.uiStore.denominations[nextDenominationIndexDependingOnLines!]);\n\n        return nextDenominationDependingOnLines !== currentDenomination;\n    }\n}\n","import Core, { GameTypes } from '@egt/core';\nimport { FeatureController, ISlotConfiguration, RootStore } from '@egt/slot';\nimport {\n    BetButton,\n    DenominationButton,\n    DenominationButtonDesktop,\n    ITitledWindowConfig,\n    MoneyText,\n    Text,\n    TitledWindow,\n    ViewContainer,\n    WinlinesButtonDesktop,\n} from '@egt/ui-lib';\nimport { Text as PixiText } from 'pixi.js';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { ISettingsPopupComponentConfiguration } from '../../interfaces/SettingsInterfaces';\nimport BetSettingsView from './BetSettingsView';\n\n@injectable()\nexport default class BetSettingsViewDesktop extends BetSettingsView {\n    public betButtonTextures: any[] = [];\n    public betButtonSelectedTextures: any[] = [];\n    // public betButtonsDesktop: BetButton[];\n    public winlinesButtonsDesktop: WinlinesButtonDesktop[];\n    public firstLineButtonsTopOffset: number;\n    private menuBody: TitledWindow;\n    private config: any;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected configuration: ISlotConfiguration,\n        @inject('SettingsPopupComponentConfiguration')\n        protected componentConfiguration: ISettingsPopupComponentConfiguration,\n        @inject('FeatureController') protected feature: FeatureController,\n    ) {\n        super(rootStore, configuration, componentConfiguration, feature);\n    }\n\n    public get panelDimensions(): any {\n        return { width: 770, height: 454, topOffset: 117 };\n    }\n\n    public destroy(): void {\n        super.destroy();\n        if (this.denominations) {\n            this.denominations.forEach((element) => {\n                element.destroy();\n                // @ts-ignore\n                element = null;\n            });\n            this.denominations.length = 0;\n            // @ts-ignore\n            this.denominations = null;\n        }\n        if (this.winlinesButtonsDesktop) {\n            this.winlinesButtonsDesktop.forEach((element) => {\n                element.destroy();\n                // @ts-ignore\n                element = null;\n            });\n            this.winlinesButtonsDesktop.length = 0;\n            // @ts-ignore\n            this.winlinesButtonsDesktop = null;\n        }\n        // if (this.betButtonsDesktop) {\n        //     this.betButtonsDesktop.forEach(element => {\n        //         element.destroy();\n        //         // @ts-ignore\n        //         element = null;\n        //     });\n        //     this.betButtonsDesktop.length = 0;\n        //     // @ts-ignore\n        //     this.betButtonsDesktop = null;\n        // }\n    }\n\n    // protected updateBetButtons(bet: number): void {\n    //     const betButton: BetButton = this.betButtonsDesktop.filter(button => {\n    //         return button.betPerLine === bet;\n    //     })[0];\n    //     this.clearBetSelection();\n    //     betButton.selected = true;\n    //     this.onBetOrDenominationChanged();\n    // }\n\n    protected setOrientation(): void {\n        const betButtonsOffset: number =\n            this.componentConfiguration.betViewProps.buttonsOffsetX[this.betButtons.length - 1];\n        // const butButtonTotalWidth: number = this.w + betButtonsOffset;\n        const topOffset: number = 54.6;\n        const textsTopOffset: number = 12;\n        const buttonsTopOffset: number = 6;\n        // const linesTopOffset: number = 64;\n\n        if (this.winlinesText) {\n            this.winlinesText.x = this.panelDimensions.width / 2;\n            this.winlinesText.y = topOffset; // this.denominations[0].y + this.denominations[0].height + textsTopOffset;\n        }\n\n        let winlinesSectionLeftOffset = 0;\n        if (this.winlinesButtonsDesktop[0]) {\n            winlinesSectionLeftOffset =\n                (this.panelDimensions.width -\n                    (this.winlinesButtonsDesktop.length * this.winlinesButtonsDesktop[0].width +\n                        (this.winlinesButtonsDesktop.length - 1) * betButtonsOffset)) /\n                2;\n        }\n\n        if (this.winlinesButtonsDesktop.length > 0) {\n            this.winlinesButtonsDesktop.forEach((winlineButton: WinlinesButtonDesktop, index: number): void => {\n                winlineButton.x = winlinesSectionLeftOffset + index * (winlineButton.width + betButtonsOffset);\n                const lineHieght = this.winlinesText.style.lineHeight ? this.winlinesText.style.lineHeight : 0;\n                winlineButton.y = this.winlinesText.y + lineHieght + buttonsTopOffset;\n            });\n        }\n\n        // this.winlinesBreakLine.anchor.x = 0.5;\n        // this.winlinesBreakLine.x = width / 2;\n        // this.winlinesBreakLine.y = this.winlinesButtons[0].y + this.winlinesButtons[0].height + linesTopOffset;\n        // this.winlinesBreakLine.visible = false;\n\n        this.positionBetsText(textsTopOffset);\n\n        const betsSectionLeftOffset =\n            (this.panelDimensions.width -\n                (this.betButtons.length * this.betButtons[0].width + (this.betButtons.length - 1) * betButtonsOffset)) /\n            2;\n\n        this.betButtons.forEach((betButton: BetButton, index: number): void => {\n            betButton.x = betsSectionLeftOffset + index * (betButton.width + betButtonsOffset);\n            const lineHieght = this.betsText.style.lineHeight ? this.betsText.style.lineHeight : 0;\n            betButton.y = this.betsText.y + lineHieght + buttonsTopOffset;\n        });\n\n        this.denominationText.x = this.panelDimensions.width / 2;\n        this.denominationText.y = this.betButtons[0].y + this.betButtons[0].height + textsTopOffset;\n\n        const denominationSectionLeftOffset =\n            (this.panelDimensions.width -\n                (this.denominations.length * this.denominations[0].width +\n                    (this.denominations.length - 1) * betButtonsOffset)) /\n            2;\n\n        this.denominations.forEach((denominationButton: DenominationButton, index: number): void => {\n            denominationButton.x =\n                denominationSectionLeftOffset + index * (denominationButton.width + betButtonsOffset);\n            const lineHieght = this.denominationText.style.lineHeight ? this.denominationText.style.lineHeight : 0;\n            denominationButton.y = this.denominationText.y + lineHieght + buttonsTopOffset;\n        });\n\n        this.balanceContainer.y = this.height - this.balanceContainer.height;\n        this.balanceContainer.x = 60;\n        this.betContainer.y = this.balanceContainer.y;\n        this.updateBetText();\n        this.betContainer.x = this.menuBody.width - this.betContainer.width - 60;\n    }\n\n    protected positionBetsText(textsTopOffset: number): void {\n        this.betsText.x = this.panelDimensions.width / 2;\n        this.betsText.y = this.winlinesButtonsDesktop[0].y + this.winlinesButtonsDesktop[0].height + textsTopOffset;\n    }\n\n    protected initialRender(): void {\n        this.createTextProps();\n        this.firstLineButtonsTopOffset = 6;\n        this.betButtonTextures = [\n            Core.assets.getAsset('svgBet').texture,\n            Core.assets.getAsset('svgBetPressed').texture,\n            Core.assets.getAsset('svgBetHover').texture,\n            Core.assets.getAsset('svgBet').texture,\n        ];\n        this.betButtonSelectedTextures = [\n            Core.assets.getAsset('svgActiveBet').texture,\n            Core.assets.getAsset('svgActiveBetPressed').texture,\n            Core.assets.getAsset('svgActiveBetHover').texture,\n            Core.assets.getAsset('svgActiveBet').texture,\n        ];\n\n        this.config = {} as ITitledWindowConfig;\n        // this.winlineButtonWidth = 94;\n        // this.winlineButtonHeight = 75;\n\n        this.config.width = this.panelDimensions.width;\n        this.config.height = this.panelDimensions.height;\n\n        this.config.borderLeftUpTexture = Core.assets.getTextureFromSpriteSheet('miscellaneous', 'windowCornerLu.png');\n        this.config.title = Core.translator.translate('BET SETTINGS');\n        this.config.titleStyle = this.componentConfiguration.tabNameProps.textStyle;\n        this.menuBody = new TitledWindow(this.config);\n        this.menuBody.x = 0;\n        this.menuBody.y = 0;\n        this.menuBody.interactive = true;\n        this.addChild(this.menuBody);\n\n        this.denominations = [];\n        this.winlinesButtonsDesktop = [];\n        // this.betButtonsDesktop = [];\n\n        this.denominationText = new PixiText(\n            Core.MONEY_MODE_IN_CREDITS.value\n                ? this.translator.translate('DENOMINATION')\n                : this.translator.translate('BET LEVELS'),\n            this.titleTextStyle,\n        );\n        this.denominationText.anchor.x = 0.5;\n        this.addChild(this.denominationText);\n\n        this.populateDenominations();\n\n        if (this.componentConfiguration.betViewProps.hasLinesSection) {\n            this.creatLinesSection();\n        } else {\n            this.createCustomSection();\n        }\n\n        // this.winlinesBreakLine = new Sprite();\n        // this.winlinesBreakLine.texture = Core.assets.getTextureFromSpriteSheet('UI', 'lineLong.png');\n        // this.addChild(this.winlinesBreakLine);\n\n        this.betsText = new PixiText(this.translator.translate('BET'), this.titleTextStyle);\n        this.betsText.anchor.x = 0.5;\n        this.addChild(this.betsText);\n\n        this.createBetButtons();\n        // biome-ignore lint/suspicious/noAssignInExpressions: <explanation>\n        this.betButtons.forEach((b) => (b.interactive = true));\n\n        this.balanceContainer = new ViewContainer();\n\n        this.balanceText = new Text(\n            this.balanceTextConfig,\n            Core.translator.translate('BALANCE') + ':',\n            this.balanceTextStyle,\n        );\n        this.balanceValue = new MoneyText(\n            this.balanceValueConfig,\n            this.rootStore.uiStore.BALANCE.value,\n            this.balanceValueStyle,\n        );\n\n        this.balanceContainer.addChild(this.balanceText);\n        this.balanceContainer.addChild(this.balanceValue);\n        this.balanceText.x = 0;\n        this.balanceText.y = 0;\n        // this.balanceValue.pivot.set(this.balanceValue.width / 2, 0);\n        this.balanceValue.x = this.balanceText.x + this.balanceText.width + this.balanceValue.pivot.x;\n        this.balanceValue.y = this.balanceText.y;\n        this.addChild(this.balanceContainer);\n\n        this.betContainer = new ViewContainer();\n\n        this.betText = new Text(this.betTextConfig, Core.translator.translate('BET') + ':', this.betTextStyle);\n\n        this.betValue = new MoneyText(this.betValueConfig, this.getTotalBet(), this.betValueStyle);\n        this.betContainer.addChild(this.betText);\n        this.betContainer.addChild(this.betValue);\n\n        this.betText.x = 0;\n        this.betText.y = this.balanceText.y;\n\n        this.betValue.x = this.betText.x + this.betText.width;\n        this.betValue.y = this.betText.y;\n        this.addChild(this.betContainer);\n    }\n\n    protected createTextProps(): void {\n        super.createTextProps();\n        this.balanceValueConfig.moneyFontSize =\n            this.balanceValueConfig.centsFontSize =\n            this.betValueConfig.centsFontSize =\n            this.betValueConfig.moneyFontSize =\n                18;\n        this.balanceValueConfig.currencyFontSize = this.betValueConfig.currencyFontSize = 9;\n        this.balanceValueConfig.bounds.height =\n            this.betValueConfig.bounds.height =\n            this.betTextConfig.bounds.height =\n            this.balanceTextConfig.bounds.height =\n                50;\n    }\n\n    protected creatLinesSection(): void {\n        this.winlinesText = new PixiText(this.translator.translate('LINES'), this.titleTextStyle);\n        this.winlinesText.anchor.x = 0.5;\n        this.addChild(this.winlinesText);\n\n        this.populateLines();\n    }\n\n    protected populateDenominations(): void {\n        this.rootStore.uiStore.denominations.forEach((denomination, index) => {\n            const denominationButton = this.createDesktopDenomination(\n                denomination,\n                'settingsDenomination' + (index + 1),\n                index,\n            );\n\n            this.addChild(denominationButton);\n            this.denominations.push(denominationButton);\n        });\n    }\n\n    protected populateLines(): void {\n        const isFixed: boolean = this.winlinesOptions.length === 1;\n        this.winlinesOptions.forEach((option: number, index: number) => {\n            // our interface if for max 5 buttons\n            if (index < 5) {\n                const isCurrent = option === this.rootStore.uiStore.LINES.value;\n                const winlineButton = new WinlinesButtonDesktop(\n                    'winlines',\n                    option,\n                    this.componentConfiguration.betViewProps.allButtonsBounds.width,\n                    this.componentConfiguration.betViewProps.allButtonsBounds.height,\n                    isCurrent && isFixed,\n                    this.betButtonTextures,\n                    this.betButtonSelectedTextures,\n                    isCurrent,\n                    this.componentConfiguration.betViewProps.winlineTextStyle,\n                    this.componentConfiguration.betViewProps.winlineTextOffsetY,\n                    this.componentConfiguration.betViewProps.winlinesButtonTextOffsetY,\n                    this.componentConfiguration.betViewProps.winlinesButtonTextOffsetX,\n                    this.componentConfiguration.betViewProps.defaultLinesValueTextStyle,\n                    this.componentConfiguration.betViewProps.selectedLinesValueTextStyle,\n                );\n                winlineButton.interactive = true;\n\n                winlineButton.CLICK.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n                    if (this.rootStore.uiStore.LINES.value !== winlineButton.lines) {\n                        let linesChanged = false;\n                        if (\n                            this.rootStore.settings.numberOfLinesPerDenomination &&\n                            this.rootStore.settings.numberOfLinesPerDenomination.length\n                        ) {\n                            linesChanged = super.changeDenominationDependingOnLines(\n                                winlineButton,\n                                this.rootStore.settings.numberOfLinesPerDenomination!,\n                            );\n                        }\n                        if (linesChanged) {\n                            this.rootStore.uiStore.LINES.next(winlineButton.lines);\n                            this.linesChanged(this.rootStore.uiStore.LINES.value);\n                        }\n                    }\n                });\n                // this.linesButtons.push(winlineButton);\n                // winlineButton.enabled = !isFixed;\n\n                if (this.configuration.gameType === GameTypes.WAYS_TO_PAY_SLOT) {\n                    this.winlinesText.visible = false;\n                    winlineButton.visible = false;\n                }\n\n                this.winlinesButtonsDesktop.push(winlineButton);\n                this.addChild(winlineButton);\n            }\n        });\n    }\n\n    // protected populateBets(): void {\n    //     this.rootStore.uiStore.bets.forEach((bet: number, index: number) => {\n    //         const betButton: BetButton = new BetButton({\n    //             name: 'settingsBet' + (index + 1),\n    //             betPerLine: bet,\n    //             currency: this.rootStore.uiStore.currency,\n    //             units: this.rootStore.uiStore.units,\n    //             denomination: Core.SELECTED_DENOMINATION.value,\n    //             lines: this.rootStore.uiStore.LINES.value,\n    //             factor: this.rootStore.settings.factor,\n    //             width: this.componentConfiguration.betButtons[index].get('betConfig').width,\n    //             height: this.componentConfiguration.betButtons[index].get('betConfig').height,\n    //             text: Core.translator.translate('BET'),\n    //             textures: this.getBetButtonsTextures(\n    //                 this.componentConfiguration.betButtons[index].get('betConfig').textures,\n    //             ),\n    //             selectedTextures: this.getBetButtonsTextures(\n    //                 this.componentConfiguration.betButtons[index].get('betConfig').selectedTextures,\n    //             ),\n    //             selected: false,\n    //             // betButtonStyles: this.configuration.betButtonStyles,\n    //             dynamicConfig: this.componentConfiguration.betButtons[index].get('betConfig'),\n    //         });\n\n    //         this['settingsBet' + (index + 1)] = betButton;\n\n    //         betButton.interactive = true;\n\n    //         betButton.CLICK.pipe(takeUntil(this.DESTROY)).subscribe(\n    //             this.onBetChanged.bind(this, 'settingsBet' + (index + 1)),\n    //         );\n\n    //         this.betButtonsDesktop.push(betButton);\n    //         this.addChild(betButton);\n\n    //         if (bet === this.rootStore.uiStore.SELECTED_BET.value) {\n    //             betButton.selected = true;\n    //         }\n    //     });\n    // }\n\n    protected createDesktopDenomination(denomination: number, name: string, index: number): DenominationButtonDesktop {\n        const denominationButtonTextures = [\n            Core.assets.getAsset('svgBet').texture,\n            Core.assets.getAsset('svgBetPressed').texture,\n            Core.assets.getAsset('svgBetHover').texture,\n            Core.assets.getAsset('svgBet').texture,\n        ];\n        const denominationSelectedTextures = [\n            Core.assets.getAsset('svgBetBlue').texture,\n            Core.assets.getAsset('svgBetBluePressed').texture,\n            Core.assets.getAsset('svgBetBlueHover').texture,\n            Core.assets.getAsset('svgBetBlue').texture,\n        ];\n\n        const denominationButton: DenominationButtonDesktop = new DenominationButtonDesktop(\n            name,\n            '1 ' + this.translator.translate('CREDIT') + ' =',\n            denomination,\n            this.rootStore.uiStore.currency,\n            this.componentConfiguration.betViewProps.allButtonsBounds.width,\n            this.componentConfiguration.betViewProps.allButtonsBounds.height,\n            index,\n            denominationButtonTextures,\n            denominationSelectedTextures,\n            denomination === Core.SELECTED_DENOMINATION.value,\n            this.configuration.denomButtonStyles,\n        );\n\n        denominationButton.interactive = true;\n\n        denominationButton.CLICK.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.updateDenomination.bind(this, denomination),\n        );\n\n        return denominationButton;\n    }\n\n    protected updateDenomination(denomination: number): void {\n        Core.SELECTED_DENOMINATION.next(denomination);\n        this.clearDenominationSelection();\n\n        if (Core.SELECTED_DENOMINATION.value !== denomination) {\n            this.rootStore.uiStore.bets.forEach((index: number) => {\n                this['settingsBet' + (index + 1)].denomination = Core.SELECTED_DENOMINATION;\n            });\n        }\n\n        this.denominations.forEach((button, index) => {\n            if (button.denominationValue === Core.SELECTED_DENOMINATION.value) {\n                button.selected = true;\n                this.rootStore.subjects.SETTINGS_DENOMINATION_CHANGED.next({\n                    denomination: index + 1,\n                    playDenomChangeSound: true,\n                });\n            }\n        });\n        if (\n            this.rootStore.settings.numberOfLinesPerDenomination &&\n            this.rootStore.settings.numberOfLinesPerDenomination.length\n        ) {\n            super.changeDenominationAndNumberOfLines(denomination);\n            this.linesChanged(this.rootStore.uiStore.LINES.value);\n        }\n        this.onBetOrDenominationChanged();\n    }\n\n    protected clearDenominationSelection(): void {\n        this.rootStore.uiStore.denominations.forEach((_denomination, index) => {\n            this.denominations[index].selected = false;\n        });\n    }\n\n    protected denominationChanged(denomination: number): void {\n        this.clearDenominationSelection();\n\n        this.denominations.forEach((button) => {\n            if (button.denominationValue === denomination) {\n                button.selected = true;\n            }\n        });\n\n        this.rootStore.uiStore.bets.forEach((_bet: number, index: number) => {\n            this['settingsBet' + (index + 1)].denomination = denomination;\n        });\n    }\n\n    protected clearLinesSelection(): void {\n        this.winlinesOptions.forEach((_lines, index) => {\n            this.winlinesButtonsDesktop[index].selected = false;\n        });\n    }\n\n    protected linesChanged(lines: number): void {\n        this.clearLinesSelection();\n\n        this.winlinesButtonsDesktop.forEach((button: WinlinesButtonDesktop) => {\n            if (button.lines === lines) {\n                button.selected = true;\n            }\n        });\n\n        this.betButtons.forEach((button: BetButton) => {\n            button.lines = this.rootStore.uiStore.LINES.value;\n        });\n    }\n\n    // protected onBetChanged(btn: string): void {\n    //     super.onBetChanged(btn);\n\n    //     const betButton: BetButton = this.betButtonsDesktop.filter(button => {\n    //         return button.betPerLine === this[btn].betPerLine;\n    //     })[0];\n    //     this.clearBetSelection();\n    //     betButton.selected = true;\n    // }\n\n    // protected onBetSelectedChanged(value: number): void {\n    //     const betButton: BetButton = this.betButtonsDesktop.filter(button => {\n    //         return button.betPerLine === value;\n    //     })[0];\n    //     this.clearBetSelection();\n    //     betButton.selected = true;\n    // }\n\n    // protected stateChanged(): void {\n    //     if (this.rootStore.uiStore.STATE.value === UIState.BONUS_IDLE) {\n    //         // this.betButtonsDesktop.forEach(betButton => {\n    //         //     betButton.enabled = false;\n    //         // });\n    //         this.denominations.forEach(denominationButton => {\n    //             denominationButton.enabled = false;\n    //         });\n\n    //         // const bButton: BetButton = this.betButtonsDesktop.filter(button => {\n    //         //     return button.betPerLine === this.rootStore.uiStore.SELECTED_BET.value;\n    //         // })[0];\n    //         // bButton.selected = true;\n    //         this.buttonsDisabled = true;\n    //     } else if (this.buttonsDisabled) {\n    //         this.buttonsDisabled = false;\n    //         // this.betButtonsDesktop.forEach(betButton => {\n    //         //     betButton.enabled = true;\n    //         // });\n    //         this.denominations.forEach(denominationButton => {\n    //             denominationButton.enabled = true;\n    //         });\n    //     }\n    // }\n\n    protected onBetOrDenominationChanged(): void {\n        super.updateBetText();\n        this.applyFontSize(this.initialValueFontSize);\n        this.betContainer.x = this.menuBody.width - this.betContainer.width - 60;\n    }\n\n    // protected onFactorChanged(): void {\n    //     for (const betButton of this.betButtonsDesktop) {\n    //         betButton.factor = this.rootStore.settings.factor;\n    //     }\n    // }\n}\n","import { ISlotConfiguration, RootStore } from '@egt/slot';\nimport {\n    Text,\n    IViewVisibilityContainer,\n    MoneyText,\n    MoneyTextConfig,\n    TextConfig,\n    ViewContainer,\n    ViewVisibilityContainer,\n    ButtonStates,\n    WinlinesButton,\n} from '@egt/ui-lib';\nimport { inject, injectable } from 'tsyringe';\nimport { Text as PixiText, Container, TextStyle } from 'pixi.js';\nimport { BetCalculatorViewDefault } from '@egt/bet-calculator';\nimport Core, { GameTypes, IOrientation } from '@egt/core';\nimport SettingsPopupSubjects from '../../subjects/SettingsPopupSubjects';\nimport { takeUntil } from 'rxjs/operators';\nimport { ISettingsPopupComponentConfiguration } from '../../interfaces/SettingsInterfaces';\nimport { gsap } from 'gsap';\n\n@injectable()\nexport default class OneDenomBetSettingsView extends ViewVisibilityContainer implements IViewVisibilityContainer {\n    public betCalculator: BetCalculatorViewDefault;\n    public mainContainer: Container;\n\n    protected linesButtons: WinlinesButton[] = [];\n    protected winlinesButtons: WinlinesButton[] = [];\n    protected balanceContainer: ViewContainer;\n    protected betContainer: ViewContainer;\n\n    protected winlinesOptions: number[] = [5, 10, 15, 20, 30];\n    protected winlinesText: PixiText = new PixiText('');\n    protected betsText: PixiText = new PixiText('');\n    protected balanceTextStyle: TextStyle = new TextStyle();\n    protected balanceTextConfig: TextConfig = new TextConfig();\n    protected betTextStyle: TextStyle = new TextStyle();\n    protected betTextConfig: TextConfig = new TextConfig();\n    protected balanceValueConfig: MoneyTextConfig = new MoneyTextConfig();\n    protected betValueConfig: MoneyTextConfig = new MoneyTextConfig();\n    protected betValueStyle: TextStyle = new TextStyle();\n    protected balanceValueStyle: TextStyle = new TextStyle();\n    protected balanceText: Text;\n    protected betText: Text;\n    protected balanceValue: MoneyText;\n    protected betValue: MoneyText;\n    protected initialValueFontSize: number = 0;\n    protected balanceTween: any;\n    protected collectDuration: number = this.configuration.collectBangupDuration;\n\n    protected titleTextStyle: TextStyle = new TextStyle();\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected configuration: ISlotConfiguration,\n        @inject('SettingsPopupSubjects') protected subjects: SettingsPopupSubjects,\n        @inject('SettingsPopupComponentConfiguration')\n        protected componentConfiguration: ISettingsPopupComponentConfiguration,\n    ) {\n        super();\n        this.init();\n    }\n\n    public init(): void {\n        this.betCalculator = Core.gameDependencyContainer.resolve('BetCalculator');\n        this.winlinesOptions = this.rootStore.settings.linesOptions;\n        this.initialRender();\n        this.rootStore.domainStore.COLLECT_RESPONSE.pipe(takeUntil(this.DESTROY)).subscribe(this.onCollect.bind(this));\n        this.subjects.AFTER_CLOSE.pipe(takeUntil(this.DESTROY)).subscribe(this.onAfterSettingsClose.bind(this));\n        this.rootStore.uiStore.BALANCE.pipe(takeUntil(this.DESTROY)).subscribe(this.onBalanceChanged.bind(this));\n        this.rootStore.subjects.DENOMINATIONS_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onDenominationsChanged.bind(this),\n        );\n        this.rootStore.uiStore.SELECTED_BET.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onBetOrDenominationChanged.bind(this),\n        );\n        Core.SELECTED_DENOMINATION.pipe(takeUntil(Core.ON_GAME_UNLOADED)).subscribe(\n            this.onBetOrDenominationChanged.bind(this),\n        );\n        this.rootStore.subjects.FACTOR_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(this.onFactorChanged.bind(this));\n\n        this.rootStore.subjects.BET_SETTINGS_TITLE.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onTitleChanged.bind(this),\n        );\n    }\n\n    public onDenominationsChanged() {\n        this.mainContainer.removeChild(this.betCalculator);\n        this.redrawView();\n    }\n\n    public redrawView(): void {\n        super.redrawView();\n        this.mainContainer.addChild(this.betCalculator);\n        this.betCalculator.resetCalculatorPopUp();\n        this.setOrientation(Core.ORIENTATION.value);\n    }\n\n    public onAfterSettingsClose(): void {\n        this.mainContainer.removeChild(this.betCalculator);\n    }\n\n    public initialRender(): void {\n        this.createMainContainer();\n        this.createTextProps();\n\n        if (this.componentConfiguration.betViewProps.hasLinesSection) {\n            this.creatLinesSection();\n        } else {\n            this.createCustomSection();\n        }\n\n        // ***** BETS SECTION *****\n        this.betsText = new PixiText(\n            Core.translator.translate(this.rootStore.subjects.BET_SETTINGS_TITLE.value),\n            this.titleTextStyle,\n        );\n        this.betsText.anchor.x = 0.5;\n        this.addChild(this.betsText);\n\n        // ***** BALANCE AND BET VALUES *****\n        this.balanceContainer = new ViewContainer();\n\n        this.balanceText = new Text(\n            this.balanceTextConfig,\n            Core.translator.translate('BALANCE') + ':',\n            this.balanceTextStyle,\n        );\n        this.balanceValue = new MoneyText(\n            this.balanceValueConfig,\n            this.rootStore.uiStore.BALANCE.value,\n            this.balanceValueStyle,\n        );\n\n        this.balanceContainer.addChild(this.balanceText);\n        this.balanceContainer.addChild(this.balanceValue);\n\n        this.addChild(this.balanceContainer);\n        this.betContainer = new ViewContainer();\n\n        this.betText = new Text(this.betTextConfig, Core.translator.translate('BET') + ':', this.betTextStyle);\n\n        this.betValue = new MoneyText(this.betValueConfig, this.getTotalBet(), this.betValueStyle);\n        this.betContainer.addChild(this.betText);\n        this.betContainer.addChild(this.betValue);\n\n        this.addChild(this.betContainer);\n        this.setBalanceAndBetInitialPositions();\n        this.checkBalanceValuePositionBasedOnDimensions();\n    }\n\n    protected creatLinesSection(): void {\n        // ***** LINES SECTION *****\n        this.winlinesText = new PixiText(Core.translator.translate('LINES'), this.titleTextStyle);\n        this.winlinesText.anchor.x = 0.5;\n        this.addChild(this.winlinesText);\n        this.createLinesButtons();\n    }\n\n    protected createLinesButtons(): void {\n        const linesButtonTextures = [\n            Core.assets.getAsset(this.componentConfiguration.betViewProps.winlinesButtonTextures[ButtonStates.Normal])\n                .texture,\n            Core.assets.getAsset(this.componentConfiguration.betViewProps.winlinesButtonTextures[ButtonStates.Pressed])\n                .texture,\n            Core.assets.getAsset(this.componentConfiguration.betViewProps.winlinesButtonTextures[ButtonStates.Pressed])\n                .texture,\n            Core.assets.getAsset(this.componentConfiguration.betViewProps.winlinesButtonTextures[ButtonStates.Disabled])\n                .texture,\n        ];\n        const linesButtonSelectedTextures = [\n            Core.assets.getAsset(\n                this.componentConfiguration.betViewProps.winlinesButtonSelectedTextures[ButtonStates.Disabled],\n            ).texture,\n            Core.assets.getAsset(\n                this.componentConfiguration.betViewProps.winlinesButtonSelectedTextures[ButtonStates.Disabled],\n            ).texture,\n            Core.assets.getAsset(\n                this.componentConfiguration.betViewProps.winlinesButtonSelectedTextures[ButtonStates.Disabled],\n            ).texture,\n            Core.assets.getAsset(\n                this.componentConfiguration.betViewProps.winlinesButtonSelectedTextures[ButtonStates.Disabled],\n            ).texture,\n        ];\n        const isFixed: boolean = this.winlinesOptions.length === 1;\n        this.winlinesOptions.forEach((option: number, index: number) => {\n            // our interface if for max 5 buttons\n            if (index < 5) {\n                const isCurrent = option === this.rootStore.uiStore.LINES.value;\n                const winlineButton = new WinlinesButton(\n                    'winlines',\n                    option,\n                    this.componentConfiguration.betViewProps.allButtonsBounds.width,\n                    this.componentConfiguration.betViewProps.allButtonsBounds.height,\n                    isCurrent && isFixed,\n                    linesButtonTextures,\n                    linesButtonSelectedTextures,\n                    isCurrent,\n                    this.componentConfiguration.betViewProps.winlineTextStyle,\n                    this.componentConfiguration.betViewProps.winlineTextOffsetY,\n                    this.componentConfiguration.betViewProps.winlinesButtonTextOffsetY,\n                    this.componentConfiguration.betViewProps.winlinesButtonTextOffsetX,\n                    this.componentConfiguration.betViewProps.defaultLinesValueTextStyle,\n                    this.componentConfiguration.betViewProps.selectedLinesValueTextStyle,\n                );\n                winlineButton.CLICK.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n                    if (this.rootStore.uiStore.LINES.value !== winlineButton.lines) {\n                        if (\n                            this.rootStore.settings.numberOfLinesPerDenomination &&\n                            this.rootStore.settings.numberOfLinesPerDenomination.length\n                        ) {\n                            this.changeDenominationDependingOnLines(\n                                winlineButton,\n                                this.rootStore.settings.numberOfLinesPerDenomination!,\n                            );\n                        }\n                        this.rootStore.uiStore.LINES.next(winlineButton.lines);\n                        this.linesChanged(this.rootStore.uiStore.LINES.value);\n                    }\n                });\n                winlineButton.pivot.set(winlineButton.width / 2, 0);\n                this.linesButtons.push(winlineButton);\n                // winlineButton.enabled = !isFixed;\n\n                if (this.configuration.gameType === GameTypes.WAYS_TO_PAY_SLOT) {\n                    this.winlinesText.visible = false;\n                    winlineButton.visible = false;\n                }\n\n                this.winlinesButtons.push(winlineButton);\n                this.addChild(winlineButton);\n            }\n        });\n    }\n\n    protected changeDenominationDependingOnLines(\n        winlineButton: WinlinesButton,\n        numberOfLinesPerDenomination: [number, number][], //[denomination, lines]\n    ): void {\n        // This functionality is for Higher denomination option reflectiong on lower number of lines and vice versa\n        const currentDenomination = Core.SELECTED_DENOMINATION.value;\n\n        const currentLinesValue = this.rootStore.uiStore.LINES.value;\n        const currentDenominationOptionIndex = numberOfLinesPerDenomination!.findIndex(\n            ([denomination, numberOfLines]) =>\n                denomination === currentDenomination && numberOfLines === currentLinesValue,\n        );\n        const lengthOfDenominationLinesPair = numberOfLinesPerDenomination.length;\n        let nextDenominationIndexDependingOnLines: number;\n\n        //Finding which index is the next denomination, taking it from the correspondig denomination/lines pair comparing to new lines selection;\n        if (currentDenominationOptionIndex === lengthOfDenominationLinesPair - 1) {\n            // Last index scenario\n            nextDenominationIndexDependingOnLines = numberOfLinesPerDenomination\n                .reduce((acc: number[], [, lines]) => {\n                    acc.push(lines);\n                    return acc;\n                }, [])\n                .lastIndexOf(winlineButton.lines);\n        } else if (currentDenominationOptionIndex === 0) {\n            //First index scenario\n            nextDenominationIndexDependingOnLines = numberOfLinesPerDenomination\n                .reduce((acc: number[], [, lines]) => {\n                    acc.push(lines);\n                    return acc;\n                }, [])\n                .findIndex((lines) => lines === winlineButton.lines);\n        } else {\n            // Handling middle scenarios, the comaparisment is with tha last index of the CURRENT line value, than checking if it is last from possible options;\n            const currentLinesValueLastIndex = numberOfLinesPerDenomination\n                .reduce((acc: number[], [, lines]) => {\n                    acc.push(lines);\n                    return acc;\n                }, [])\n                .lastIndexOf(currentLinesValue);\n            // In case of fifth denomination\n            const currentLinesValuefirstIndex = numberOfLinesPerDenomination\n                .reduce((acc: number[], [, lines]) => {\n                    acc.push(lines);\n                    return acc;\n                }, [])\n                .indexOf(currentLinesValue);\n\n            const isLastFromDenomintation = currentDenominationOptionIndex === currentLinesValueLastIndex;\n            const isFirstFromDenomination = currentDenominationOptionIndex === currentLinesValuefirstIndex;\n            const indexOffset = numberOfLinesPerDenomination.length % 2 === 0 ? 1 : 2;\n\n            // The expected behavior is to go from 2nd bet option to 4th bet option upon clicking the 25 lines option and vice versa (also from 5th to 2nd)\n            nextDenominationIndexDependingOnLines = isLastFromDenomintation\n                ? numberOfLinesPerDenomination.length - indexOffset\n                : isFirstFromDenomination\n                  ? 0\n                  : 1;\n        }\n        const denomination = Number(this.rootStore.uiStore.denominations[nextDenominationIndexDependingOnLines!]);\n\n        if (Core.SELECTED_DENOMINATION.value === denomination) {\n            return;\n        }\n        Core.SELECTED_DENOMINATION.next(denomination);\n        this.rootStore.uiStore.CURRENT_BET_LEVEL.next({\n            betLevel: this.rootStore.uiStore.SELECTED_BET.value,\n            denomLevel: Core.SELECTED_DENOMINATION.value,\n        });\n    }\n\n    protected clearLinesSelection(): void {\n        this.winlinesOptions.forEach((_lines, index) => {\n            this.linesButtons[index].selected = false;\n        });\n    }\n\n    protected linesChanged(lines: number): void {\n        this.clearLinesSelection();\n\n        this.linesButtons.forEach((button: WinlinesButton) => {\n            if (button.lines === lines) {\n                button.selected = true;\n            }\n        });\n    }\n\n    protected createCustomSection(): void {\n        // implement in extended class\n    }\n\n    private updateWinlinesTextPosition(): void {\n        if (this.winlinesText) {\n            this.winlinesText.x = this.componentConfiguration.oneDenomBetViewProps.winlinesTextX;\n            this.winlinesText.y = this.componentConfiguration.oneDenomBetViewProps.winlinesTextY;\n        }\n    }\n\n    private updateBetsTextPosition(widthBounds: number): void {\n        this.betsText.x = widthBounds / 2;\n        this.betsText.y = this.componentConfiguration.oneDenomBetViewProps.betsTextY;\n    }\n\n    protected updateBetText(): void {\n        if (this.betValue) {\n            this.betValue.money = this.getTotalBet();\n        }\n    }\n\n    protected onBetOrDenominationChanged(): void {\n        this.updateBetText();\n        this.betContainer.x = this.componentConfiguration.betViewProps.betContainerX - this.betContainer.width;\n    }\n\n    protected onFactorChanged(): void {\n        this.updateBetText();\n    }\n\n    protected onBalanceChanged(): void {\n        if (this.balanceValue) {\n            this.balanceValue.money = this.rootStore.uiStore.BALANCE.value;\n            this.checkBalanceValuePositionBasedOnDimensions();\n        }\n    }\n\n    protected updateBalanceFields(winValue: number): void {\n        const ceiledValue = Math.floor(winValue);\n        this.balanceValue.money = ceiledValue;\n        this.checkBalanceValuePositionBasedOnDimensions();\n    }\n\n    protected onMoneyModeChanged(): void {\n        this.onBalanceChanged();\n        this.onBetOrDenominationChanged();\n    }\n\n    protected onCollect(response): void {\n        if (this.rootStore.uiStore.SHOW_SETTINGS.value) {\n            const winAmount = this.rootStore.uiStore.WIN.prevValue.amount;\n            const incrementValue: any = { money: 0 };\n            const currentBalance = this.rootStore.uiStore.BALANCE.value;\n            let toBalance = currentBalance;\n            let onUpdate = () => {\n                //\n            };\n\n            const duration = winAmount === 0 ? 0 : this.collectDuration;\n            toBalance += Number(winAmount);\n            onUpdate = () => {\n                const newBalance = Math.floor(currentBalance + incrementValue.money);\n                if (toBalance !== response.balance) {\n                    this.balanceValue.money = response.balance;\n                    this.checkBalanceValuePositionBasedOnDimensions();\n                } else {\n                    this.updateBalanceFields(newBalance);\n                }\n            };\n            this.balanceTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/slot-components/settings-popup/src/egt/settings-views/bet/OneDenomBetSettingsView.ts:393:33\",null]), gsap.to(incrementValue, {\n                duration,\n                money: winAmount,\n                ease: 'none',\n                onUpdate,\n            }));\n\n            (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/slot-components/settings-popup/src/egt/settings-views/bet/OneDenomBetSettingsView.ts:400:13\",null]), gsap.to(this.balanceValue.scale, {\n                x: 1.05,\n                duration: (duration - 0.1) / 3,\n                repeat: 3,\n                yoyo: true,\n            }));\n        }\n    }\n\n    protected setOrientation(orientation: IOrientation): void {\n        // sets the pivot to (0, 0)\n        this.betCalculator.pivot.set(this.betCalculator.globalPosition.x, this.betCalculator.globalPosition.y);\n\n        let scaleFactor = 1;\n        this.mainContainer.scale.set(scaleFactor);\n        this.mainContainer.pivot.set(this.mainContainer.width / 2, 0);\n\n        if (this.mainContainer.height > this.componentConfiguration.betCalculatorProps.maxHeight) {\n            scaleFactor = this.componentConfiguration.betCalculatorProps.maxHeight / this.mainContainer.height;\n        }\n        this.mainContainer.scale.set(scaleFactor);\n\n        this.mainContainer.x = this.componentConfiguration.betCalculatorProps.x;\n        this.mainContainer.y = this.componentConfiguration.betCalculatorProps.y;\n\n        this.updateBalanceContainerPosition();\n        this.updateBetContainerPosition();\n        this.updateWinlinesTextPosition();\n        this.updateBetsTextPosition(this.getWidthBounds(orientation.width));\n        this.updateWinlinesButtonsPosition();\n    }\n\n    protected getTotalBet(): number {\n        const factor = this.rootStore.settings.factor\n            ? this.rootStore.settings.factor\n            : this.rootStore.uiStore.LINES.value;\n        return Core.SELECTED_DENOMINATION.value * this.rootStore.uiStore.SELECTED_BET.value * factor;\n    }\n\n    protected createTextProps(): void {\n        this.titleTextStyle = this.componentConfiguration.betViewProps.titleTextStyle;\n        this.balanceTextStyle = this.componentConfiguration.betViewProps.balanceTextStyle;\n        this.betTextStyle = this.componentConfiguration.betViewProps.betTextStyle;\n        this.betValueStyle = this.componentConfiguration.betViewProps.betValueStyle;\n        this.balanceValueStyle = this.componentConfiguration.betViewProps.balanceValueStyle;\n\n        this.balanceValueConfig.showCredits = false;\n        this.balanceValueConfig.showCurrency = true;\n\n        this.balanceValueConfig.currency = this.betValueConfig.currency = this.rootStore.uiStore.currency;\n        this.betValueConfig.shouldFitInBounds = this.balanceValueConfig.shouldFitInBounds = false;\n        this.balanceValueConfig.useMoneyMode = this.betValueConfig.useMoneyMode = false;\n        this.balanceValueConfig.bounds.width = 0;\n        this.betValueConfig.bounds.width = 0;\n        this.balanceValueConfig.moneyFontSize =\n            this.balanceValueConfig.centsFontSize =\n            this.betValueConfig.centsFontSize =\n            this.betValueConfig.moneyFontSize =\n                22;\n        this.balanceValueConfig.bounds.height =\n            this.betValueConfig.bounds.height =\n            this.betTextConfig.bounds.height =\n            this.balanceTextConfig.bounds.height =\n                50;\n        this.balanceValueConfig.spaceBetweenMoneyAndCurrency = this.betValueConfig.spaceBetweenMoneyAndCurrency = 4;\n    }\n\n    protected getButtonXPosition(index: number, length: number, buttonWidth: number): number {\n        const offset = this.componentConfiguration.betViewProps.buttonsOffsetX[length - 1];\n        return (\n            this.componentConfiguration.oneDenomBetViewProps.firstLinesButtonPositionsX[length - 1] +\n            index * (buttonWidth + offset)\n        );\n    }\n\n    private updateWinlinesButtonsPosition(): void {\n        if (this.winlinesButtons) {\n            this.winlinesButtons.forEach((button, index) => {\n                const positionX = this.getButtonXPosition(index, this.winlinesButtons.length, button.width);\n                button.x = positionX;\n                button.y = this.componentConfiguration.oneDenomBetViewProps.linesButtonsY;\n            });\n        }\n    }\n\n    private createMainContainer(): void {\n        this.mainContainer = new Container();\n        this.addChild(this.mainContainer);\n    }\n\n    private updateBalanceContainerPosition(): void {\n        this.balanceContainer.x = this.componentConfiguration.betViewProps.balanceContainerX;\n        this.balanceContainer.y = this.componentConfiguration.betViewProps.balanceContainerY;\n        this.checkBalanceValuePositionBasedOnDimensions();\n    }\n\n    private updateBetContainerPosition(): void {\n        this.betContainer.x = this.componentConfiguration.betViewProps.betContainerX - this.betContainer.width;\n        this.betContainer.y = this.componentConfiguration.betViewProps.betContainerY;\n    }\n\n    private getWidthBounds(defaultWidth: number): number {\n        return this.componentConfiguration.betViewProps.widthBounds || defaultWidth;\n    }\n\n    private onTitleChanged(): void {\n        this.betsText.text = Core.translator.translate(this.rootStore.subjects.BET_SETTINGS_TITLE.value);\n    }\n\n    private setBalanceAndBetInitialPositions(): void {\n        this.balanceText.x = 0;\n        this.balanceText.y = 0;\n        this.balanceValue.pivot.set(this.balanceValue.width / 2, 0);\n        this.balanceValue.x = this.balanceText.x + this.balanceText.width + this.balanceValue.pivot.x;\n        this.balanceValue.y = this.balanceText.y;\n        this.betText.x = 0;\n        this.betText.y = this.balanceText.y;\n\n        this.betValue.x = this.betText.x + this.betText.width;\n        this.betValue.y = this.betText.y;\n    }\n\n    private checkBalanceValuePositionBasedOnDimensions(): void {\n        this.setBalanceAndBetInitialPositions();\n        if (\n            this.balanceValue.width / this.balanceValue.scale.x >\n                this.componentConfiguration.oneDenomBetViewProps.balanceValueWidthBounds &&\n            Core.ORIENTATION.value.isLandscape &&\n            this.betCalculator.betButtons.length > 5\n        ) {\n            this.balanceValue.x = this.balanceValue.width / 2;\n            this.balanceText.y = this.balanceValue.y - this.balanceText.textBounds.height / 2;\n        }\n    }\n}\n","import Core, { IOrientation } from '@egt/core';\nimport { FeatureController, ISlotConfiguration, RootStore } from '@egt/slot';\nimport { ViewVisibilityContainer, WaysPayWinlinesButton } from '@egt/ui-lib';\nimport { Text as PixiText, Texture } from 'pixi.js';\nimport { inject, injectable } from 'tsyringe';\nimport { ISettingsPopupComponentConfiguration } from '../../interfaces/SettingsInterfaces';\nimport BetSettingsView from './BetSettingsView';\n\n@injectable()\nexport default class WaysPayBetSettingsView extends BetSettingsView implements ViewVisibilityContainer {\n    protected waysPayLinesButton: WaysPayWinlinesButton;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected configuration: ISlotConfiguration,\n        @inject('SettingsPopupComponentConfiguration')\n        protected componentConfiguration: ISettingsPopupComponentConfiguration,\n        @inject('FeatureController') protected feature: FeatureController,\n    ) {\n        super(rootStore, configuration, componentConfiguration, feature);\n    }\n\n    public destroy(): void {\n        this.waysPayLinesButton.destroy();\n        super.destroy();\n    }\n\n    // biome-ignore lint/suspicious/noEmptyBlockStatements: <explanation>\n    protected linesChanged(_lines: number): void {}\n\n    protected creatLinesSection(): void {\n        // ***** LINES SECTION *****\n        this.winlinesText = new PixiText(this.translator.translate('WAYS PAY'), this.titleTextStyle);\n        this.winlinesText.anchor.x = 0.5;\n        this.addChild(this.winlinesText);\n        this.createLinesButtons();\n    }\n\n    protected createLinesButtons(): void {\n        const lines = this.rootStore.uiStore.LINES.value;\n        const linesButtonTextures = this.getLinesButtonTextures();\n\n        this.waysPayLinesButton = new WaysPayWinlinesButton(\n            lines,\n            this.componentConfiguration.betButtonsConfigs.width,\n            this.componentConfiguration.betButtonsConfigs.height,\n            linesButtonTextures,\n        );\n\n        this.addChild(this.waysPayLinesButton);\n    }\n\n    protected getLinesButtonTextures(): Texture[] {\n        const textures = [\n            Core.assets.getAsset('svgActiveBet').texture,\n            Core.assets.getAsset('svgActiveBet').texture,\n            Core.assets.getAsset('svgActiveBet').texture,\n            Core.assets.getAsset('svgActiveBet').texture,\n        ];\n\n        return textures;\n    }\n\n    protected setOrientation(orientation: IOrientation): void {\n        super.setOrientation(orientation);\n        const waysPayButtonOffset: number = 20;\n\n        this.waysPayLinesButton.x = Core.display.stage.width / 2 - this.waysPayLinesButton.width / 2;\n        this.waysPayLinesButton.y = this.winlinesText.y + this.winlinesText.height + waysPayButtonOffset;\n\n        const betTextOffset: number = Core.ORIENTATION.value.isLandscape ? 20 : 106;\n        this.positionBetsText(orientation.width, betTextOffset);\n    }\n\n    protected positionBetsText(width: number, _textsTopOffset: number): void {\n        this.betsText.x = width / 2;\n\n        if (Core.ORIENTATION.value.isLandscape) {\n            this.betsText.y = 168;\n        } else {\n            this.betsText.y = 364;\n        }\n    }\n}\n","import Core from '@egt/core';\nimport { FeatureController, ISlotConfiguration, RootStore } from '@egt/slot';\nimport { WaysPayWinlinesButtonDesktop } from '@egt/ui-lib';\nimport { Text as PixiText, Texture } from 'pixi.js';\nimport { inject, injectable } from 'tsyringe';\nimport { ISettingsPopupComponentConfiguration } from '../../interfaces/SettingsInterfaces';\nimport BetSettingsViewDesktop from './BetSettingsViewDesktop';\n\n@injectable()\nexport default class WaysPayBetSettingsViewDesktop extends BetSettingsViewDesktop {\n    protected waysPayLinesButton: WaysPayWinlinesButtonDesktop;\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected configuration: ISlotConfiguration,\n        @inject('SettingsPopupComponentConfiguration')\n        protected componentConfiguration: ISettingsPopupComponentConfiguration,\n        @inject('FeatureController') protected feature: FeatureController,\n    ) {\n        super(rootStore, configuration, componentConfiguration, feature);\n    }\n\n    public destroy(): void {\n        this.waysPayLinesButton.destroy();\n        super.destroy();\n    }\n\n    // biome-ignore lint/suspicious/noEmptyBlockStatements: <explanation>\n    protected linesChanged(_lines: number): void {}\n\n    protected creatLinesSection(): void {\n        this.winlinesText = new PixiText(this.translator.translate('WAYS PAY'), this.titleTextStyle);\n        this.winlinesText.anchor.x = 0.5;\n        this.addChild(this.winlinesText);\n\n        this.populateLines();\n    }\n\n    protected populateLines(): void {\n        const lines = this.rootStore.uiStore.LINES.value;\n        const linesButtonTextures = this.getLinesButtonTextures();\n\n        this.waysPayLinesButton = new WaysPayWinlinesButtonDesktop(\n            lines,\n            this.componentConfiguration.betButtonsConfigs.width,\n            this.componentConfiguration.betButtonsConfigs.height,\n            linesButtonTextures,\n        );\n\n        this.addChild(this.waysPayLinesButton);\n    }\n\n    protected getLinesButtonTextures(): Texture[] {\n        const textures = [\n            Core.assets.getAsset('svgActiveBet').texture,\n            Core.assets.getAsset('svgActiveBet').texture,\n            Core.assets.getAsset('svgActiveBet').texture,\n            Core.assets.getAsset('svgActiveBet').texture,\n        ];\n\n        return textures;\n    }\n\n    // protected setOrientation(orientation: IOrientation): void {\n    //     super.setOrientation(orientation);\n    //     // const topOffset = 6;\n\n    //     this.waysPayLinesButton.x = this.componentConfiguration.betViewProps.widthBounds / 2 - this.waysPayLinesButton.width / 2;\n    //     this.waysPayLinesButton.y = this.winlinesText.y + this.winlinesText.height + this.componentConfiguration.betViewProps.buttonsOffsetY;\n    // }\n\n    protected setOrientation(): void {\n        super.setOrientation();\n        // const topOffset = 6;\n\n        this.waysPayLinesButton.x =\n            this.componentConfiguration.betViewProps.widthBounds / 2 - this.waysPayLinesButton.width / 2;\n        this.waysPayLinesButton.y =\n            this.winlinesText.y + this.winlinesText.height + this.componentConfiguration.betViewProps.buttonsOffsetY;\n    }\n\n    protected positionBetsText(_textsTopOffset: number): void {\n        this.betsText.x = this.componentConfiguration.betViewProps.widthBounds / 2;\n        this.betsText.y = 169;\n    }\n}\n","import Core, { IOrientation } from '@egt/core';\nimport {\n    OneDenomBetSettingsView,\n    ISettingsPopupComponentConfiguration,\n    SettingsPopupSubjects,\n} from '@egt/settings-popup';\nimport { ISlotConfiguration, RootStore } from '@egt/slot';\nimport { IViewVisibilityContainer, WaysPayWinlinesButton } from '@egt/ui-lib';\nimport { Text as PixiText, Texture } from 'pixi.js';\nimport { inject, injectable } from 'tsyringe';\n\n@injectable()\nexport default class WaysPayOneDenomBetSettingsView\n    extends OneDenomBetSettingsView\n    implements IViewVisibilityContainer\n{\n    protected waysPayLinesButton: WaysPayWinlinesButton;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected configuration: ISlotConfiguration,\n        @inject('SettingsPopupSubjects') protected subjects: SettingsPopupSubjects,\n        @inject('SettingsPopupComponentConfiguration')\n        protected componentConfiguration: ISettingsPopupComponentConfiguration,\n    ) {\n        super(rootStore, configuration, subjects, componentConfiguration);\n    }\n\n    public destroy(): void {\n        this.waysPayLinesButton.destroy();\n        super.destroy();\n    }\n\n    // biome-ignore lint/suspicious/noEmptyBlockStatements: <explanation>\n    protected linesChanged(_lines: number): void {}\n\n    protected creatLinesSection(): void {\n        // ***** LINES SECTION *****\n        this.winlinesText = new PixiText(Core.translator.translate('WAYS PAY'), this.titleTextStyle);\n        this.winlinesText.anchor.x = 0.5;\n        this.addChild(this.winlinesText);\n        this.createLinesButtons();\n    }\n\n    protected createLinesButtons(): void {\n        const lines = this.rootStore.uiStore.LINES.value;\n        const linesButtonTextures = this.getLinesButtonTextures();\n\n        this.waysPayLinesButton = new WaysPayWinlinesButton(\n            lines,\n            this.componentConfiguration.betButtonsConfigs.width,\n            this.componentConfiguration.betButtonsConfigs.height,\n            linesButtonTextures,\n        );\n        this.waysPayLinesButton.pivot.set(this.waysPayLinesButton.width / 2, 0);\n        this.addChild(this.waysPayLinesButton);\n    }\n\n    protected getLinesButtonTextures(): Texture[] {\n        const textures = [\n            Core.assets.getAsset('svgActiveBet').texture,\n            Core.assets.getAsset('svgActiveBet').texture,\n            Core.assets.getAsset('svgActiveBet').texture,\n            Core.assets.getAsset('svgActiveBet').texture,\n        ];\n\n        return textures;\n    }\n\n    protected setOrientation(orientation: IOrientation): void {\n        super.setOrientation(orientation);\n\n        const positionX = this.getButtonXPosition(0, 1, this.waysPayLinesButton.width);\n        this.waysPayLinesButton.x = positionX;\n        this.waysPayLinesButton.y = this.componentConfiguration.oneDenomBetViewProps.linesButtonsY;\n    }\n}\n","import Core, { AnalyticsDispatcher, IOrientation, PostMessageDispatcher } from '@egt/core';\nimport { Features, ISlotConfiguration, InitialSettings, RootStore } from '@egt/slot';\nimport { Button, IViewVisibilityContainer, ToggleButton, ViewVisibilityContainer } from '@egt/ui-lib';\nimport { Container, NineSlicePlane, Text, TextStyle } from 'pixi.js';\nimport { takeUntil } from 'rxjs/operators';\nimport Icon from 'slot-features/ui-lib/src/egt/ui/Icon';\nimport { inject, injectable } from 'tsyringe';\nimport {\n    ISettingsItemConfig,\n    ISettingsItemParts,\n    ISettingsPopupComponentConfiguration,\n    SettingsItemT,\n} from '../../interfaces/SettingsInterfaces';\n\n@injectable()\nexport default class GeneralSettingsView extends ViewVisibilityContainer implements IViewVisibilityContainer {\n    protected leftHandContainer: Container;\n    protected leftHandBackground: NineSlicePlane;\n    protected leftHandIcon: Icon;\n    protected leftHandTextsContainer: Container;\n    protected leftHandText: Text;\n    protected leftHandExplainText: Text;\n    protected leftHandButton: ToggleButton;\n\n    protected quickSpinContainer: Container;\n    protected quickSpinBackground: NineSlicePlane;\n    protected quickSpinIcon: Icon;\n    protected quickSpinTextsContainer: Container;\n    protected quickSpinText: Text;\n    protected quickSpinExplainText: Text;\n    protected quickSpinButton: ToggleButton;\n\n    protected turboSpinContainer: Container;\n    protected turboSpinBackground: NineSlicePlane;\n    protected turboSpinIcon: Icon;\n    protected turboSpinTextsContainer: Container;\n    protected turboSpinText: Text;\n    protected turboSpinExplainText: Text;\n    protected turboSpinButton: ToggleButton;\n\n    protected batterySaveModeContainer: Container;\n    protected batterySaveModeBackground: NineSlicePlane;\n    protected batterySaveModeIcon: Icon;\n    protected batterySaveModeTextsContainer: Container;\n    protected batterySaveModeText: Text;\n    protected batterySaveModeExplainText: Text;\n    protected batterySaveModeButton: ToggleButton;\n\n    protected soundsContainer: Container;\n    protected soundsBackground: NineSlicePlane;\n    protected soundsIcon: Icon;\n    protected soundsTextsContainer: Container;\n    protected soundsText: Text;\n    protected soundsExplainText: Text;\n    protected soundsButton: ToggleButton;\n\n    protected soundsBackgroundMusicContainer: Container;\n    protected soundsBackgroundMusicBackground: NineSlicePlane;\n    protected soundsBackgroundMusicIcon: Icon;\n    protected soundsBackgroundMusicTextsContainer: Container;\n    protected soundsBackgroundMusicText: Text;\n    protected soundsBackgroundMusicExplainText: Text;\n    protected soundsBackgroundMusicButton: ToggleButton;\n\n    protected historyContainer: Container;\n    protected historyBackground: NineSlicePlane;\n    protected historyText: Text;\n    protected historyButton: Button;\n\n    protected textsStyle: TextStyle;\n\n    protected italicTextsStyle: TextStyle;\n\n    protected settingsItemParts: Record<SettingsItemT, ISettingsItemParts>;\n\n    protected itemsConfig: ISettingsItemConfig[] = [\n        {\n            name: 'sounds',\n            text: 'SOUNDS',\n            explainText: 'SOUNDS EXPLANATION',\n            icons: { on: 'soundEffectsOn', off: 'soundEffectsOff' },\n            selected: true,\n            landscapePosition: 'left',\n            visible: true,\n        },\n        {\n            name: 'soundsBackgroundMusic',\n            text: 'BACKGROUND SOUNDS',\n            explainText: 'BACKGROUND SOUNDS EXPLANATION',\n            icons: { on: 'musicOn', off: 'musicOff' },\n            selected: true,\n            landscapePosition: this.componentConfiguration.generalSettingsProps.hasBackgroundMusicContainer\n                ? 'left'\n                : 'right',\n            visible: this.componentConfiguration.generalSettingsProps.hasBackgroundMusicContainer,\n        },\n        {\n            name: 'batterySaveMode',\n            text: 'BATTERY SAVE MODE',\n            explainText: 'BATTERY SAVE MODE EXPLANATION',\n            icons: { on: 'batterySaverModeOn', off: 'batterySaverModeOff' },\n            selected: false,\n            landscapePosition: 'right',\n            visible: true,\n        },\n        {\n            name: 'leftHand',\n            text: 'LEFT HAND MODE',\n            explainText: 'LEFT HAND MODE EXPLANATION',\n            icons: { on: 'leftHandModeOn', off: 'leftHandModeOff' },\n            selected: false,\n            landscapePosition: this.componentConfiguration.generalSettingsProps.hasBackgroundMusicContainer\n                ? this.componentConfiguration.generalSettingsProps.hasLeftHandModeContainer\n                    ? 'right'\n                    : 'left'\n                : 'left',\n            visible:\n                this.componentConfiguration.generalSettingsProps.hasLeftHandModeContainer &&\n                Core.configuration.mode !== 'kiosk',\n        },\n        {\n            name: 'quickSpin',\n            text: 'QUICK SPIN',\n            explainText: 'QUICK SPIN EXPLANATION',\n            icons: { on: 'quickSpinOn', off: 'quickSpinOff' },\n            selected: false,\n            landscapePosition: 'left',\n            visible: this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value === 0,\n        },\n        {\n            name: 'turboSpin',\n            text: 'TURBO SPIN',\n            explainText: 'TURBO SPIN EXPLANATION',\n            icons: { on: 'turboSpinOn', off: 'turboSpinOff' },\n            selected: false,\n            landscapePosition: 'right',\n            visible: this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value === 0,\n        },\n        {\n            name: 'history',\n            text: 'HISTORY',\n            selected: false,\n            landscapePosition: 'right',\n            visible: !Core.configuration.demo && !this.settings.settings.settings.jurisdiction.hidePlayerHistory,\n        },\n    ];\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected configuration: ISlotConfiguration,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('SettingsPopupComponentConfiguration')\n        protected componentConfiguration: ISettingsPopupComponentConfiguration,\n    ) {\n        super();\n        this.init();\n    }\n\n    public init(): void {\n        this.settingsItemParts = {\n            leftHand: {\n                container: this.leftHandContainer,\n                background: this.leftHandBackground,\n                icon: this.leftHandIcon,\n                textsContainer: this.leftHandTextsContainer,\n                text: this.leftHandText,\n                explainText: this.leftHandExplainText,\n                button: this.leftHandButton,\n            },\n            quickSpin: {\n                container: this.quickSpinContainer,\n                background: this.quickSpinBackground,\n                icon: this.quickSpinIcon,\n                textsContainer: this.quickSpinTextsContainer,\n                text: this.quickSpinText,\n                explainText: this.quickSpinExplainText,\n                button: this.quickSpinButton,\n            },\n            turboSpin: {\n                container: this.turboSpinContainer,\n                background: this.turboSpinBackground,\n                icon: this.turboSpinIcon,\n                textsContainer: this.turboSpinTextsContainer,\n                text: this.turboSpinText,\n                explainText: this.turboSpinExplainText,\n                button: this.turboSpinButton,\n            },\n            batterySaveMode: {\n                container: this.batterySaveModeContainer,\n                background: this.batterySaveModeBackground,\n                icon: this.batterySaveModeIcon,\n                textsContainer: this.batterySaveModeTextsContainer,\n                text: this.batterySaveModeText,\n                explainText: this.batterySaveModeExplainText,\n                button: this.batterySaveModeButton,\n            },\n            sounds: {\n                container: this.soundsContainer,\n                background: this.soundsBackground,\n                icon: this.soundsIcon,\n                textsContainer: this.soundsTextsContainer,\n                text: this.soundsText,\n                explainText: this.soundsExplainText,\n                button: this.soundsButton,\n            },\n            soundsBackgroundMusic: {\n                container: this.soundsBackgroundMusicContainer,\n                background: this.soundsBackgroundMusicBackground,\n                icon: this.soundsBackgroundMusicIcon,\n                textsContainer: this.soundsBackgroundMusicTextsContainer,\n                text: this.soundsBackgroundMusicText,\n                explainText: this.soundsBackgroundMusicExplainText,\n                button: this.soundsBackgroundMusicButton,\n            },\n            history: {\n                container: this.historyContainer,\n                background: this.historyBackground,\n                text: this.historyText,\n                button: this.historyButton,\n            },\n        };\n        this.initialRender();\n        Core.sounds.ON_SOUND_MUTED.pipe(takeUntil(this.DESTROY)).subscribe(this.onSoundMuted.bind(this));\n        if (this.componentConfiguration.generalSettingsProps.hasBackgroundMusicContainer) {\n            Core.sounds.ON_BACKGROUND_SOUNDS_MUTED.pipe(takeUntil(this.DESTROY)).subscribe(\n                this.onBackgroundSoundMuted.bind(this),\n            );\n        }\n        if (this.settingsItemParts.quickSpin.container) {\n            this.rootStore.subjects.TOGGLE_QUICK_SPIN.pipe(takeUntil(this.DESTROY)).subscribe(\n                this.onQuickSpinToggled.bind(this),\n            );\n        }\n        if (this.settingsItemParts.turboSpin.container) {\n            this.rootStore.subjects.TOGGLE_TURBO_SPIN.pipe(takeUntil(this.DESTROY)).subscribe(\n                this.onTurboSpinToggled.bind(this),\n            );\n        }\n        this.show = false;\n    }\n\n    public destroy(_options?: { children?: boolean; texture?: boolean; baseTexture?: boolean }): void {\n        super.destroy.call(this, arguments);\n        Object.keys(this).forEach((key: string) => {\n            if (this[key] && !key.includes('_') && !(this[key] instanceof Function)) {\n                this[key] = null;\n            }\n        });\n    }\n\n    public redrawView(): void {\n        this.setOrientation(Core.ORIENTATION.value);\n    }\n\n    protected positionSettingItem(\n        item: ISettingsItemParts,\n        lastElementYPosition: number,\n        landscapePosition?: 'left' | 'right',\n    ): void {\n        const X_OFFSET = this.componentConfiguration.generalSettingsProps.generalXOffset;\n\n        const {\n            containerBaseHeight,\n            containerBaseWidth,\n            containerPadding,\n            explainTextsYOffset,\n            leftContainerInitialXOffset,\n            rightContainerInitialXOffset,\n            iconXOffset,\n            hasDesktopView,\n        } = this.componentConfiguration.generalSettingsProps;\n\n        const { container, background, icon, textsContainer, text, explainText, button } = item;\n        text.scale.set(1);\n        if (text.width > this.componentConfiguration.generalSettingsProps.titleTextWrapBounds) {\n            text.scale.set(this.componentConfiguration.generalSettingsProps.titleTextWrapBounds / text.width);\n        }\n\n        // Explain Text\n        if (explainText) {\n            explainText.y = text.height + explainTextsYOffset;\n        }\n\n        // Background\n        background.height = containerBaseHeight;\n        background.width = containerBaseWidth;\n        background.x = -containerPadding;\n        background.y = -containerPadding;\n\n        // Background Height\n        if (container.height > containerBaseHeight) {\n            background.height += container.height - containerBaseHeight + containerPadding;\n        }\n\n        // Texts Container\n        if (textsContainer?.name === 'historyTextsContainer') {\n            textsContainer.x = -containerPadding + X_OFFSET + button.width + iconXOffset;\n            textsContainer.y = (container.height - textsContainer.height) / 2 - containerPadding;\n        }\n\n        if (textsContainer && icon) {\n            textsContainer.x = -containerPadding + X_OFFSET + icon.width + iconXOffset;\n            textsContainer.y = (container.height - textsContainer.height) / 2 - containerPadding;\n        }\n\n        // Icon\n        if (icon) {\n            icon.x = -containerPadding + X_OFFSET;\n            icon.y = (background.height - icon.height) / 2 - containerPadding;\n        }\n\n        // Button\n        if (button.name === 'historyButton') {\n            button.x = -containerPadding + X_OFFSET;\n        } else {\n            button.x = background.width - button.width - containerPadding - X_OFFSET;\n        }\n        button.y = (container.height - button.height) / 2 - containerPadding;\n\n        // Container\n        if (hasDesktopView && Core.isDesktopMode) {\n            container.x = leftContainerInitialXOffset;\n        } else {\n            container.x = Core.ORIENTATION.value.isLandscape\n                ? landscapePosition === 'right'\n                    ? rightContainerInitialXOffset\n                    : leftContainerInitialXOffset\n                : leftContainerInitialXOffset;\n        }\n\n        container.y = lastElementYPosition;\n    }\n\n    protected setOrientation(orientation: IOrientation): void {\n        // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n        const { x, y, titleTextWrapBounds, explainTextsWrapBounds, containersInitialY, containersYOffset } =\n            this.componentConfiguration.generalSettingsProps;\n\n        this.italicTextsStyle.wordWrapWidth = explainTextsWrapBounds;\n        this.y = y;\n        this.x = x;\n\n        if (orientation.isLandscape) {\n            let lastLeftElementYPosition: number = containersInitialY;\n            let lastRightElementYPosition: number = containersInitialY;\n\n            this.itemsConfig.map((item) => {\n                if (item.visible) {\n                    const settingsItem = this.settingsItemParts[item.name];\n                    this.positionSettingItem(\n                        settingsItem,\n                        item.landscapePosition === 'left' ? lastLeftElementYPosition : lastRightElementYPosition,\n                        item.landscapePosition,\n                    );\n\n                    const containerHeight = this.getContainerHeight(settingsItem.container);\n\n                    if (item.landscapePosition === 'left') {\n                        lastLeftElementYPosition += containerHeight + containersYOffset;\n                    } else {\n                        lastRightElementYPosition += containerHeight + containersYOffset;\n                    }\n                }\n            });\n        } else {\n            let lastElementYPosition: number = containersInitialY;\n\n            this.itemsConfig.map((item) => {\n                if (item.visible) {\n                    const settingsItem = this.settingsItemParts[item.name];\n                    this.positionSettingItem(settingsItem, lastElementYPosition);\n\n                    const containerHeight = this.getContainerHeight(settingsItem.container);\n                    lastElementYPosition += containerHeight + containersYOffset;\n                }\n            });\n        }\n    }\n\n    protected settingsItemBuilder(settingsItem: ISettingsItemConfig): void {\n        const { toggleButtonTextures, historyButtonTexture, iconHeight, iconWidth } =\n            this.componentConfiguration.generalSettingsProps;\n        const settingName = settingsItem.name;\n        const currentItem = this.settingsItemParts[settingName];\n\n        // Container\n        currentItem.container = new Container();\n        currentItem.container.name = `${settingName}Container`;\n        currentItem.container.sortableChildren = true;\n        this.addChild(currentItem.container);\n\n        // Texts Container\n        currentItem.textsContainer = new Container();\n        currentItem.textsContainer.name = `${settingName}TextsContainer`;\n\n        if (settingName === 'history') {\n            currentItem.textsContainer.interactive = true;\n            currentItem.textsContainer.buttonMode = true;\n        }\n\n        // Text\n        currentItem.text = new Text(Core.translator.translate(settingsItem.text), this.textsStyle);\n        currentItem.textsContainer.addChild(currentItem.text);\n\n        // Explain Text\n        if (settingsItem.explainText) {\n            currentItem.explainText = new Text(\n                Core.translator.translate(settingsItem.explainText),\n                this.italicTextsStyle,\n            );\n            currentItem.textsContainer.addChild(currentItem.explainText);\n        }\n        currentItem.container.addChild(currentItem.textsContainer);\n\n        // Button\n        if (settingName !== 'history') {\n            currentItem.button = new ToggleButton(\n                new Button([Core.assets.getAsset(toggleButtonTextures[0]).texture]),\n                new Button([Core.assets.getAsset(toggleButtonTextures[1]).texture]),\n            );\n            currentItem.button.selected = settingsItem.selected;\n        } else {\n            currentItem.button = new Button([Core.assets.getAsset(historyButtonTexture).texture]);\n            currentItem.button.width = iconWidth;\n            currentItem.button.height = iconHeight;\n        }\n        currentItem.button.name = `${settingName}Button`;\n        currentItem.container.addChild(currentItem.button);\n\n        // Background\n        currentItem.background = new NineSlicePlane(\n            Core.assets.getTextureFromSpriteSheet('popupFill', 'popupFill.png'),\n            25,\n            25,\n            25,\n            25,\n        );\n        currentItem.background.name = `${settingName}Background`;\n        currentItem.container.addChildAt(currentItem.background, 0);\n\n        // Icon\n        if (settingsItem.icons) {\n            currentItem.icon = new Icon(\n                Core.assets.getAsset(settingsItem.icons?.on).texture,\n                Core.assets.getAsset(settingsItem.icons?.off).texture,\n            );\n            currentItem.icon.width = iconWidth;\n            currentItem.icon.height = iconHeight;\n            currentItem.icon.name = `${settingName}Icon`;\n            currentItem.icon.selected = settingsItem.selected;\n            currentItem.container.addChild(currentItem.icon);\n        }\n\n        // Add functionality to buttons\n        this.buttonsManager(currentItem.button);\n    }\n\n    protected buttonsManager(button: ISettingsItemParts['button']): void {\n        switch (button.name) {\n            case 'soundsButton':\n                //@ts-ignore\n                this.settingsItemParts.sounds.button.SWITCH.pipe(takeUntil(this.DESTROY)).subscribe(\n                    (enabled: boolean) => {\n                        Core.sounds.ON_SOUND_MUTED.next(!enabled);\n                        PostMessageDispatcher.toggleSound(enabled);\n                        if (this.settingsItemParts.sounds.icon) {\n                            this.settingsItemParts.sounds.icon.selected = enabled;\n                        }\n                        if (enabled) {\n                            Core.sounds.play('unmuteSound');\n                        }\n                    },\n                );\n                break;\n\n            case 'soundsBackgroundMusicButton':\n                //@ts-ignore\n                this.settingsItemParts.soundsBackgroundMusic.button.SWITCH.pipe(takeUntil(this.DESTROY)).subscribe(\n                    (enabled: boolean) => {\n                        Core.sounds.ON_BACKGROUND_SOUNDS_MUTED.next(!enabled);\n                        if (this.settingsItemParts.soundsBackgroundMusic.icon) {\n                            this.settingsItemParts.soundsBackgroundMusic.icon.selected = enabled;\n                        }\n                        if (enabled) {\n                            Core.sounds.play('unmuteSound');\n                        }\n                    },\n                );\n                break;\n\n            case 'batterySaveModeButton':\n                //@ts-ignore\n                this.settingsItemParts.batterySaveMode.button.SWITCH.pipe(takeUntil(this.DESTROY)).subscribe(\n                    (enabled: boolean) => {\n                        Core.BATTERY_SAVE_MODE.next(enabled);\n                        if (this.settingsItemParts.batterySaveMode.icon) {\n                            this.settingsItemParts.batterySaveMode.icon.selected = enabled;\n                        }\n                        enabled ? Core.sounds.play('menuSound') : Core.sounds.play('menuSound');\n                    },\n                );\n                break;\n\n            case 'leftHandButton':\n                //@ts-ignore\n                this.settingsItemParts.leftHand.button.SWITCH.pipe(takeUntil(this.DESTROY)).subscribe(\n                    (enabled: boolean) => {\n                        Core.LEFT_HAND_MODE.next(enabled);\n                        if (this.settingsItemParts.leftHand.icon) {\n                            this.settingsItemParts.leftHand.icon.selected = enabled;\n                        }\n                        enabled ? Core.sounds.play('menuSound') : Core.sounds.play('menuSound');\n                    },\n                );\n                break;\n\n            case 'quickSpinButton':\n                //@ts-ignore\n                this.settingsItemParts.quickSpin.button.SWITCH.pipe(takeUntil(this.DESTROY)).subscribe(\n                    (enabled: boolean) => {\n                        this.rootStore.subjects.TOGGLE_TURBO_SPIN.next(false);\n                        this.rootStore.subjects.TOGGLE_QUICK_SPIN.next(enabled);\n                        enabled\n                            ? this.rootStore.subjects.SPIN_SPEED.next(1)\n                            : this.rootStore.subjects.SPIN_SPEED.next(0);\n                        if (this.settingsItemParts.quickSpin.icon) {\n                            this.settingsItemParts.quickSpin.icon.selected = enabled;\n                        }\n                        enabled ? Core.sounds.play('turboQuickOn') : Core.sounds.play('turboQuickOff');\n                    },\n                );\n                break;\n\n            case 'turboSpinButton':\n                //@ts-ignore\n                this.settingsItemParts.turboSpin.button.SWITCH.pipe(takeUntil(this.DESTROY)).subscribe(\n                    (enabled: boolean) => {\n                        this.rootStore.subjects.TOGGLE_QUICK_SPIN.next(false);\n                        this.rootStore.subjects.TOGGLE_TURBO_SPIN.next(enabled);\n                        enabled\n                            ? this.rootStore.subjects.SPIN_SPEED.next(2)\n                            : this.rootStore.subjects.SPIN_SPEED.next(0);\n                        if (this.settingsItemParts.turboSpin.icon) {\n                            this.settingsItemParts.turboSpin.icon.selected = enabled;\n                        }\n                        enabled ? Core.sounds.play('turboQuickOn2') : Core.sounds.play('turboQuickOff');\n                    },\n                );\n                break;\n\n            case 'historyButton':\n                //@ts-ignore\n                this.settingsItemParts.history.button.CLICK.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n                    this.openHistoryUrl();\n                });\n                if (this.settingsItemParts.history.textsContainer) {\n                    (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/slot-components/settings-popup/src/egt/settings-views/general/GeneralSettingsView.ts:557:21\",(this.settingsItemParts.history.textsContainer),\"pointertap\"]), this.settingsItemParts.history.textsContainer.on('pointertap', () => {\n                        this.openHistoryUrl();\n                    }));\n                }\n                this.settingsItemParts.history.button.interactive = true;\n                break;\n        }\n    }\n\n    protected initialRender(): void {\n        this.textsStyle = this.componentConfiguration.generalSettingsProps.textStyle;\n        this.italicTextsStyle = this.componentConfiguration.generalSettingsProps.italicTextStyle;\n\n        this.itemsConfig.map((item) => {\n            if (item.visible) {\n                this.settingsItemBuilder(item);\n            }\n        });\n    }\n\n    protected getContainerHeight(container: ISettingsItemParts['container']): number {\n        return container.height;\n    }\n\n    protected openHistoryUrl(): void {\n        // ON-95860: we use ssi object instead Core.configuration.historyHost because\n        // if there is no ssi settings client get its from build config\n        if (!window['ssi']?.historyHost || window['ssi']?.historyHost === '' || Core.configuration.mode === 'kiosk') {\n            PostMessageDispatcher.openPlayerHistory();\n        } else {\n            let url =\n                Core.configuration.historyHost +\n                `?gameKey=${Core.configuration.gameKey}&sessionKey=${Core.configuration.sessionKey}&playerId=${Core.configuration.playerId}&lang=${Core.configuration.language}`;\n\n            // This will become Features.BRANDING and\n            // will send the brand when the feature is reworked to universal\n            if (Core.hasFeature(Features.BRANDING)) {\n                url += '&branding=' + this.settings.clientSettings.branding;\n            }\n            window.open(url);\n        }\n        AnalyticsDispatcher.playerHistoryClicked();\n    }\n\n    private onSoundMuted(): void {\n        const { sounds, soundsBackgroundMusic } = this.settingsItemParts;\n\n        sounds.button.selected = !Core.sounds.ON_SOUND_MUTED.value;\n        if (sounds.icon) {\n            sounds.icon.selected = !Core.sounds.ON_SOUND_MUTED.value;\n        }\n\n        if (!this.componentConfiguration.generalSettingsProps.hasBackgroundMusicContainer) {\n            return;\n        }\n\n        if (Core.sounds.ON_SOUND_MUTED.value) {\n            soundsBackgroundMusic.container.alpha = 0.5;\n            soundsBackgroundMusic.button.enabled = false;\n        } else {\n            soundsBackgroundMusic.container.alpha = 1;\n            soundsBackgroundMusic.button.enabled = true;\n        }\n        this.onBackgroundSoundMuted();\n    }\n\n    private onBackgroundSoundMuted(): void {\n        const isSelected = this.settingsItemParts.sounds.button.selected\n            ? !Core.sounds.ON_BACKGROUND_SOUNDS_MUTED.value\n            : !Core.sounds.ON_SOUND_MUTED.value;\n\n        this.settingsItemParts.soundsBackgroundMusic.button.selected = isSelected;\n        if (this.settingsItemParts.soundsBackgroundMusic.icon) {\n            this.settingsItemParts.soundsBackgroundMusic.icon.selected = isSelected;\n        }\n    }\n\n    private onQuickSpinToggled(): void {\n        this.settingsItemParts.quickSpin.button.selected = this.rootStore.subjects.TOGGLE_QUICK_SPIN.value;\n    }\n\n    private onTurboSpinToggled(): void {\n        this.settingsItemParts.turboSpin.button.selected = this.rootStore.subjects.TOGGLE_TURBO_SPIN.value;\n    }\n}\n","import Core from '@egt/core';\nimport { ISlotConfiguration, InitialSettings, RootStore } from '@egt/slot';\nimport { ITitledWindowConfig, TitledWindow } from '@egt/ui-lib';\nimport { inject, injectable } from 'tsyringe';\nimport { ISettingsPopupComponentConfiguration } from '../../interfaces/SettingsInterfaces';\nimport GeneralSettingsView from './GeneralSettingsView';\n\n@injectable()\nexport default class GeneralSettingsViewDesktop extends GeneralSettingsView {\n    // private historyBreakLine: Sprite;\n    private menuBody: TitledWindow;\n    private config: any;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected configuration: ISlotConfiguration,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('SettingsPopupComponentConfiguration')\n        protected componentConfiguration: ISettingsPopupComponentConfiguration,\n    ) {\n        super(rootStore, configuration, settings, componentConfiguration);\n    }\n\n    public get panelDimensions(): any {\n        return { width: 804, height: 546, topOffset: 84 };\n    }\n\n    protected setOrientation(): void {\n        const { containersInitialY, containersYOffset, explainTextsWrapBounds } =\n            this.componentConfiguration.generalSettingsProps;\n\n        // this.textsStyle.wordWrapWidth = titleTextWrapBounds;\n        this.italicTextsStyle.wordWrapWidth = explainTextsWrapBounds;\n\n        let lastYPositionElement: number = containersInitialY;\n\n        this.itemsConfig.map((item) => {\n            if (item.visible) {\n                const settingsItem = this.settingsItemParts[item.name];\n                this.positionSettingItem(settingsItem, lastYPositionElement);\n\n                const containerHeight = this.getContainerHeight(settingsItem.container);\n                lastYPositionElement += containerHeight + containersYOffset;\n            }\n        });\n\n        if (this.menuBody) {\n            const lastElementPadding = containersYOffset * 1.5;\n            const finalHeight = lastYPositionElement + lastElementPadding;\n            this.menuBody.height = Math.max(finalHeight, this.panelDimensions.height);\n        }\n    }\n\n    protected initialRender(): void {\n        this.textsStyle = this.componentConfiguration.generalSettingsProps.textStyle;\n        this.italicTextsStyle = this.componentConfiguration.generalSettingsProps.italicTextStyle;\n\n        this.config = {} as ITitledWindowConfig;\n\n        this.config.width = this.panelDimensions.width;\n        this.config.height = this.panelDimensions.height;\n\n        this.config.borderLeftUpTexture = Core.assets.getTextureFromSpriteSheet('miscellaneous', 'windowCornerLu.png');\n        this.config.title = Core.translator.translate('GENERAL SETTINGS');\n        this.config.titleStyle = this.componentConfiguration.tabNameProps.textStyle;\n        this.menuBody = new TitledWindow(this.config);\n        this.menuBody.x = 0;\n        this.menuBody.y = 0;\n        this.menuBody.interactive = true;\n        this.addChild(this.menuBody);\n\n        this.itemsConfig.map((item) => {\n            if (item.visible) {\n                this.settingsItemBuilder(item);\n            }\n        });\n    }\n}\n","import Core, {\n    FeatureFlags,\n    GameTypes,\n    IContentLoadData,\n    Language,\n    PostMessageDispatcher,\n    RestrictionType,\n    Timers,\n} from '@egt/core';\nimport { Features, InitialSettings, ISlotConfiguration, RootStore, SlotComponents, SlotGameLayouts } from '@egt/slot';\nimport { BuyBonusModes } from '@egt/buy-bonus';\nimport { ITitledWindowConfig, IViewVisibilityContainer, TitledWindow, ViewVisibilityContainer } from '@egt/ui-lib';\nimport { Rectangle } from 'pixi.js';\nimport { merge } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport SettingsTab from '../../enums/SettingsTab';\nimport { ISettingsPopupComponentConfiguration } from '../../interfaces/SettingsInterfaces';\n\n@injectable()\nexport default class HelpView extends ViewVisibilityContainer implements IViewVisibilityContainer {\n    // private timeOut: NodeJS.Timeout;\n    protected helpHTMLDiv: any;\n    protected htmlElement: any;\n    // private html: string;\n    private closeEvent: any;\n    private panelIsOpen: boolean = false;\n    private externalHelps: Map<string, HTMLElement> = new Map();\n    private gameKey: string;\n    private menuBody: TitledWindow;\n    private config: any;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('SettingsPopupComponentConfiguration')\n        protected componentConfiguration: ISettingsPopupComponentConfiguration,\n    ) {\n        super();\n        this.init();\n    }\n\n    public init(): void {\n        if (this.componentConfiguration.helpViewProps.showDesktopVersion) {\n            this.interactive = true;\n            this.generateHelpContainer();\n        }\n        this.name = 'helpView';\n        this.htmlElement = document.documentElement;\n        this.gameKey =\n            this.slotConfiguration.cloneGameKey && this.slotConfiguration.setCloneGameKeyForHelpAssets\n                ? this.slotConfiguration.cloneGameKey\n                : Core.configuration.gameKey;\n        // this.rootStore.subjects.OPEN_HELP_POPUP.pipe(takeUntil(this.DESTROY)).subscribe(this.showHideHelp.bind(this));\n        Core.CONTENT_LOADED.pipe(takeUntil(this.DESTROY)).subscribe(this.onHTMLLoaded.bind(this));\n        this.rootStore.subjects.SETTINGS_POPUP_OPENED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.popupOpened.bind(this),\n        );\n        this.rootStore.subjects.CLOSE_SETTINGS_POPUP.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            Core.LOADING_ASSETS.next(false);\n            this.panelIsOpen = false;\n        });\n\n        this.rootStore.subjects.FACTOR_CHANGED.pipe(takeUntil(this.DESTROY)).subscribe(this.onFactorChanged.bind(this));\n\n        // const openEvent = merge(this.rootStore.subjects.SETTINGS_POPUP_OPENED, this.rootStore.subjects.OPEN_HELP_POPUP);\n        this.rootStore.subjects.OPEN_HELP_POPUP.pipe(takeUntil(this.DESTROY)).subscribe(this.showHideHelp.bind(this));\n\n        this.closeEvent = merge(\n            this.DESTROY,\n            this.rootStore.subjects.CLOSE_SETTINGS_POPUP,\n            this.rootStore.subjects.CLOSE_ALL_POPUPS,\n        );\n        this.closeEvent.pipe(takeUntil(this.DESTROY)).subscribe(this.showHideHelp.bind(this, false));\n        this.show = false;\n    }\n\n    public destroy(_options?: { children?: boolean; texture?: boolean; baseTexture?: boolean }): void {\n        this.hideHTML();\n        if (this.htmlElement) {\n            this.htmlElement.style.fontSize = null;\n        }\n        this.closeEvent = null;\n        this.htmlElement = null;\n\n        super.destroy({ children: true, texture: true, baseTexture: true });\n    }\n\n    public redrawView(): void {\n        // Log.debug('*** ORIENTATION REDRAW FOR ', this.constructor.name);\n        this.resizeDiv();\n    }\n\n    protected popupOpened(): void {\n        this.panelIsOpen = true;\n        if (this.rootStore.uiStore.SELECTED_SETTINGS_TAB.value === SettingsTab.HELP) {\n            this.showHideHelp(true);\n        }\n    }\n\n    protected attachEvents(): void {\n        // if (Core.environment.getDeviceType() === 'mobile') {\n        //     // Core.ORIENTATION.pipe(\n        //     //     filter(x => this.VISIBLE.value),\n        //     //     takeUntil(this.DESTROY)).subscribe(this.redrawView.bind(this));\n        // }\n        // Core.MEDIA_INFO_UPDATED.pipe(takeUntil(this.closeEvent)).subscribe(this.resizeDiv.bind(this));\n        Core.SHOW_ERROR.pipe(takeUntil(this.DESTROY)).subscribe(this.onErrorShown.bind(this));\n        Core.HIDE_ERROR.pipe(takeUntil(this.DESTROY)).subscribe(this.onErrorClosed.bind(this));\n\n        Core.STAGE_RESIZE_END.pipe(takeUntil(this.DESTROY)).subscribe(this.resizeDiv.bind(this));\n    }\n\n    protected resizeDiv(): void {\n        if (!this.helpHTMLDiv) {\n            return;\n        }\n        const stage = Core.stage.getMediaInfo().display.stage;\n        const scale = stage.currentWidth / stage.initialWidth;\n        const fontSize = (this.componentConfiguration.helpViewProps.fontSize * scale).toFixed(4) + 'px';\n\n        if (this.helpHTMLDiv.style.display !== 'none' && this.htmlElement.style.fontSize !== fontSize) {\n            this.htmlElement.style.fontSize = fontSize;\n        }\n        // this.debug('r=' + this.htmlElement.style.fontSize + \"=\" + fontSize);\n        // const headerSize = this.parent ? (this.parent as SettingsPopup).headerHeight : 55;\n\n        // const headerHeight: number = (headerSize + 2) * Number(stage.scaleY);\n        const headerHeight: number = this.componentConfiguration.helpViewProps.headerHeight * Number(stage.scaleY);\n        const buttonsHeight: number = this.componentConfiguration.helpViewProps.buttonsHeight * Number(stage.scaleY);\n        const bottomHeight: number = this.componentConfiguration.helpViewProps.bottomHeight * Number(stage.scaleY);\n\n        const offsetX: number = document?.getElementById('app-canvas')?.offsetLeft || 0;\n\n        const area = new Rectangle();\n\n        if (this.componentConfiguration.paytableViewProps.showDesktopVersion) {\n            area.x =\n                (Core.display.stage.width * Number(stage.scaleX) -\n                    this.componentConfiguration.helpViewProps.widthBounds * Number(stage.scaleX)) /\n                    2 +\n                stage.x +\n                offsetX;\n            area.y =\n                this.componentConfiguration.helpViewProps.viewTopOffset * Number(stage.scaleY) +\n                headerHeight +\n                this.componentConfiguration.helpViewProps.additionalHeaderHeightOffsetY +\n                stage.y;\n            area.width =\n                this.componentConfiguration.helpViewProps.widthBounds * scale -\n                this.componentConfiguration.helpViewProps.widthReduce;\n            area.height =\n                this.componentConfiguration.helpViewProps.heightBounds * Number(stage.scaleY) -\n                headerHeight -\n                this.componentConfiguration.helpViewProps.heightReduce;\n        } else {\n            area.x = stage.x + (offsetX && offsetX + this.componentConfiguration.helpViewProps.offsetX);\n            area.y = stage.y + headerHeight + this.componentConfiguration.helpViewProps.offsetY;\n            area.width = stage.currentWidth;\n            area.height = stage.currentHeight - (headerHeight + buttonsHeight + bottomHeight);\n        }\n\n        // const area = new Rectangle(\n        //     stage.x + (offsetX && offsetX + this.componentConfiguration.helpViewProps.offsetX),\n        //     stage.y + headerHeight + this.componentConfiguration.helpViewProps.offsetY,\n        //     stage.currentWidth,\n        //     stage.currentHeight - (headerHeight + buttonsHeight + bottomHeight),\n        // );\n\n        this.helpHTMLDiv.style.top = area.y + 'px';\n\n        this.helpHTMLDiv.style.left = area.x + 'px';\n        this.helpHTMLDiv.style.width = area.width + 'px';\n        this.helpHTMLDiv.style.height = area.height + 'px';\n\n        // document.body.style.display = 'none';\n        // Timers.setTimeout(() => {\n        //     document.body.style.display = 'block';\n        // }, 20);\n    }\n\n    // using timeot until to start resizeng where resize is finished\n    // hide content until resize\n    // private onResize(): void {\n    //     if (!this.helpHTMLDiv) {\n    //         this.helpHTMLDiv = document.getElementById('helpHTMLDiv') as HTMLDivElement;\n    //     }\n    //     if (!this.helpHTMLDiv) {\n    //         return;\n    //     }\n    //     this.helpHTMLDiv.style.display = 'none';\n    //     Timers.clearTimeout(this.timeOut);\n    //     this.timeOut = Timers.setTimeout(() => {\n    //         this.resizeDiv();\n    //         this.helpHTMLDiv.style.display = 'block';\n    //     }, 100);\n    // }\n\n    private showHideHelp(show: boolean | undefined): void {\n        if (show === undefined) {\n            show = this.rootStore.uiStore.SELECTED_SETTINGS_TAB.value === SettingsTab.HELP;\n        }\n        if (!show) {\n            this.hideHTML();\n            this.htmlElement.style.fontSize = null;\n        } else {\n            if (this.helpHTMLDiv !== undefined && this.panelIsOpen) {\n                this.showHTML();\n            } else if (this.helpHTMLDiv === undefined) {\n                this.loadHTML();\n                this.attachEvents();\n            } else if (!document.getElementById('helpHTMLDiv') && this.panelIsOpen) {\n                const appDiv = document.getElementById('app-root');\n                appDiv?.appendChild(this.helpHTMLDiv);\n            }\n        }\n    }\n\n    // if we have to hide - remove from dom and remove listnere\n    private hideHTML(): void {\n        // notify parent an HTML window is shown / closed\n        Core.environment.showHelperWhenAsked = true;\n        // window.removeEventListener('resize', this.onResize.bind(this));\n        const helpHTMLDiv = document.getElementById('helpHTMLDiv') as HTMLDivElement;\n        if (helpHTMLDiv && helpHTMLDiv.parentElement) {\n            PostMessageDispatcher.htmlClosed('help');\n            helpHTMLDiv.parentElement.removeChild(helpHTMLDiv);\n        }\n        return;\n    }\n\n    // if we have to show - check is loaded. if not loaded\n    // show ajax loader and when is done - display it\n    private showHTML(): void {\n        // we still have urls for loading or panel open is not finished\n        if (this.rootStore.uiStore.SELECTED_SETTINGS_TAB.value !== SettingsTab.HELP) {\n            return;\n        }\n        if ((this.externalHelps.size > 0 && document.getElementById('helpHTMLDiv')) || !this.panelIsOpen) {\n            return;\n        }\n        // not gated on isMobileIos(): the fullscreen hand also runs on iPads, the flag is a no-op elsewhere\n        Core.environment.showHelperWhenAsked = false;\n        // notify parent an HTML window is shown / closed\n\n        Core.LOADING_ASSETS.next(false);\n        // this.helpHTMLDiv = (document.getElementById('helpHTMLDiv') || document.createElement('div')) as HTMLDivElement;\n        if (!document.getElementById('helpHTMLDiv')) {\n            PostMessageDispatcher.htmlOpened('help');\n            this.resizeDiv();\n            // this.helpHTMLDiv.innerHTML = this.html;\n            this.helpHTMLDiv.id = 'helpHTMLDiv';\n            (this.helpHTMLDiv as HTMLDivElement).setAttribute('lang', Core.configuration.language);\n            this.helpHTMLDiv.className =\n                (Core.isDesktopMode ? 'desktop noselect' : 'mobile noselect') + ' ' + this.gameKey;\n            const appDiv = document.getElementById('app-root');\n            appDiv?.appendChild(this.helpHTMLDiv);\n            // document.body.insertAdjacentElement('afterbegin', this.helpHTMLDiv);\n            // problems with iPhones when started in landscape\n            if (Core.environment.isIosBrowser && Core.ORIENTATION.value.isLandscape) {\n                Core.LOADING_ASSETS.next(true);\n                this.helpHTMLDiv.style.display = 'none';\n                Timers.setTimeout(() => {\n                    this.resizeDiv();\n                    this.helpHTMLDiv.style.display = 'block';\n                    Core.LOADING_ASSETS.next(false);\n                }, 1000);\n            }\n        } else {\n            this.resizeDiv();\n        }\n        if (Core.gameLayout === SlotGameLayouts.TURTLE) {\n            this.helpHTMLDiv.classList.add('TURTLE_LAYOUT');\n        } else {\n            this.helpHTMLDiv.classList.remove('TURTLE_LAYOUT');\n        }\n    }\n\n    private loadHTML(): void {\n        Core.LOADING_ASSETS.next(true);\n        const url = 'assets/help/' + Core.configuration.language.toLowerCase() + '.html?' + Core.hash;\n        Core.requestManager.get(url, 'HELP');\n    }\n\n    private onHTMLLoaded(res: IContentLoadData): void {\n        if (res.param === 'HELP' && !this.helpHTMLDiv) {\n            this.helpHTMLDiv = document.createElement('div');\n            this.helpHTMLDiv.id = 'helpHTMLDiv';\n            this.helpHTMLDiv.innerHTML = this.reformatHTML(res.data).innerHTML;\n            // hide and load all conditional\n            const conditionals = this.helpHTMLDiv.querySelectorAll('[conditional]');\n            Array.from(conditionals).forEach((condition: HTMLElement) => {\n                const conditions = condition.getAttribute('conditional');\n                if (conditions) {\n                    const features: string[] = conditions.split('|');\n                    const conditionPassed = this.checkConditions(conditions);\n\n                    if (!conditionPassed) {\n                        const elements = this.helpHTMLDiv.querySelectorAll('[conditional=\"' + conditions + '\"]');\n                        if (elements.length) {\n                            // console.log(\"CONDITION:\", conditions, conditionPassed, elements[0].parentElement);\n                            elements[0].parentElement?.removeChild(elements[0]);\n                        }\n                    } else if (features.length === 1) {\n                        const url = condition.getAttribute('src');\n                        if (url && !this.externalHelps.has(conditions)) {\n                            this.externalHelps.set(conditions, condition);\n\n                            const { restrictionFolderPath, lang } = this.checkRestrictions(conditions);\n\n                            switch (url) {\n                                case 'gamble':\n                                    Core.requestManager.get(\n                                        '/assets/features/slot/gamble/help/gamble/' +\n                                            restrictionFolderPath +\n                                            lang +\n                                            '.html?' +\n                                            Core.hash,\n                                        conditions,\n                                    );\n                                    break;\n                                default:\n                                    Core.requestManager.get(\n                                        '../assets/help/' +\n                                            url +\n                                            '/' +\n                                            restrictionFolderPath +\n                                            lang +\n                                            '.html?' +\n                                            Core.hash,\n                                        conditions,\n                                    );\n                                    break;\n                            }\n                        }\n                    }\n                }\n            });\n            this.showHTML();\n        } else {\n            if (this.externalHelps.has(res.param)) {\n                // res.data = this.addVipJackpotPrefixIfNeeded(res);\n\n                const externalDiv = this.reformatHTML(res.data);\n\n                // hide all conditional\n                const externalConditionals = externalDiv.querySelectorAll('[conditional]');\n                Array.from(externalConditionals).forEach((externalCondition: HTMLElement) => {\n                    const externalConditions = externalCondition.getAttribute('conditional');\n                    if (externalConditions) {\n                        if (!this.checkConditions(externalConditions)) {\n                            const externalElements = externalDiv.querySelectorAll(\n                                '[conditional=\"' + externalConditions + '\"]',\n                            );\n                            if (externalElements.length) {\n                                // console.log(\"CONDITION:\", conditions, conditionPassed, elements[0].parentElement);\n                                externalElements[0].parentElement?.removeChild(externalElements[0]);\n                            }\n                        }\n                    }\n                });\n                const tempDiv = document.createElement('div');\n                const html = externalDiv.innerHTML;\n                const elements = this.helpHTMLDiv.querySelectorAll('[conditional=\"' + res.param + '\"]');\n                Array.from(elements).forEach((element: HTMLElement) => {\n                    if (element.getAttribute('src')) {\n                        const sectionName = element.getAttribute('section');\n                        if (sectionName) {\n                            tempDiv.innerHTML = html;\n                            const sectionDivs = tempDiv.querySelectorAll('[section=\"' + sectionName + '\"]');\n                            element.innerHTML = '';\n                            Array.from(sectionDivs).forEach((sectionDiv: HTMLElement) => {\n                                element.innerHTML += sectionDiv.outerHTML;\n                            });\n                        } else {\n                            element.innerHTML = html;\n                        }\n                    }\n                });\n                // let element = this.externalHelps.get(res.param) as HTMLElement;\n                this.externalHelps.delete(res.param);\n                this.resizeDiv();\n                this.showHTML();\n            }\n        }\n    }\n\n    private checkRestrictions(feature: string): any {\n        const lang: string = Core.configuration.language.toLowerCase();\n        let restrictionFolderPath: string = '';\n\n        // No early-return guard: counting active JURISDICTION-group flags never reached zero — the\n        // group also holds ALLOW_AUTOPLAY_POPUP and ALLOW_DENOMINATION_POPUP, which are registered\n        // unconditionally active — so the guard cost a full map scan and returned early never. Both\n        // branches below are already isActive-guarded, which is the real check.\n        if (\n            Core.flags.isActive(FeatureFlags.HIDE_JACKPOT) &&\n            Core.flags.get(FeatureFlags.HIDE_JACKPOT).affectedFeatures?.includes(feature)\n        ) {\n            // example help/bl-jackpot/noJackpot/en.html\n            restrictionFolderPath = `${RestrictionType.NO_JACKPOT}/`;\n        }\n        if (\n            Core.flags.isActive(FeatureFlags.USE_SA_FEATURE) &&\n            Core.flags.get(FeatureFlags.USE_SA_FEATURE).affectedFeatures?.includes(feature as Features)\n        ) {\n            // Trailing separator is required: the caller composes\n            // `../assets/help/<url>/${restrictionFolderPath}${lang}.html`.\n            restrictionFolderPath = `${RestrictionType.SA_FEATURE}/`;\n        }\n        return { restrictionFolderPath, lang };\n    }\n\n    /**\n     * Whether the DOUBLE_CHANCE help section applies.\n     *\n     * Gated on HIDE_DOUBLE_CHANCE alone, matching pre-release. HIDE_BUY_BONUS must NOT be part of\n     * this: in the DEFAULT and MULTIPLE_BUY_BONUS modes it suppresses only the buy-bonus part and\n     * the double-chance part keeps working, so including it would hide the double-chance help\n     * exactly when double chance is still offered. See\n     * docs/buy-bonus-restriction-coordination-pre-release.drawio (Tier 1, sibling-survives).\n     *\n     * Shared by both condition evaluators in this class so they cannot drift apart again.\n     */\n    private isDoubleChanceHelpVisible(): boolean {\n        return (\n            (this.hasFeatureOrComponent(SlotComponents.BUY_BONUS, BuyBonusModes.DEFAULT) ||\n                this.hasFeatureOrComponent(SlotComponents.BUY_BONUS, BuyBonusModes.MULTIPLE_BUY_BONUS)) &&\n            this.settings.haveGameMode('DOUBLE_CHANCE') &&\n            !Core.flags.isActive(FeatureFlags.HIDE_DOUBLE_CHANCE)\n        );\n    }\n\n    /**\n     * Whether the EXTENDED_MULTIPLE_BUY_BONUS help section applies.\n     *\n     * Gated on HIDE_BUY_BONUS alone, matching pre-release. HIDE_DOUBLE_CHANCE must NOT be part of\n     * this: in the EXTENDED mode the parts are fixed and a double-chance restriction switches the\n     * configuration and asset variant rather than removing the offering, so the section still\n     * applies. Shared by both condition evaluators in this class.\n     */\n    private isExtendedMultipleBuyBonusHelpVisible(): boolean {\n        return (\n            this.hasFeatureOrComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS) &&\n            !Core.flags.isActive(FeatureFlags.HIDE_BUY_BONUS)\n        );\n    }\n\n    /**\n     * Whether the bet is currently formed from a buy bonus factor instead of the base game one.\n     *\n     * Derived on read instead of tracked: FACTOR_CHANGED fires on every factor transition\n     * (buy bonus activation, deactivation, double chance, factor restore after a feature) and\n     * those emissions do not arrive in on/off pairs, so a flag flipped per emission drifts out\n     * of sync with the real factor and leaves the help bet titles swapped - ON-166322.\n     */\n    private get isFactorChanged(): boolean {\n        return (\n            this.hasFeatureOrComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS) &&\n            this.settings.factor !== this.settings.getFactorByUniqueGameMode('NORMAL_MODE')\n        );\n    }\n\n    private hasFeatureOrComponent(module: Features | SlotComponents, mode?: any): boolean {\n        return Core.hasFeature(module as Features) || Core.hasComponent(module as SlotComponents, mode);\n        // if (Object.values(Features).includes(module as Features)) {\n        //     return Core.hasFeature(module as Features);\n        // } else if (module is SlotComponents) {\n        //     return Core.hasComponent(module as SlotComponents);\n        // }\n    }\n\n    private checkConditions(conditions: string): boolean {\n        let conditionPassed = false;\n        const features: string[] = conditions.split('|');\n\n        const linesOptions = this.rootStore.settings.multipleLinesGameAvailableLines\n            ? this.rootStore.settings.multipleLinesGameAvailableLines.length\n            : this.rootStore.settings.linesOptions.length;\n        // if the condition is like \"GAMBLE,GIFT_SPINS\" - hide if not of both features is included\n        // condition can start with ! for \"does not have feature\"\n        // condition name can start with # for special hardcoded conditions as #MINIMUM_SPEEN_TIME\n        if (features.length > 1) {\n            features.forEach((feature) => {\n                const negative = feature.trim().startsWith('!');\n                if (negative) {\n                    feature = feature.substring(1).trim();\n                }\n                const special = conditions.trim().startsWith('#');\n                if (special) {\n                    // search for special conditions\n                    conditions = conditions.substring(1).trim();\n                    switch (conditions) {\n                        case 'MINIMUM_SPIN_TIME':\n                            if (negative) {\n                                conditionPassed =\n                                    conditionPassed || this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value === 0;\n                            } else {\n                                conditionPassed =\n                                    conditionPassed || this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value > 0;\n                            }\n                            break;\n                        case 'AUTOPLAY_SETTING':\n                            if (negative) {\n                                conditionPassed = conditionPassed || this.settings.autoplay === true;\n                            } else {\n                                conditionPassed = conditionPassed || this.settings.autoplay === false;\n                            }\n                            break;\n                        case 'HAVE_LINES_AND_TILES':\n                        case 'HAVE_LINES':\n                            if (negative) {\n                                conditionPassed =\n                                    conditionPassed ||\n                                    this.settings.lines === 0 ||\n                                    this.slotConfiguration.gameType === GameTypes.JUMBO_WAYS_SLOT ||\n                                    this.slotConfiguration.gameType === GameTypes.CASCADE_SLOT ||\n                                    this.slotConfiguration.gameType === GameTypes.WAYS_TO_PAY_SLOT;\n                            } else {\n                                conditionPassed =\n                                    conditionPassed ||\n                                    (this.settings.lines > 0 &&\n                                        this.slotConfiguration.gameType !== GameTypes.CASCADE_SLOT &&\n                                        this.slotConfiguration.gameType !== GameTypes.WAYS_TO_PAY_SLOT);\n                                this.slotConfiguration.gameType !== GameTypes.WAYS_TO_PAY_SLOT;\n                                if (conditions === 'HAVE_LINES_AND_TILES') {\n                                    conditionPassed =\n                                        conditionPassed && !this.slotConfiguration.gameHasLinesButNoLinesTile;\n                                }\n                                // settings for ways games now come from the server with a number of lines (no more 0 lines).\n                            }\n                            break;\n                        case 'HAVE_LINES_AND_NOT_HIGH_CASH':\n                            conditionPassed =\n                                conditionPassed ||\n                                (this.settings.lines > 0 &&\n                                    !this.slotConfiguration.cascadeGame &&\n                                    this.slotConfiguration.gameType !== GameTypes.WAYS_TO_PAY_SLOT &&\n                                    this.slotConfiguration.gameType !== GameTypes.JUMBO_WAYS_SLOT &&\n                                    !this.hasFeatureOrComponent('HIGH_CASH_COUNTERS' as Features));\n                            break;\n                        case 'HAVE_BACKGROUND_SOUND':\n                            conditionPassed = this.componentConfiguration.helpViewProps.hasBackgroundMusic;\n                            break;\n                        case 'HAS_LEFT_HAND_MODE_ENABLED':\n                            conditionPassed = this.componentConfiguration.generalSettingsProps.hasLeftHandModeContainer;\n                            break;\n                        case 'IS_WAYS_GAME':\n                            if (negative) {\n                                conditionPassed =\n                                    conditionPassed || this.slotConfiguration.gameType !== GameTypes.WAYS_TO_PAY_SLOT;\n                            } else {\n                                conditionPassed =\n                                    conditionPassed ||\n                                    this.slotConfiguration.gameType === GameTypes.WAYS_TO_PAY_SLOT ||\n                                    this.slotConfiguration.gameType === GameTypes.JUMBO_WAYS_SLOT;\n                            }\n                            break;\n                        case 'CLUSTER_GAME':\n                            if (negative) {\n                                conditionPassed =\n                                    conditionPassed || this.slotConfiguration.gameType !== GameTypes.CLUSTER_SLOT;\n                            } else {\n                                conditionPassed =\n                                    conditionPassed || this.slotConfiguration.gameType === GameTypes.CLUSTER_SLOT;\n                            }\n                            break;\n                        case 'JUMBO_WAYS_BUY_BONUS_GAME':\n                            conditionPassed =\n                                (conditionPassed || this.slotConfiguration.gameType === GameTypes.JUMBO_WAYS_SLOT) &&\n                                !Core.flags.isActive(FeatureFlags.HIDE_BUY_BONUS) &&\n                                !this.hasFeatureOrComponent(SlotComponents.BUY_BONUS, BuyBonusModes.DEFAULT) &&\n                                !this.hasFeatureOrComponent(\n                                    SlotComponents.BUY_BONUS,\n                                    BuyBonusModes.MULTIPLE_BUY_BONUS,\n                                ) &&\n                                !this.hasFeatureOrComponent(\n                                    SlotComponents.BUY_BONUS,\n                                    BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS,\n                                );\n                            break;\n                        case 'SHOW_GIFT_SPINS':\n                            conditionPassed = conditionPassed || !this.settings.gsHideInfo;\n                            break;\n                        case 'JUMBO_WAYS_COUNTER':\n                            conditionPassed =\n                                conditionPassed || this.slotConfiguration.gameType === GameTypes.JUMBO_WAYS_SLOT;\n                            break;\n                        case 'NO_JACKPOT':\n                            if (negative) {\n                                conditionPassed = conditionPassed || !Core.flags.isActive(FeatureFlags.HIDE_JACKPOT);\n                            } else {\n                                conditionPassed = conditionPassed || Core.flags.isActive(FeatureFlags.HIDE_JACKPOT);\n                            }\n                            break;\n                        case 'HAS_MULTIPLE_LINE_OPTIONS':\n                            conditionPassed = conditionPassed || linesOptions > 1;\n                            break;\n                        case 'HIDE_PLAYER_HISTORY':\n                            conditionPassed = !this.settings.settings.settings.jurisdiction.hidePlayerHistory;\n                            break;\n                        case 'GUARANTEED_WIN_TOGGLE':\n                            conditionPassed = this.componentConfiguration.haveGuaranteedWinToggleDescription;\n                            break;\n                        case 'DOUBLE_CHANCE':\n                            conditionPassed = this.isDoubleChanceHelpVisible();\n                            break;\n                        case 'BUY_BONUS':\n                            conditionPassed =\n                                this.hasFeatureOrComponent(SlotComponents.BUY_BONUS, BuyBonusModes.DEFAULT) &&\n                                !Core.flags.isActive(FeatureFlags.HIDE_BUY_BONUS);\n                            break;\n                        case 'MULTIPLE_BUY_BONUS':\n                            conditionPassed =\n                                this.hasFeatureOrComponent(\n                                    SlotComponents.BUY_BONUS,\n                                    BuyBonusModes.MULTIPLE_BUY_BONUS,\n                                ) && !Core.flags.isActive(FeatureFlags.HIDE_BUY_BONUS);\n                            break;\n                        case 'EXTENDED_MULTIPLE_BUY_BONUS':\n                            conditionPassed = this.isExtendedMultipleBuyBonusHelpVisible();\n                            break;\n                        case 'BL_EXTENDED_MULTIPLE_BUY_BONUS':\n                            conditionPassed =\n                                this.hasFeatureOrComponent(Features.BL_JACKPOT) &&\n                                this.hasFeatureOrComponent(\n                                    SlotComponents.BUY_BONUS,\n                                    BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS,\n                                ) &&\n                                !Core.flags.isActive(FeatureFlags.HIDE_BUY_BONUS);\n                            break;\n                        case 'ONLY_DOUBLE_CHANCE':\n                            conditionPassed =\n                                this.hasFeatureOrComponent(\n                                    SlotComponents.BUY_BONUS,\n                                    BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS,\n                                ) &&\n                                Core.flags.isActive(FeatureFlags.HIDE_BUY_BONUS) &&\n                                !Core.flags.isActive(FeatureFlags.HIDE_DOUBLE_CHANCE) &&\n                                this.settings.haveGameMode('DOUBLE_CHANCE');\n                            break;\n                        case 'HAVE_DOUBLE_CHANCE':\n                            conditionPassed =\n                                this.hasFeatureOrComponent(\n                                    SlotComponents.BUY_BONUS,\n                                    BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS,\n                                ) &&\n                                !Core.flags.isActive(FeatureFlags.HIDE_DOUBLE_CHANCE) &&\n                                this.settings.haveGameMode('DOUBLE_CHANCE');\n                            break;\n                        case 'NO_MAX_LOSE_LIMIT':\n                            conditionPassed =\n                                !this.settings.settings.settings.jurisdiction?.autoplayRestrictions?.maxLossAmount;\n                            break;\n                        case 'KIOSK':\n                            if (negative) {\n                                conditionPassed = Core.configuration.mode !== 'kiosk';\n                            } else {\n                                conditionPassed = Core.configuration.mode === 'kiosk';\n                            }\n                            break;\n                        case 'TURTLE_LAYOUT':\n                            if (negative) {\n                                conditionPassed = conditionPassed || Core.gameLayout !== SlotGameLayouts.TURTLE;\n                            } else {\n                                conditionPassed = conditionPassed || Core.gameLayout === SlotGameLayouts.TURTLE;\n                            }\n                            break;\n                    }\n                } else {\n                    // search for feature\n                    if (negative) {\n                        conditionPassed = conditionPassed || !this.hasFeatureOrComponent(feature as Features);\n                    } else {\n                        conditionPassed = conditionPassed || this.hasFeatureOrComponent(feature.trim() as Features);\n                    }\n                }\n            });\n        } else {\n            const negative = conditions.trim().startsWith('!');\n            if (negative) {\n                conditions = conditions.substring(1).trim();\n            }\n            const special = conditions.trim().startsWith('#');\n            if (special) {\n                // search for special conditions\n                conditions = conditions.substring(1).trim();\n                switch (conditions) {\n                    case 'MINIMUM_SPIN_TIME':\n                        if (negative) {\n                            conditionPassed = this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value === 0;\n                        } else {\n                            conditionPassed = this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value > 0;\n                        }\n                        break;\n                    case 'AUTOPLAY_SETTING':\n                        if (negative) {\n                            conditionPassed = conditionPassed || this.settings.autoplay === true;\n                        } else {\n                            conditionPassed = conditionPassed || this.settings.autoplay === false;\n                        }\n                        break;\n                    case 'CLUSTER_GAME':\n                        if (negative) {\n                            conditionPassed =\n                                conditionPassed || this.slotConfiguration.gameType !== GameTypes.CLUSTER_SLOT;\n                        } else {\n                            conditionPassed =\n                                conditionPassed || this.slotConfiguration.gameType === GameTypes.CLUSTER_SLOT;\n                        }\n                        break;\n                    case 'HAVE_LINES_AND_TILES':\n                    case 'HAVE_LINES':\n                        if (negative) {\n                            conditionPassed =\n                                conditionPassed ||\n                                (this.settings.lines === 0 &&\n                                    this.slotConfiguration.gameType !== GameTypes.JUMBO_WAYS_SLOT) ||\n                                this.slotConfiguration.gameType === GameTypes.CASCADE_SLOT ||\n                                this.slotConfiguration.gameType === GameTypes.WAYS_TO_PAY_SLOT;\n                        } else {\n                            conditionPassed =\n                                conditionPassed ||\n                                (this.settings.lines > 0 &&\n                                    this.slotConfiguration.gameType !== GameTypes.CASCADE_SLOT &&\n                                    this.slotConfiguration.gameType !== GameTypes.WAYS_TO_PAY_SLOT);\n                            this.slotConfiguration.gameType !== GameTypes.WAYS_TO_PAY_SLOT;\n                            if (conditions === 'HAVE_LINES_AND_TILES') {\n                                conditionPassed = conditionPassed && !this.slotConfiguration.gameHasLinesButNoLinesTile;\n                            }\n                            // settings for ways games now come from the server with a number of lines (no more 0 lines).\n                        }\n                        break;\n                    case 'HAVE_LINES_AND_NOT_HIGH_CASH':\n                        conditionPassed =\n                            conditionPassed ||\n                            (this.settings.lines > 0 &&\n                                !this.slotConfiguration.cascadeGame &&\n                                this.slotConfiguration.gameType !== GameTypes.WAYS_TO_PAY_SLOT &&\n                                this.slotConfiguration.gameType !== GameTypes.JUMBO_WAYS_SLOT &&\n                                !this.hasFeatureOrComponent('HIGH_CASH_COUNTERS' as Features));\n                        break;\n                    case 'HAVE_BACKGROUND_SOUND':\n                        conditionPassed = this.componentConfiguration.helpViewProps.hasBackgroundMusic;\n                        break;\n                    case 'HAS_LEFT_HAND_MODE_ENABLED':\n                        conditionPassed = this.componentConfiguration.generalSettingsProps.hasLeftHandModeContainer;\n                        break;\n                    case 'IS_WAYS_GAME':\n                        if (negative) {\n                            conditionPassed =\n                                conditionPassed || this.slotConfiguration.gameType !== GameTypes.WAYS_TO_PAY_SLOT;\n                        } else {\n                            conditionPassed =\n                                conditionPassed ||\n                                this.slotConfiguration.gameType === GameTypes.WAYS_TO_PAY_SLOT ||\n                                this.slotConfiguration.gameType === GameTypes.JUMBO_WAYS_SLOT;\n                        }\n                        break;\n\n                    case 'JUMBO_WAYS_BUY_BONUS_GAME':\n                        conditionPassed =\n                            (conditionPassed || this.slotConfiguration.gameType === GameTypes.JUMBO_WAYS_SLOT) &&\n                            !Core.flags.isActive(FeatureFlags.HIDE_BUY_BONUS) &&\n                            !this.hasFeatureOrComponent(SlotComponents.BUY_BONUS, BuyBonusModes.DEFAULT) &&\n                            !this.hasFeatureOrComponent(SlotComponents.BUY_BONUS, BuyBonusModes.MULTIPLE_BUY_BONUS) &&\n                            !this.hasFeatureOrComponent(\n                                SlotComponents.BUY_BONUS,\n                                BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS,\n                            );\n                        break;\n                    case 'SHOW_GIFT_SPINS':\n                        conditionPassed = conditionPassed || !this.settings.gsHideInfo;\n                        break;\n                    case 'JUMBO_WAYS_COUNTER':\n                        conditionPassed =\n                            conditionPassed || this.slotConfiguration.gameType === GameTypes.JUMBO_WAYS_SLOT;\n                        break;\n                    case 'NO_JACKPOT':\n                        if (negative) {\n                            conditionPassed = conditionPassed || !Core.flags.isActive(FeatureFlags.HIDE_JACKPOT);\n                        } else {\n                            conditionPassed = conditionPassed || Core.flags.isActive(FeatureFlags.HIDE_JACKPOT);\n                        }\n                        break;\n                    case 'SA_FEATURE':\n                        conditionPassed = negative\n                            ? conditionPassed || !Core.flags.isActive(FeatureFlags.USE_SA_FEATURE)\n                            : conditionPassed || Core.flags.isActive(FeatureFlags.USE_SA_FEATURE);\n                        break;\n                    case 'HAS_MULTIPLE_LINE_OPTIONS':\n                        conditionPassed = conditionPassed || linesOptions > 1;\n                        break;\n                    case 'HIDE_PLAYER_HISTORY':\n                        conditionPassed = !this.settings.settings.settings.jurisdiction.hidePlayerHistory;\n                        break;\n                    case 'GUARANTEED_WIN_TOGGLE':\n                        conditionPassed = this.componentConfiguration.haveGuaranteedWinToggleDescription;\n                        break;\n                    case 'DOUBLE_CHANCE':\n                        conditionPassed = this.isDoubleChanceHelpVisible();\n                        break;\n                    case 'BUY_BONUS':\n                        conditionPassed =\n                            this.hasFeatureOrComponent(SlotComponents.BUY_BONUS, BuyBonusModes.DEFAULT) &&\n                            !Core.flags.isActive(FeatureFlags.HIDE_BUY_BONUS);\n                        break;\n                    case 'MULTIPLE_BUY_BONUS':\n                        conditionPassed =\n                            this.hasFeatureOrComponent(SlotComponents.BUY_BONUS, BuyBonusModes.MULTIPLE_BUY_BONUS) &&\n                            !Core.flags.isActive(FeatureFlags.HIDE_BUY_BONUS);\n                        break;\n                    case 'EXTENDED_MULTIPLE_BUY_BONUS':\n                        conditionPassed = this.isExtendedMultipleBuyBonusHelpVisible();\n                        break;\n                    case 'BL_EXTENDED_MULTIPLE_BUY_BONUS':\n                        conditionPassed =\n                            this.hasFeatureOrComponent(Features.BL_JACKPOT) &&\n                            this.hasFeatureOrComponent(\n                                SlotComponents.BUY_BONUS,\n                                BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS,\n                            ) &&\n                            !Core.flags.isActive(FeatureFlags.HIDE_BUY_BONUS);\n                        break;\n                    case 'ONLY_DOUBLE_CHANCE':\n                        conditionPassed =\n                            this.hasFeatureOrComponent(\n                                SlotComponents.BUY_BONUS,\n                                BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS,\n                            ) &&\n                            Core.flags.isActive(FeatureFlags.HIDE_BUY_BONUS) &&\n                            !Core.flags.isActive(FeatureFlags.HIDE_DOUBLE_CHANCE) &&\n                            this.settings.haveGameMode('DOUBLE_CHANCE');\n                        break;\n                    case 'HAVE_DOUBLE_CHANCE':\n                        conditionPassed =\n                            this.hasFeatureOrComponent(\n                                SlotComponents.BUY_BONUS,\n                                BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS,\n                            ) &&\n                            !Core.flags.isActive(FeatureFlags.HIDE_DOUBLE_CHANCE) &&\n                            this.settings.haveGameMode('DOUBLE_CHANCE');\n                        break;\n                    case 'NO_MAX_LOSE_LIMIT':\n                        conditionPassed =\n                            !this.settings.settings.settings.jurisdiction?.autoplayRestrictions?.maxLossAmount;\n                        break;\n                    case 'KIOSK':\n                        if (negative) {\n                            conditionPassed = Core.configuration.mode !== 'kiosk';\n                        } else {\n                            conditionPassed = Core.configuration.mode === 'kiosk';\n                        }\n                        break;\n                    case 'DISABLE_HOLD_AND_PLAY':\n                        if (negative) {\n                            conditionPassed = !Core.flags.isActive(FeatureFlags.HIDE_HOLD_AND_PLAY);\n                        } else {\n                            conditionPassed = Core.flags.isActive(FeatureFlags.HIDE_HOLD_AND_PLAY);\n                        }\n                        break;\n                    case 'TURTLE_LAYOUT':\n                        if (negative) {\n                            conditionPassed = conditionPassed || Core.gameLayout !== SlotGameLayouts.TURTLE;\n                        } else {\n                            conditionPassed = conditionPassed || Core.gameLayout === SlotGameLayouts.TURTLE;\n                        }\n                        break;\n                    case 'USE_NON_LINEAR_BET_TITLES':\n                        if (negative) {\n                            conditionPassed =\n                                !this.isFactorChanged &&\n                                !this.componentConfiguration.helpViewProps.useNonLinearBetTitles;\n                        } else {\n                            conditionPassed =\n                                this.isFactorChanged || this.componentConfiguration.helpViewProps.useNonLinearBetTitles;\n                        }\n                        break;\n                }\n            } else {\n                // search for feature\n                if (negative) {\n                    conditionPassed = !this.hasFeatureOrComponent(conditions as Features);\n                } else {\n                    conditionPassed = this.hasFeatureOrComponent(conditions as Features);\n                }\n            }\n        }\n        return conditionPassed;\n    }\n\n    private onFactorChanged(): void {\n        this.reloadHTML();\n    }\n\n    private reloadHTML(): void {\n        const isHelpSelected = this.rootStore.uiStore.SELECTED_SETTINGS_TAB.value === SettingsTab.HELP;\n\n        this.hideHTML();\n        this.externalHelps.clear();\n        this.helpHTMLDiv = undefined;\n\n        if (isHelpSelected && this.panelIsOpen) {\n            this.loadHTML();\n        }\n    }\n\n    private addHashStringToAllImages(html: string): string {\n        // const arrayWithMatches = html.match(/<img[^>]+src=\"([^\">]+)/g);\n        const arrayWithMatches = html.match(/<img.*?src=[\"|'](.*?)[\"|']/gs);\n        // filter only unique correct\n        // @ts-ignore\n        const uniqueArray = arrayWithMatches.filter((v, i, a) => a.indexOf(v) === i);\n\n        if (uniqueArray?.length) {\n            uniqueArray.forEach((match) => {\n                match = match.substring(0, match.length - 1);\n                if (match.indexOf('?' + Core.hash) === -1) {\n                    html = html.replace(new RegExp(match, 'g'), match + '?' + Core.hash);\n                }\n            });\n        }\n\n        return html;\n    }\n\n    private addVipJackpotPrefixIfNeeded(response: any): string {\n        const bellLinkLinkedJPs = ['BL_JACKPOT'];\n        // const bellLinkLinkedJPs = ['BL_JACKPOT', 'GAKL_JACKPOT_V1', 'GAKL_JACKPOT_BASE', 'BL_BOOST_JACKPOT'];\n        if (\n            bellLinkLinkedJPs.includes(response.param) &&\n            this.settings?.jackpotStats[0]?.jackpotName === 'VIP Bell Link' &&\n            this.settings?.clientSettings?.enableVipUi\n        ) {\n            return response.data.replace(/(\\/help\\/)([^/]+)/g, (_, helpPath, folder) => '/vip' + helpPath + folder);\n        }\n        return response.data;\n    }\n\n    private getAssetUrl(id: string): string {\n        return Core.assets.getAsset(id)?.url;\n    }\n\n    private reformatHTML(html: string): HTMLElement {\n        // get only body of the HTML\n        const temp: any = document.createElement('div');\n        // local resources per game\n        html = html.replace(/##GAME_KEY##/g, this.gameKey);\n        // local resources per game type where games have own UI skin\n\n        html = html.replace(/assetId:blitzSpinButton/g, this.getAssetUrl('blitzSpinButton'));\n\n        const helpImageFolder = this.slotConfiguration.helpAssetsFolder;\n        if (helpImageFolder !== '') {\n            html = html.replace(/\\/help\\/images\\//g, helpImageFolder);\n        }\n\n        html = this.setLanguageInAssetPaths(html);\n        html = this.addHashStringToAllImages(html);\n\n        temp.innerHTML = html;\n        const body = temp.getElementsByClassName('container');\n        if (body.length > 0) {\n            html = body[0].outerHTML;\n            temp.innerHTML = html;\n        }\n\n        // change relative paths to the images\n        // const images = temp.getElementsByTagName('img');\n        // Array.from(images).forEach((img: HTMLImageElement) => {\n        //     if (img.src.indexOf(this.appLocation) > -1) {\n        //         if (img.src.indexOf(this.appLocation + '/assets') === -1) {\n        //             img.src = img.src.replace(\n        //                 this.appLocation,\n        //                 this.appLocation + '/assets/help/' + Core.configuration.gameKey,\n        //             );\n        //         }\n        //     }\n        //     // console.log(this.appLocation, img.src);\n        // });\n\n        // remove .desktop-only if is mobile and .mobile-only if is desktop\n        const platformRemoveElements = temp.getElementsByClassName(Core.isDesktopMode ? 'mobile-only' : 'desktop-only');\n        Array.from(platformRemoveElements).forEach((element: HTMLElement) => {\n            element.parentElement?.removeChild(element);\n        });\n\n        // set number of lines\n        const linesTexts = temp.getElementsByClassName('lines-text');\n        Array.from(linesTexts).forEach((linesText: HTMLImageElement) => {\n            let lines: string = '';\n\n            if (this.settings.linesOptions.length > 1) {\n                const availableLinesOptions = this.rootStore.settings.multipleLinesGameAvailableLines\n                    ? this.rootStore.settings.multipleLinesGameAvailableLines\n                    : this.rootStore.settings.linesOptions;\n                lines =\n                    availableLinesOptions.length > 1\n                        ? Core.translator.translate('GAME_LINES')\n                        : Core.translator.translate('GAME_FIXED_LINES');\n\n                let resultString = '';\n                if (availableLinesOptions.length > 1) {\n                    availableLinesOptions.forEach((el) => {\n                        if (availableLinesOptions.indexOf(el) === availableLinesOptions.length - 1) {\n                            resultString += ` ${Core.translator.translate('PAYTABLE.OR')} ${el}`;\n                        } else {\n                            resultString += `${el}`;\n                            if (availableLinesOptions.indexOf(el) !== availableLinesOptions.length - 2) {\n                                resultString += ', ';\n                            }\n                        }\n                    });\n                } else {\n                    resultString = availableLinesOptions[0].toString();\n                }\n                lines = lines.replace(/##LINES##/g, resultString);\n            } else {\n                lines = Core.translator.translate('GAME_FIXED_LINES');\n                lines = lines.replace(/##LINES##/g, this.settings.lines.toString());\n            }\n            linesText.innerHTML = lines;\n        });\n\n        // set game name\n\n        // general games\n        const gameName = temp.getElementsByClassName('game-name');\n        Array.from(gameName).forEach((span: HTMLImageElement) => {\n            span.innerHTML = this.slotConfiguration.gameTitle\n                .replace(' BL', ' Bell Link')\n                .replace(' G&K', ' Gods & Kings')\n                .replace(' JW', ' Jumboways')\n                .replace(' CH', ' Cash Heat');\n        });\n\n        // high cash games\n        const highCashGameName = temp.getElementsByClassName('highCash-game-name');\n        Array.from(highCashGameName).forEach((span: HTMLImageElement) => {\n            span.innerHTML = this.slotConfiguration.gameTitle.replace(' HC', ' High Cash');\n        });\n\n        // set version\n        const version = temp.getElementsByClassName('version');\n        Array.from(version).forEach((span: HTMLImageElement) => {\n            span.innerHTML = Core.configuration.version;\n        });\n\n        // upper cased specific\n        // https://jira.egt-digital.com/browse/ON-22355\n        const upperCased = temp.getElementsByClassName('upper-cased');\n        Array.from(upperCased).forEach((span: HTMLElement) => {\n            let transformed = span.innerText.toUpperCase();\n            switch (Core.configuration.language) {\n                case Language.EL:\n                    transformed = transformed.normalize('NFD').replace(/\\p{Diacritic}/gu, '');\n                    break;\n            }\n            span.innerText = transformed;\n        });\n        // html = temp.innerHTML;\n        // this.helpHTMLDiv = temp;\n        // temp = null;\n        return temp;\n    }\n\n    private setLanguageInAssetPaths(html: string): string {\n        const currentLanguage = Core.configuration.language;\n        const defaultLanguage = Core.translator.defaultLanguage;\n\n        const localizedImagePattern =\n            /<img\\b([^>]*\\bsrc=[\"'])([^\"']*\\/translations\\/)##LANGUAGE##(\\/[^\"']+)([\"'][^>]*)>/i;\n        if (localizedImagePattern.test(html)) {\n            html = html.replace(\n                /<img\\b([^>]*\\bsrc=[\"'])([^\"']*\\/translations\\/)##LANGUAGE##(\\/[^\"']+)([\"'][^>]*)>/gi,\n                (_match, attributes, path, imagePath, quoteAndAttributes) => {\n                    const currentPath = `${path}${currentLanguage}${imagePath}`;\n                    const defaultPath = `${path}${defaultLanguage}${imagePath}`;\n                    const fallbackHandler = `this.onerror=null;var currentSrc=this.getAttribute('src')||'';var suffix=currentSrc.includes('?')?currentSrc.slice(currentSrc.indexOf('?')):'';this.src='${defaultPath}' + suffix;`;\n                    return `<img${attributes}${currentPath}${quoteAndAttributes} onerror=\"${fallbackHandler}\">`;\n                },\n            );\n        }\n\n        return html.replace(/##LANGUAGE##/g, currentLanguage);\n    }\n\n    /* private showError(response: string): void {\n        Log.error(response);\n        const errorData = {} as IErrorData;\n        errorData.code = response;\n        errorData.modal = true;\n        errorData.type = ErrorTypes.GAME_ERROR;\n        Core.SHOW_ERROR.next(errorData);\n    } */\n\n    private onErrorShown(): void {\n        if (this.helpHTMLDiv) {\n            this.helpHTMLDiv.style.display = 'none';\n        }\n    }\n\n    private onErrorClosed(): void {\n        if (this.helpHTMLDiv) {\n            this.helpHTMLDiv.style.display = 'block';\n        }\n        this.resizeDiv();\n    }\n\n    private generateHelpContainer(): void {\n        this.config = {} as ITitledWindowConfig;\n        this.config.width = this.componentConfiguration.helpViewProps.widthBounds;\n        this.config.height = this.componentConfiguration.helpViewProps.heightBounds;\n\n        this.config.borderLeftUpTexture = Core.assets.getTextureFromSpriteSheet('miscellaneous', 'windowCornerLu.png');\n        this.config.title = Core.translator.translate('HELP');\n        this.config.titleStyle = this.componentConfiguration.tabNameProps.textStyle;\n        this.menuBody = new TitledWindow(this.config);\n        this.menuBody.x = 0;\n        this.menuBody.y = 0;\n        this.menuBody.interactive = true;\n        this.addChild(this.menuBody);\n    }\n\n    // // create div with id and add it after boddy. used for debug of mobiles\n    // private addElementFromHTML(id: string, html: string): HTMLElement {\n    //     const div = document.createElement('div');\n    //     div.id = id;\n    //     div.innerHTML = html.trim();\n    //     document.body.insertAdjacentElement('afterbegin', div);\n    //     return div;\n    // }\n\n    // private log(s: any): void {\n    //     let debugEl = document.getElementById('debug') as HTMLTextAreaElement;\n    //     if (!debugEl) {\n    //         this.addElementFromHTML(\n    //             'debugContainer',\n    //             `<textarea id='debug' style='position:fixed; z-index: 99999; font-size: 20px; top:0; right:0; width: 50%; height: 200px'></textarea>`,\n    //         );\n    //         debugEl = document.getElementById('debug') as HTMLTextAreaElement;\n    //     }\n    //     if (debugEl) {\n    //         debugEl.value = JSON.stringify(s) + '\\n' + debugEl.value;\n    //     }\n    // }\n}\n","import { BuyBonusModes } from '@egt/buy-bonus';\nimport { ICascadeSlotConfiguration } from '@egt/cascade-slot';\nimport Core, {\n    FeatureFlags,\n    GameTypes,\n    Money,\n    PostMessageDispatcher,\n    RESTRICTION_TYPE_BY_FEATURE_FLAG,\n} from '@egt/core';\nimport { Features, InitialSettings, RootStore, SlotComponents } from '@egt/slot';\nimport {\n    ITitledWindowConfig,\n    IViewVisibilityContainer,\n    MoneyTextConfig,\n    TitledWindow,\n    ViewVisibilityContainer,\n} from '@egt/ui-lib';\nimport { Rectangle } from 'pixi.js';\nimport { Subject, merge, zip } from 'rxjs';\nimport { filter, takeUntil } from 'rxjs/operators';\nimport { IRTPDetails } from 'slot/src/egt/slots/components/interfaces/IRTPDetails';\nimport { ISlotConfiguration } from 'slot/src/egt/slots/slot-configuration/ISlotConfiguration';\nimport { inject, injectable } from 'tsyringe';\nimport SettingsTab from '../../enums/SettingsTab';\nimport { ISettingsPopupComponentConfiguration } from '../../interfaces/SettingsInterfaces';\nimport PaytableScript from './PaytableScript';\n\n@injectable()\nexport default class PaytableHTMLView extends ViewVisibilityContainer implements IViewVisibilityContainer {\n    protected paytableHTMLDiv: any;\n    protected closeInfo = new Subject();\n    protected alreadyOpen: boolean = false;\n    private closeEvent: any;\n    private hideEvent: any;\n    protected html: string;\n    protected availableSection: string[];\n    private panelIsOpen: boolean = false;\n    private inClossing: boolean = false;\n    private gameKey: string;\n    private menuBody: TitledWindow;\n    private config: any;\n    private multipleRTPDetails: IRTPDetails;\n    private hasMultipleRTP: boolean;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('InitialSettings') protected gameInitSettings: InitialSettings,\n        @inject('PaytableSpecificScript') protected paytableScript: PaytableScript,\n        @inject('SettingsPopupComponentConfiguration')\n        protected componentConfiguration: ISettingsPopupComponentConfiguration,\n    ) {\n        super();\n        this.init();\n        this.multipleRTPDetails = this.gameInitSettings.settings.settings.clientSettings.rtp;\n        this.hasMultipleRTP =\n            this.multipleRTPDetails?.hasOwnProperty('doubleChance') ||\n            this.multipleRTPDetails?.hasOwnProperty('buyBonus') ||\n            this.multipleRTPDetails?.hasOwnProperty('modes');\n    }\n\n    public init(): void {\n        if (this.componentConfiguration.paytableViewProps.showDesktopVersion) {\n            this.interactive = true;\n            this.generatePaytableContainer();\n        }\n\n        this.gameKey = this.slotConfiguration.cloneGameKey\n            ? this.slotConfiguration.cloneGameKey\n            : Core.configuration.gameKey;\n        this.rootStore.subjects.OPEN_INFO_POPUP.pipe(takeUntil(this.DESTROY)).subscribe(this.showHideInfo.bind(this));\n\n        this.rootStore.subjects.SETTINGS_POPUP_OPENED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.popupOpened.bind(this),\n        );\n\n        this.hideEvent = merge(this.DESTROY, this.rootStore.subjects.CLOSE_ALL_POPUPS);\n        this.hideEvent.pipe(takeUntil(this.DESTROY)).subscribe(this.hidePaytable.bind(this, false));\n        this.rootStore.subjects.CLOSE_SETTINGS_POPUP.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.inClossing = this.panelIsOpen; // set to true if opened\n            this.panelIsOpen = false;\n            this.hidePaytable();\n        });\n        this.rootStore.subjects.SETTINGS_POPUP_CLOSED.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.inClossing = false;\n            this.panelIsOpen = false;\n        });\n        this.closeEvent = merge(this.rootStore.subjects.CLOSE_SETTINGS_POPUP, this.hideEvent);\n        this.show = false;\n    }\n\n    public destroy(_options?: { children?: boolean; texture?: boolean; baseTexture?: boolean }): void {\n        this.hidePaytable();\n        this.closeEvent = null;\n        this.panelIsOpen = false;\n        this.paytableHTMLDiv = null;\n        super.destroy({ children: true, texture: true, baseTexture: true });\n    }\n\n    public redrawView(): void {\n        this.resizeDiv();\n    }\n\n    protected resizeDiv(): void {\n        if (!this.paytableHTMLDiv) {\n            return;\n        }\n        const stage = Core.stage.getMediaInfo().display.stage;\n        const scale = stage.currentWidth / stage.initialWidth;\n        this.paytableHTMLDiv.style.fontSize = this.componentConfiguration.paytableViewProps.fontSize * scale + 'px';\n\n        const headerHeight: number = this.componentConfiguration.paytableViewProps.headerHeight * Number(stage.scaleY);\n        const buttonsHeight: number =\n            this.componentConfiguration.paytableViewProps.buttonsHeight * Number(stage.scaleY);\n        const bottomHeight: number = this.componentConfiguration.paytableViewProps.bottomHeight * Number(stage.scaleY);\n        const offsetX: number = document?.getElementById('app-canvas')?.offsetLeft || 0;\n\n        const area = new Rectangle();\n\n        if (this.componentConfiguration.paytableViewProps.showDesktopVersion) {\n            area.x =\n                (Core.display.stage.width * Number(stage.scaleX) -\n                    this.componentConfiguration.paytableViewProps.widthBounds * Number(stage.scaleX)) /\n                    2 +\n                stage.x +\n                offsetX;\n            area.y =\n                this.componentConfiguration.paytableViewProps.viewTopOffset * Number(stage.scaleY) +\n                headerHeight +\n                this.componentConfiguration.paytableViewProps.additionalHeaderHeightOffsetY +\n                stage.y;\n            area.width =\n                this.componentConfiguration.paytableViewProps.widthBounds * scale -\n                this.componentConfiguration.paytableViewProps.widthReduce;\n            area.height =\n                this.componentConfiguration.paytableViewProps.heightBounds * Number(stage.scaleY) -\n                headerHeight -\n                this.componentConfiguration.paytableViewProps.heightReduce;\n        } else {\n            area.x = stage.x + offsetX;\n            area.y = stage.y + headerHeight;\n            area.width = stage.currentWidth;\n            area.height = stage.currentHeight - (headerHeight + buttonsHeight + bottomHeight);\n        }\n\n        this.paytableHTMLDiv.style.top = area.y + 'px';\n\n        this.paytableHTMLDiv.style.left = area.x + 'px';\n        this.paytableHTMLDiv.style.width = area.width + 'px';\n        this.paytableHTMLDiv.style.height = area.height + 'px';\n    }\n\n    protected reformatHTML(html: string): string {\n        const re = /\\##PAYOUTITEM.*?\\##/gi;\n        // Replace PayoutItems\n        /* tslint:disable:no-conditional-assignment */\n        html = html.replace(/(\\r\\n|\\n|\\r)/gm, '');\n        const match = html.match(re);\n        match?.forEach((element) => {\n            const payOutObject: any = JSON.parse(element.split('##PAYOUTITEM').join('').split('##').join(''));\n\n            html = html.replace(element, this.setPayoutItem(payOutObject));\n        });\n\n        const cascadeRe = /\\##CASCADEPAYITEM.*?\\##/gi;\n        let cascadeMatch;\n        // biome-ignore lint/suspicious/noAssignInExpressions: <explanation>\n        while ((cascadeMatch = cascadeRe.exec(html)) != null) {\n            const payOutObject: any = JSON.parse(\n                cascadeMatch[0].split('##CASCADEPAYITEM').join('').split('##').join(''),\n            );\n            const config = (this.slotConfiguration as ICascadeSlotConfiguration).paytablePayItemsConfiguration;\n            html = html.replace(\n                cascadeMatch[0],\n                this.setCascadePayoutItem(payOutObject, config.step, config.minSymbols, config.moreThanSymbols),\n            );\n        }\n\n        // const cascade7x7Re = /\\##CASCADE7X7PAYITEM.*?\\##/gi;\n        // let cascade7x7Match;\n        // // biome-ignore lint/suspicious/noAssignInExpressions: <explanation>\n        // while ((cascade7x7Match = cascade7x7Re.exec(html)) != null) {\n        //     const payOutObject: any = JSON.parse(\n        //         cascade7x7Match[0].split('##CASCADE7X7PAYITEM').join('').split('##').join(''),\n        //     );\n\n        //     html = html.replace(cascade7x7Match[0], this.setCascadePayoutItem(payOutObject, 2, 13, 19));\n        // }\n\n        const clusterRe = /\\##CLUSTERPAYITEM.*?\\##/gi;\n        let clusterMatch;\n        // biome-ignore lint/suspicious/noAssignInExpressions: <explanation>\n        while ((clusterMatch = clusterRe.exec(html)) != null) {\n            const payOutObject: any = JSON.parse(\n                clusterMatch[0].split('##CLUSTERPAYITEM').join('').split('##').join(''),\n            );\n\n            html = html.replace(clusterMatch[0], this.setClusterPayoutItem(payOutObject));\n        }\n\n        const pickMeRe = /\\##PICKMEPAYOUT.*?\\##/gi;\n        const pickMeArray = html.match(pickMeRe);\n        if (pickMeArray) {\n            html = this.setPickMeValues(html, pickMeArray);\n        }\n\n        const scriptRe = /\\##SCRIPT.*?\\##/gi;\n        const scriptsArray = html.match(scriptRe);\n        if (scriptsArray) {\n            html = this.setScriptResult(html, scriptsArray);\n        }\n\n        html = this.translatePaytable(html);\n        html = this.replaceImagePlaceholders(html);\n        html = this.replaceGambleXTwoImage(html);\n        html = this.setGambleAmounts(html);\n        html = this.setAccumulatedJackpot(html);\n        html = this.setRangeTexts(html);\n        html = this.setMinMaxBet(html);\n        html = this.setMaxWinFactor(html);\n\n        html = this.setGameKeysInAssetPaths(html);\n\n        if (\n            html.search('##BET_VALUE_MULTIPLIER_10##') !== -1 ||\n            html.search('##BET_VALUE_MULTIPLIER_5##') !== -1 ||\n            html.search('##BET_VALUE_RANDOM_MULTIPLIER##') !== -1\n        ) {\n            html = this.setMultiplierBetValues(html);\n        }\n        html = this.setLanguageInAssetPaths(html);\n        html = this.addHashStringToAllImages(html);\n        if (html.search('##BUY_BONUS##') !== -1) {\n            html = this.setBuyBonusText(html);\n        }\n        if (html.search('##SUPER_BUY_BONUS##') !== -1) {\n            html = this.setSuperBuyBonusText(html);\n        }\n\n        if (html.search('##MAX_BET_BUY_BONUS##') !== -1) {\n            html = this.setMaxBetBuyBonusText(html);\n        }\n\n        if (html.search('##MAX_BET_BELL_LINK_BUY_BONUS##') !== -1) {\n            html = this.setMaxBetBellLinkBuyBonusText(html);\n        }\n\n        html = this.setJackpotLimits(html);\n        html = this.applyRestrictions(html);\n        html = this.setGameName(html);\n        if (html.search('##BUY_WILDS_VALUE_') !== -1) {\n            html = this.setWildHuntBets(html);\n        }\n        if (html.search('##BUY_BONUS_BET_VALUE##') !== -1) {\n            html = this.setBuyBonusBetValues(html);\n        }\n        if (html.search('##SUPER_BUY_BONUS_BET_VALUE##') !== -1) {\n            html = this.setSuperBuyBonusBetValues(html);\n        }\n        if (html.search('##MEGA_BUY_BONUS_BET_VALUE##') !== -1) {\n            html = this.setMegaBuyBonusBetValues(html);\n        }\n        if (html.search('##DOUBLE_CHANCE_BET_VALUE##') !== -1) {\n            html = this.setDoubleChanceBetValues(html);\n        }\n        if (html.search('##BUY_BONUS_BET_') !== -1 || html.search('##SUPER_BUY_BONUS_BET_') !== -1) {\n            html = this.setBuyBonusBets(html);\n        }\n        this.rootStore.subjects.FEATURE_MODIFY_PAYTABLE.next(html);\n\n        return html;\n    }\n\n    protected formatMinMax(credits: number): string {\n        const moneyValues = new Money(credits);\n\n        return moneyValues.htmlMoneyWithCurrency;\n    }\n\n    protected hidePaytable(): void {\n        const paytableHTMLDiv = document.getElementById('paytableHTMLDiv') as HTMLDivElement;\n        Core.environment.showHelperWhenAsked = true;\n        this.closeInfo.next();\n        if (this.alreadyOpen) {\n            Core.LOADING_ASSETS.next(false);\n        }\n\n        this.alreadyOpen = false;\n        if (paytableHTMLDiv && paytableHTMLDiv.parentElement) {\n            PostMessageDispatcher.htmlClosed('paytable');\n            paytableHTMLDiv.parentElement.removeChild(paytableHTMLDiv);\n        }\n    }\n    protected showHideInfo(show: boolean | undefined): void {\n        show =\n            (show === undefined ? this.rootStore.uiStore.SELECTED_SETTINGS_TAB.value === SettingsTab.INFO : show) &&\n            !this.inClossing;\n        if (!show) {\n            this.hidePaytable();\n            this.alreadyOpen = false;\n        } else if (!this.alreadyOpen && !this.panelIsOpen) {\n            Core.LOADING_ASSETS.next(true);\n            this.alreadyOpen = true;\n            const openEvent = zip(\n                this.rootStore.subjects.SETTINGS_POPUP_OPENED,\n                Core.CONTENT_LOADED.pipe(filter((res) => res.param === 'mainHTML')),\n            );\n            openEvent.pipe(takeUntil(this.closeInfo)).subscribe(this.onHTMLLoaded.bind(this));\n\n            Core.requestManager.get('assets/' + this.gameKey + '/paytable/paytable.html?' + Core.hash, 'mainHTML');\n        } else if (!this.alreadyOpen) {\n            this.alreadyOpen = true;\n            Core.LOADING_ASSETS.next(true);\n            Core.CONTENT_LOADED.pipe(\n                filter((res) => res.param === 'mainHTML'),\n                takeUntil(this.closeInfo),\n            ).subscribe(this.onHTMLLoaded.bind(this));\n\n            Core.requestManager.get('assets/' + this.gameKey + '/paytable/paytable.html?' + Core.hash, 'mainHTML');\n        }\n    }\n\n    private popupOpened(): void {\n        this.panelIsOpen = true;\n        if (this.rootStore.uiStore.SELECTED_SETTINGS_TAB.value === SettingsTab.INFO) {\n            this.showHideInfo(true);\n            // not gated on isMobileIos(): the fullscreen hand also runs on iPads, the flag is a no-op elsewhere\n            Core.environment.showHelperWhenAsked = false;\n        }\n    }\n\n    protected async onHTMLLoaded(res: any): Promise<void> {\n        if (Array.isArray(res)) {\n            res = res[1];\n        }\n\n        if (res.param === 'mainHTML') {\n            this.html = res.data;\n            Core.CONTENT_LOADED.pipe(takeUntil(this.closeInfo)).subscribe(this.onHTMLLoaded.bind(this));\n            this.checkForAddingSection();\n        } else if (!this.html) {\n            return;\n        } else {\n            const sectionKey = '@SECTION_' + res.param;\n            this.html = this.html.replace(sectionKey, res.data);\n            this.availableSection = this.availableSection.filter((word) => word !== res.param);\n        }\n\n        if (this.availableSection.length === 0) {\n            this.html = this.reformatHTML(this.html);\n            await this.modifiedReady();\n            if (this.rootStore.subjects.FEATURE_MODIFIED_PAYTABLE.value.length > 0) {\n                this.html = this.rootStore.subjects.FEATURE_MODIFIED_PAYTABLE.value;\n            }\n            this.showHTML();\n            Core.LOADING_ASSETS.next(false);\n        }\n    }\n\n    protected showHTML(): void {\n        this.paytableHTMLDiv = (document.getElementById('paytableHTMLDiv') ||\n            document.createElement('div')) as HTMLDivElement;\n        if (!document.getElementById('paytableHTMLDiv')) {\n            (this.paytableHTMLDiv as HTMLDivElement).setAttribute('lang', Core.configuration.language);\n            PostMessageDispatcher.htmlOpened('paytable');\n            this.paytableHTMLDiv.id = 'paytableHTMLDiv';\n            this.paytableHTMLDiv.className =\n                (Core.isDesktopMode ? 'desktop noselect' : 'mobile noselect') + ' ' + this.gameKey;\n\n            if (Core.hasFeature(Features.BRANDING) && Core.configuration.gameKey !== this.gameKey) {\n                this.paytableHTMLDiv.classList.add('branded');\n            }\n\n            this.paytableHTMLDiv.innerHTML = this.html;\n            this.paytableHTMLDiv.style.color = 'white';\n            const appDiv = document.getElementById('app-root');\n            appDiv?.appendChild(this.paytableHTMLDiv);\n        }\n        this.paytableHTMLDiv.classList.remove('amount-credits');\n        this.paytableHTMLDiv.classList.remove('amount-currency');\n        this.paytableHTMLDiv.classList.add(Core.MONEY_MODE_IN_CREDITS.value ? 'amount-credits' : 'amount-currency');\n        this.resizeDiv();\n        Core.STAGE_RESIZE_END.pipe(takeUntil(this.closeEvent)).subscribe(this.resizeDiv.bind(this));\n\n        Core.SHOW_ERROR.pipe(takeUntil(this.closeEvent)).subscribe(this.onErrorShown.bind(this));\n        Core.HIDE_ERROR.pipe(takeUntil(this.closeEvent)).subscribe(this.onErrorClosed.bind(this));\n    }\n\n    protected checkForAddingSection(): void {\n        this.availableSection = [\n            'BL_JACKPOT',\n            'GAKL_JACKPOT',\n            'BL_BOOST_JACKPOT',\n            'GAMBLE',\n            'LINES_AND_RULES',\n            'GAKL_LINES_AND_RULES',\n            'MIN_AND_MAX',\n            'SG_JACKPOT',\n            'PREMIUM_JACKPOT',\n            'RTP',\n            'TOPPLING_REELS',\n            'CASCADE_RESPIN',\n            'INCREASING_MULTIPLIERS_TOPPLING_REELS',\n            'CASCADE_REEL_MULTIPLIER',\n            'CASCADE_4_MULTIPLIERS',\n            'CASCADE_FREE_SPINS',\n            'CASCADE_EXTRA_FREE_SPIN',\n            'EXTENDED_BB_CASCADE_FREE_SPINS',\n            // remove when new buy bonus is ready for Ola Diego\n            'BUY_BONUS',\n            // remove when new buy bonus is ready for Ola Diego\n            'CASH_HEAT_BONUS',\n            'RESPIN_BONUS',\n            'MULTIPLE_BUY_BONUS',\n            'DOUBLE_CHANCE',\n            'EXTENDED_MULTIPLE_BUY_BONUS',\n            'BL_EXTENDED_MULTIPLE_BUY_BONUS',\n            'EXT_MULTIPLE_BUY_BONUS_0_BONUS_DESCRIPTION',\n            'EXT_MULTIPLE_BUY_BONUS_1_BONUS_DESCRIPTION',\n            'EXT_MULTIPLE_BUY_BONUS_2_BONUS_DESCRIPTION',\n            'EXT_MULTIPLE_BUY_BONUS_3_BONUS_DESCRIPTION',\n            'BL_EXT_MULTIPLE_BUY_BONUS_0_BONUS_DESCRIPTION',\n            'BL_EXT_MULTIPLE_BUY_BONUS_1_BONUS_DESCRIPTION',\n            'BL_EXT_MULTIPLE_BUY_BONUS_2_BONUS_DESCRIPTION',\n            'EXT_MULTIPLE_BUY_BONUS_DOUBLE_CHANCE_DESCRIPTION',\n            'MYSTERY_JACKPOT',\n            'EXPLOSION',\n            'GAME_RULES',\n            'MAX_WIN_LIMIT',\n            'WAYS_MYSTERY_WIN',\n            'WAYS_MULTIPLIER',\n            'WAYS_PAY_RULES',\n            'MULTIPLIER_FEATURE',\n            'EXTRA_FREE_SPIN_RTP_DESC',\n        ];\n        for (const section of this.availableSection) {\n            switch (section) {\n                case 'BL_JACKPOT':\n                    if (this.html.includes('@SECTION_BL_JACKPOT') && Core.hasFeature(Features.BL_JACKPOT)) {\n                        if (Core.flags.isActive(FeatureFlags.USE_SA_FEATURE)) {\n                            Core.requestManager.get('../assets/paytable/saFeatureBLJackpot.html?' + Core.hash, section);\n                        } else {\n                            Core.requestManager.get('../assets/paytable/blJackpot.html?' + Core.hash, section);\n                        }\n                    } else {\n                        this.html = this.html.replace('@SECTION_BL_JACKPOT', '');\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'BL_BOOST_JACKPOT':\n                    if (this.html.includes('@SECTION_BL_BOOST_JACKPOT') && Core.hasFeature(Features.BL_BOOST_JACKPOT)) {\n                        Core.requestManager.get('../assets/paytable/blBoostJackpot.html?' + Core.hash, section);\n                    } else {\n                        this.html = this.html.replace('@SECTION_BL_BOOST_JACKPOT', '');\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'GAKL_JACKPOT':\n                    if (\n                        this.html.includes('@SECTION_GAKL_JACKPOT') &&\n                        (Core.hasFeature(Features.GAKL_JACKPOT_V1) || Core.hasFeature(Features.GAKL_JACKPOT_BASE))\n                    ) {\n                        const featureFolder = Core.hasFeature(Features.GAKL_JACKPOT_V1)\n                            ? 'gakl-jackpot-v1'\n                            : 'gakl-jackpot-base';\n\n                        const gaklFeature = Core.getGameFeatures().find(\n                            (f) =>\n                                f.featureType === Features.GAKL_JACKPOT_V1 ||\n                                f.featureType === Features.GAKL_JACKPOT_BASE,\n                        );\n\n                        const gaklJackpotHtml =\n                            Core.hasFeature(Features.GAKL_JACKPOT_V1) ||\n                            (gaklFeature as any)?.configuration?.featureChance\n                                ? 'gaklJackpot'\n                                : 'gaklJackpotNoFC';\n\n                        Core.requestManager.get(\n                            `../assets/paytable/${featureFolder}/${gaklJackpotHtml}.html?` + Core.hash,\n                            section,\n                        );\n                    } else {\n                        this.html = this.html.replace('@SECTION_GAKL_JACKPOT', '');\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'GAMBLE':\n                    if (this.html.includes('@SECTION_GAMBLE') && Core.hasFeature(Features.GAMBLE)) {\n                        Core.requestManager.get(\n                            '../assets/features/slot/gamble/paytable/gamble.html?' + Core.hash,\n                            section,\n                        );\n                    } else {\n                        this.html = this.html.replace('@SECTION_GAMBLE', '');\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'SG_JACKPOT':\n                    if (this.html.includes('@SECTION_SG_JACKPOT') && Core.hasFeature(Features.SG_JACKPOT)) {\n                        Core.requestManager.get('../assets/paytable/sgJackpot.html?' + Core.hash, section);\n                    } else {\n                        this.html = this.html.replace('@SECTION_SG_JACKPOT', '');\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'CASH_HEAT_BONUS':\n                    if (this.html.includes('@SECTION_MYSTERY_JACKPOT') && Core.hasFeature(Features.CASH_HEAT)) {\n                        Core.requestManager.get('../assets/paytable/cashHeat.html?' + Core.hash, section);\n                    } else {\n                        this.html = this.html.replace('@SECTION_CASH_HEAT_BONUS', '');\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'RESPIN_BONUS':\n                    if (this.html.includes('@SECTION_RESPIN_BONUS') && Core.hasFeature(Features.HOLD_AND_WIN)) {\n                        Core.requestManager.get(\n                            `../assets/${Core.configuration.gameKey}/hold-and-win/paytable/respinFeature.html?` +\n                                Core.hash,\n                            section,\n                        );\n                    } else {\n                        this.html = this.html.replace('@SECTION_RESPIN_BONUS', '');\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'MYSTERY_JACKPOT':\n                    if (this.html.includes('@SECTION_MYSTERY_JACKPOT') && Core.hasFeature(Features.MYSTERY_JACKPOT)) {\n                        if (Core.flags.isActive(FeatureFlags.USE_SA_FEATURE)) {\n                            Core.requestManager.get(\n                                '../assets/paytable/saFeaturemysteryJackpot.html?' + Core.hash,\n                                section,\n                            );\n                        } else {\n                            Core.requestManager.get('../assets/paytable/mysteryJackpot.html?' + Core.hash, section);\n                        }\n                    } else {\n                        this.html = this.html.replace('@SECTION_MYSTERY_JACKPOT', '');\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'PREMIUM_JACKPOT':\n                    if (\n                        this.html.includes('@SECTION_PREMIUM_JACKPOT') &&\n                        Core.hasFeature(Features.PREMIUM_LINK_JACKPOT)\n                    ) {\n                        Core.requestManager.get('../assets/paytable/premiumLinkJackpot.html?' + Core.hash, section);\n                    } else {\n                        this.html = this.html.replace('@SECTION_PREMIUM_JACKPOT', '');\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'EXPLOSION':\n                    if (this.html.includes('@SECTION_EXPLOSION') && Core.hasFeature(Features.EXPLOSION)) {\n                        Core.requestManager.get('../assets/paytable/explosion.html?' + Core.hash, section);\n                    } else {\n                        // this.html = this.html.replace('@SECTION_CASCADE_REEL_MULTIPLIER', '');\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'LINES_AND_RULES':\n                    if (this.html.includes('@SECTION_LINES_AND_RULES')) {\n                        Core.requestManager.get('../assets/paytable/linesAndRules.html?' + Core.hash, section);\n                    } else {\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'GAKL_LINES_AND_RULES':\n                    if (this.html.includes('@SECTION_GAKL_LINES_AND_RULES')) {\n                        Core.requestManager.get('../assets/paytable/gaklLinesAndRules.html?' + Core.hash, section);\n                    } else {\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'MIN_AND_MAX':\n                    if (this.html.includes('@SECTION_MIN_AND_MAX')) {\n                        Core.requestManager.get('../assets/paytable/minMax.html?' + Core.hash, section);\n                    } else {\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'RTP':\n                    this.html = this.html.replace('@SECTION_' + section, this.formatRTP());\n                    this.availableSection = this.availableSection.filter((word) => word !== section);\n                    break;\n                case 'MAX_WIN_LIMIT':\n                    this.html = this.html.replace('@SECTION_' + section, this.formatMaxWinLimit());\n                    this.availableSection = this.availableSection.filter((word) => word !== section);\n                    break;\n                case 'INCREASING_MULTIPLIERS_TOPPLING_REELS':\n                    if (this.html.includes('@SECTION_INCREASING_MULTIPLIERS_TOPPLING_REELS')) {\n                        Core.requestManager.get(\n                            '../assets/paytable/increasingMultipliersToppLingReels.html?' + Core.hash,\n                            section,\n                        );\n                    } else {\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'TOPPLING_REELS':\n                    if (this.html.includes('@SECTION_TOPPLING_REELS')) {\n                        Core.requestManager.get('../assets/paytable/toppLingReels.html?' + Core.hash, section);\n                    } else {\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n\n                case 'CASCADE_RESPIN':\n                    if (this.html.includes('@SECTION_CASCADE_RESPIN')) {\n                        Core.requestManager.get('../assets/paytable/cascadeRespin.html?' + Core.hash, section);\n                    } else {\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'CASCADE_REEL_MULTIPLIER':\n                    if (\n                        this.html.includes('@SECTION_CASCADE_REEL_MULTIPLIER') &&\n                        Core.hasComponent(SlotComponents.CASCADE_REEL_MULTIPLIER)\n                    ) {\n                        Core.requestManager.get('../assets/paytable/cascadeReelMultiplier.html?' + Core.hash, section);\n                    } else {\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'CASCADE_4_MULTIPLIERS':\n                    if (this.html.includes('@SECTION_CASCADE_4_MULTIPLIERS')) {\n                        Core.requestManager.get('../assets/paytable/cascade4Multipliers.html?' + Core.hash, section);\n                    } else {\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'CASCADE_FREE_SPINS':\n                    if (this.html.includes('@SECTION_CASCADE_FREE_SPINS')) {\n                        Core.requestManager.get('../assets/paytable/cascadeFreeSpins.html?' + Core.hash, section);\n                    } else {\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'CASCADE_EXTRA_FREE_SPIN':\n                    const hasExtraSpinFeature = (this.rootStore.settings.settings.settings.feature as any[]).some(\n                        (feature) => feature === 'WIN_DEDUCTED_EXTRA_SPINS',\n                    );\n                    if (this.html.includes('@SECTION_CASCADE_EXTRA_FREE_SPIN') && hasExtraSpinFeature) {\n                        Core.requestManager.get('../assets/paytable/cascadeExtraFreeSpin.html?' + Core.hash, section);\n                    } else {\n                        this.html = this.html.replace('@SECTION_CASCADE_EXTRA_FREE_SPIN', '');\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'EXTENDED_BB_CASCADE_FREE_SPINS':\n                    if (this.html.includes('@SECTION_EXTENDED_BB_CASCADE_FREE_SPINS')) {\n                        Core.requestManager.get(\n                            '../assets/paytable/extendedBBCascadeFreeSpins.html?' + Core.hash,\n                            section,\n                        );\n                    } else {\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                // remove when new buy bonus is ready for Ola Diego\n                case 'BUY_BONUS':\n                    if (\n                        this.html.includes('@SECTION_BUY_BONUS') &&\n                        Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.DEFAULT) &&\n                        !Core.flags.isActive(FeatureFlags.HIDE_BUY_BONUS)\n                    ) {\n                        Core.requestManager.get('../assets/paytable/buyBonus.html?' + Core.hash, section);\n                    } else {\n                        this.html = this.html.replace('@SECTION_BUY_BONUS', '');\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                // remove when new buy bonus is ready for Ola Diego\n                case 'MULTIPLE_BUY_BONUS':\n                    if (\n                        this.html.includes('@SECTION_MULTIPLE_BUY_BONUS') &&\n                        Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.MULTIPLE_BUY_BONUS)\n                    ) {\n                        Core.requestManager.get('../assets/paytable/multipleBuyBonus.html?' + Core.hash, section);\n                    } else {\n                        this.html = this.html.replace('@SECTION_MULTIPLE_BUY_BONUS', '');\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'DOUBLE_CHANCE':\n                    if (this.html.includes('@SECTION_DOUBLE_CHANCE') && this.hasDoubleChancePart()) {\n                        Core.requestManager.get('../assets/paytable/doubleChance.html?' + Core.hash, section);\n                    } else {\n                        this.html = this.html.replace('@SECTION_DOUBLE_CHANCE', '');\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'EXTENDED_MULTIPLE_BUY_BONUS':\n                    if (\n                        this.html.includes('@SECTION_EXTENDED_MULTIPLE_BUY_BONUS') &&\n                        Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS) &&\n                        !Core.flags.isActive(FeatureFlags.HIDE_BUY_BONUS)\n                    ) {\n                        Core.requestManager.get(\n                            '../assets/paytable/extendedMultipleBuyBonus.html?' + Core.hash,\n                            section,\n                        );\n                    } else {\n                        this.html = this.html.replace('@SECTION_EXTENDED_MULTIPLE_BUY_BONUS', '');\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'EXT_MULTIPLE_BUY_BONUS_0_BONUS_DESCRIPTION':\n                    if (\n                        this.html.includes('@SECTION_EXT_MULTIPLE_BUY_BONUS_0_BONUS_DESCRIPTION') &&\n                        Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS) &&\n                        !Core.flags.isActive(FeatureFlags.HIDE_BUY_BONUS)\n                    ) {\n                        Core.requestManager.get(\n                            '../assets/paytable/extendedMultipleBuyBonus0BonusDescription.html?' + Core.hash,\n                            section,\n                        );\n                    } else {\n                        this.html = this.html.replace('@SECTION_EXT_MULTIPLE_BUY_BONUS_0_BONUS_DESCRIPTION', '');\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'EXT_MULTIPLE_BUY_BONUS_1_BONUS_DESCRIPTION':\n                    if (\n                        this.html.includes('@SECTION_EXT_MULTIPLE_BUY_BONUS_1_BONUS_DESCRIPTION') &&\n                        Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS) &&\n                        !Core.flags.isActive(FeatureFlags.HIDE_BUY_BONUS)\n                    ) {\n                        Core.requestManager.get(\n                            '../assets/paytable/extendedMultipleBuyBonus1BonusDescription.html?' + Core.hash,\n                            section,\n                        );\n                    } else {\n                        this.html = this.html.replace('@SECTION_EXT_MULTIPLE_BUY_BONUS_1_BONUS_DESCRIPTION', '');\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'EXT_MULTIPLE_BUY_BONUS_2_BONUS_DESCRIPTION':\n                    if (\n                        this.html.includes('@SECTION_EXT_MULTIPLE_BUY_BONUS_2_BONUS_DESCRIPTION') &&\n                        Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS) &&\n                        !Core.flags.isActive(FeatureFlags.HIDE_BUY_BONUS)\n                    ) {\n                        Core.requestManager.get(\n                            '../assets/paytable/extendedMultipleBuyBonus2BonusDescription.html?' + Core.hash,\n                            section,\n                        );\n                    } else {\n                        this.html = this.html.replace('@SECTION_EXT_MULTIPLE_BUY_BONUS_2_BONUS_DESCRIPTION', '');\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'EXT_MULTIPLE_BUY_BONUS_3_BONUS_DESCRIPTION':\n                    if (\n                        this.html.includes('@SECTION_EXT_MULTIPLE_BUY_BONUS_3_BONUS_DESCRIPTION') &&\n                        Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS) &&\n                        !Core.flags.isActive(FeatureFlags.HIDE_BUY_BONUS)\n                    ) {\n                        Core.requestManager.get(\n                            '../assets/paytable/extendedMultipleBuyBonus3BonusDescription.html?' + Core.hash,\n                            section,\n                        );\n                    } else {\n                        this.html = this.html.replace('@SECTION_EXT_MULTIPLE_BUY_BONUS_3_BONUS_DESCRIPTION', '');\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'BL_EXTENDED_MULTIPLE_BUY_BONUS':\n                    if (\n                        this.html.includes('@SECTION_BL_EXTENDED_MULTIPLE_BUY_BONUS') &&\n                        Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS) &&\n                        !Core.flags.isActive(FeatureFlags.HIDE_BUY_BONUS)\n                    ) {\n                        Core.requestManager.get(\n                            '../assets/paytable/extendedMultipleBuyBonusBL.html?' + Core.hash,\n                            section,\n                        );\n                    } else {\n                        this.html = this.html.replace('@SECTION_BL_EXTENDED_MULTIPLE_BUY_BONUS', '');\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'BL_EXT_MULTIPLE_BUY_BONUS_0_BONUS_DESCRIPTION':\n                    if (\n                        this.html.includes('@SECTION_BL_EXT_MULTIPLE_BUY_BONUS_0_BONUS_DESCRIPTION') &&\n                        Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS) &&\n                        !Core.flags.isActive(FeatureFlags.HIDE_BUY_BONUS)\n                    ) {\n                        Core.requestManager.get(\n                            '../assets/paytable/extendedMultipleBuyBonusBL0BonusDescription.html?' + Core.hash,\n                            section,\n                        );\n                    } else {\n                        this.html = this.html.replace('@SECTION_BL_EXT_MULTIPLE_BUY_BONUS_0_BONUS_DESCRIPTION', '');\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'BL_EXT_MULTIPLE_BUY_BONUS_1_BONUS_DESCRIPTION':\n                    if (\n                        this.html.includes('@SECTION_BL_EXT_MULTIPLE_BUY_BONUS_1_BONUS_DESCRIPTION') &&\n                        Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS) &&\n                        !Core.flags.isActive(FeatureFlags.HIDE_BUY_BONUS)\n                    ) {\n                        Core.requestManager.get(\n                            '../assets/paytable/extendedMultipleBuyBonusBL1BonusDescription.html?' + Core.hash,\n                            section,\n                        );\n                    } else {\n                        this.html = this.html.replace('@SECTION_BL_EXT_MULTIPLE_BUY_BONUS_1_BONUS_DESCRIPTION', '');\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'BL_EXT_MULTIPLE_BUY_BONUS_2_BONUS_DESCRIPTION':\n                    if (\n                        this.html.includes('@SECTION_BL_EXT_MULTIPLE_BUY_BONUS_2_BONUS_DESCRIPTION') &&\n                        Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS) &&\n                        !Core.flags.isActive(FeatureFlags.HIDE_BUY_BONUS)\n                    ) {\n                        Core.requestManager.get(\n                            '../assets/paytable/extendedMultipleBuyBonusBL2BonusDescription.html?' + Core.hash,\n                            section,\n                        );\n                    } else {\n                        this.html = this.html.replace('@SECTION_BL_EXT_MULTIPLE_BUY_BONUS_2_BONUS_DESCRIPTION', '');\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'EXT_MULTIPLE_BUY_BONUS_DOUBLE_CHANCE_DESCRIPTION':\n                    if (\n                        this.html.includes('@SECTION_EXT_MULTIPLE_BUY_BONUS_DOUBLE_CHANCE_DESCRIPTION') &&\n                        Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS) &&\n                        !Core.flags.isActive(FeatureFlags.HIDE_DOUBLE_CHANCE)\n                    ) {\n                        Core.requestManager.get(\n                            '../assets/paytable/extendedMultipleBuyBonusDoubleChanceDescription.html?' + Core.hash,\n                            section,\n                        );\n                    } else {\n                        this.html = this.html.replace('@SECTION_EXT_MULTIPLE_BUY_BONUS_DOUBLE_CHANCE_DESCRIPTION', '');\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'GAME_RULES':\n                    if (this.html.includes('@SECTION_GAME_RULES')) {\n                        Core.requestManager.loadContent('../assets/paytable/gameRules.html?' + Core.hash, section);\n                    } else {\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'WAYS_MYSTERY_WIN':\n                    if (this.html.includes('@SECTION_WAYS_MYSTERY_WIN') && Core.hasFeature(Features.WAYS_MYSTERY)) {\n                        Core.requestManager.get('../assets/paytable/mysteryWin.html?' + Core.hash, section);\n                    } else {\n                        this.html = this.html.replace('@SECTION_WAYS_MYSTERY_WIN', '');\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'WAYS_MULTIPLIER':\n                    if (this.html.includes('@SECTION_WAYS_MULTIPLIER')) {\n                        Core.requestManager.get('../assets/paytable/waysMultiplier.html?' + Core.hash, section);\n                    } else {\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'WAYS_PAY_RULES':\n                    if (this.html.includes('@SECTION_WAYS_PAY_RULES')) {\n                        Core.requestManager.get('../assets/paytable/waysPayRules.html?' + Core.hash, section);\n                    } else {\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'MULTIPLIER_FEATURE':\n                    if (this.html.includes('@SECTION_MULTIPLIER_FEATURE')) {\n                        Core.requestManager.get('../assets/paytable/multiplierFeature.html?' + Core.hash, section);\n                    } else {\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n                case 'EXTRA_FREE_SPIN_RTP_DESC':\n                    const hasExtraFreeSpinFeature = (this.rootStore.settings.settings.settings.feature as any[]).some(\n                        (feature) => feature === 'WIN_DEDUCTED_EXTRA_SPINS',\n                    );\n                    if (this.html.includes('@SECTION_EXTRA_FREE_SPIN_RTP_DESC') && hasExtraFreeSpinFeature) {\n                        Core.requestManager.get('../assets/paytable/extraFreeSpinRtp.html?' + Core.hash, section);\n                    } else {\n                        this.html = this.html.replace('@SECTION_EXTRA_FREE_SPIN_RTP_DESC', '');\n                        this.availableSection = this.availableSection.filter((word) => word !== section);\n                    }\n                    break;\n            }\n        }\n    }\n\n    protected modifiedReady(): Promise<void> {\n        return new Promise((resolve) => {\n            if (\n                this.rootStore.subjects.FEATURE_MODIFIED_PAYTABLE.value.length > 0 ||\n                this.rootStore.subjects.FEATURE_MODIFY_PAYTABLE.observers.length === 0\n            ) {\n                resolve();\n            }\n        });\n    }\n\n    private addHashStringToAllImages(html: string): string {\n        // @ts-ignore\n        const arrayWithMatches = html.match(/<img.*?src=[\"|'](.*?)[\"|']/gs);\n        // filter only unique correct\n        // @ts-ignore\n        const uniqueArray = arrayWithMatches.filter((v, i, a) => a.indexOf(v) === i);\n\n        if (uniqueArray?.length) {\n            uniqueArray.forEach((match) => {\n                match = match.substring(0, match.length - 1);\n\n                if (match.indexOf('?' + Core.hash) === -1) {\n                    html = html.replace(new RegExp(match, 'g'), match + '?' + Core.hash);\n                }\n            });\n        }\n\n        return html;\n    }\n    // Translate HTML\n    private replaceImagePlaceholders(html: string): string {\n        const map = this.paytableScript.imageMap();\n        return html.replace(/<<([\\w.]+)>>/g, (match, key) => {\n            if (map[key] !== undefined) {\n                return map[key];\n            }\n            const translated = Core.translator.translate(key);\n            return translated !== key ? translated : match;\n        });\n    }\n\n    private translatePaytable(html: string): string {\n        const re = /\\#{.*?\\}#/gi;\n        const match = html.match(re);\n        match?.forEach((element) => {\n            const str: string = element.split('#{').join('').split('}#').join('');\n\n            const newStr = Core.translator.translate(str);\n\n            html = html.replace(element, newStr);\n        });\n\n        return html;\n    }\n\n    // Replace Gamble amounts in HTML\n    private setGambleAmounts(html: string): string {\n        const currentGamble =\n            Core.SELECTED_DENOMINATION.value *\n            this.rootStore.uiStore.SELECTED_BET.value *\n            this.factor *\n            this.gameInitSettings.gambleMultiplier;\n\n        const moneyConfig: any = {};\n        moneyConfig.units = this.rootStore.uiStore.units;\n        moneyConfig.showCurrency = true;\n        moneyConfig.showCredits = false;\n        moneyConfig.currency = this.rootStore.uiStore.currency;\n\n        const maxGamble = this.gameInitSettings.gambleMax;\n\n        const currentBetValue = new Money(currentGamble > maxGamble ? maxGamble : currentGamble);\n        const value: any = currentBetValue.htmlMoneyWithCurrency;\n        html = html.replace(/##GAMBLE_MAX##/g, value);\n        html = html.replace(/##GAMBLE_ATTEMPTS##/g, this.gameInitSettings.maxGambleAttempts.toString());\n\n        // Cases for Jackpots that are NOT single and NOT Premium Jackpot\n        const hasOneJackpot =\n            Core.hasFeature(Features.SG_JACKPOT) ||\n            Core.hasFeature(Features.MYSTERY_JACKPOT) ||\n            Core.hasFeature(Features.BL_JACKPOT) ||\n            Core.hasFeature(Features.BL_BOOST_JACKPOT) ||\n            Core.hasFeature(Features.GAKL_JACKPOT_V1) ||\n            Core.hasFeature(Features.GAKL_JACKPOT_BASE) ||\n            Core.hasFeature(Features.HIGH_CASH_JACKPOT_WON);\n        const hasPremiumLinkJackpot = Core.hasFeature(Features.PREMIUM_LINK_JACKPOT);\n\n        let jackpotText = '';\n        if (hasOneJackpot && hasPremiumLinkJackpot) {\n            jackpotText = Core.translator.translate('PAYTABLE.GAMBLE_PROGRESSIVE_PREMIUM_LINK');\n        } else if (hasOneJackpot) {\n            jackpotText = Core.translator.translate('PAYTABLE.GAMBLE_PROGRESSIVE');\n        }\n\n        html = html.replace('##PROGRESSIVE_JACKPOT##', jackpotText);\n\n        return html;\n    }\n\n    // Replace Jackpot amounts in HTML\n    private setAccumulatedJackpot(html: string): string {\n        const paytable = this.gameInitSettings.paytable[this.slotConfiguration.wildIndex];\n        if (!paytable) {\n            return html;\n        }\n        const payoutsArrayReversed = paytable.coef.slice(0).reverse();\n\n        const moneyConfig: any = {};\n        moneyConfig.units = this.rootStore.uiStore.units;\n        moneyConfig.debug = false;\n        moneyConfig.shouldFitInBounds = true;\n        moneyConfig.showCurrency = !Core.MONEY_MODE_IN_CREDITS.value;\n        moneyConfig.showCredits = Core.MONEY_MODE_IN_CREDITS.value;\n        moneyConfig.currency = this.rootStore.uiStore.currency;\n        moneyConfig.denomination = 1;\n\n        const bet = this.rootStore.uiStore.bets[this.rootStore.uiStore.bets.length - 1];\n        const mtext = this.formatMoney(payoutsArrayReversed[0] * bet * 2, moneyConfig);\n\n        html = html.replace(/##JACKPOT_ACUMULATED##/g, mtext);\n\n        return html;\n    }\n\n    private setRangeTexts(html: string): string {\n        const premiumLinkJackpot = this.gameInitSettings.jackpotStats?.find(\n            (jackpot) => jackpot.jackpotName === 'Premium Link',\n        );\n\n        if (!premiumLinkJackpot?.levelStats) {\n            return html;\n        }\n\n        const levelStatsMap = premiumLinkJackpot.levelStats.reduce(\n            (acc, level) => {\n                acc[level.levelId] = {\n                    minTriggerValue: level.minTriggerValue,\n                    maxTriggerValue: level.maxTriggerValue,\n                    minBetToWin: level.minBetToWin,\n                };\n\n                return acc;\n            },\n            {} as Record<\n                number,\n                {\n                    minTriggerValue: number;\n                    maxTriggerValue: number;\n                    minBetToWin: number;\n                }\n            >,\n        );\n\n        const formatMoney = (value: number): string => {\n            return new Money(value).htmlMoneyWithCurrency;\n        };\n\n        html = html.replace(/##MIN_VALUE_SUPER##/g, formatMoney(levelStatsMap[1].minTriggerValue));\n        html = html.replace(/##MAX_VALUE_SUPER##/g, formatMoney(levelStatsMap[1].maxTriggerValue));\n        html = html.replace(\n            /##MIN_BET_SUPER##/g,\n            formatMoney(this.rootStore.displayedMinBetUnits(levelStatsMap[1].minBetToWin)),\n        );\n\n        html = html.replace(/##MIN_VALUE_MIDDLE##/g, formatMoney(levelStatsMap[2].minTriggerValue));\n        html = html.replace(/##MAX_VALUE_MIDDLE##/g, formatMoney(levelStatsMap[2].maxTriggerValue));\n        html = html.replace(\n            /##MIN_BET_MIDDLE##/g,\n            formatMoney(this.rootStore.displayedMinBetUnits(levelStatsMap[2].minBetToWin)),\n        );\n\n        html = html.replace(/##MIN_VALUE_MINI##/g, formatMoney(levelStatsMap[3].minTriggerValue));\n        html = html.replace(/##MAX_VALUE_MINI##/g, formatMoney(levelStatsMap[3].maxTriggerValue));\n        html = html.replace(\n            /##MIN_BET_MINI##/g,\n            formatMoney(this.rootStore.displayedMinBetUnits(levelStatsMap[3].minBetToWin)),\n        );\n\n        return html;\n    }\n\n    private hasDoubleChancePart(): boolean {\n        const buyBonusComponent: any = Core.getGameComponents().find(\n            (component) => component.componentType === SlotComponents.BUY_BONUS,\n        );\n        return !!buyBonusComponent?.hasDoubleChancePart;\n    }\n\n    // Replace Max Win Factoe bet amounts in HTML\n    private setMaxWinFactor(html: string): string {\n        if (html.search('##MAX_WIN_FACTOR##') !== -1) {\n            let maxWinFactor: string = this.slotConfiguration.maxWinFactor;\n            if (\n                (this.hasDoubleChancePart() && this.rootStore.subjects.DOUBLE_CHANCE_ACTIVATED.value) ||\n                (Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS) &&\n                    this.rootStore.settings.haveGameMode('DOUBLE_CHANCE') &&\n                    this.factor === this.gameInitSettings.getFactorByUniqueGameMode('DOUBLE_CHANCE'))\n            ) {\n                maxWinFactor = this.slotConfiguration.maxWinFactorDoubleChanceActive;\n            }\n            html = html.replace(/##MAX_WIN_FACTOR##/g, maxWinFactor);\n        }\n        return html;\n    }\n\n    // Replace MinMax bet amounts in HTML\n    protected setMinMaxBet(html: string): string {\n        const moneyConfig: any = {};\n        moneyConfig.units = this.rootStore.uiStore.units;\n        moneyConfig.showCurrency = true;\n        moneyConfig.showCredits = false;\n        moneyConfig.currency = this.rootStore.uiStore.currency;\n\n        const valueMin: any = this.formatMinMax(\n            this.rootStore.uiStore.bets[0] * this.rootStore.uiStore.denominations[0] * this.factor,\n        );\n        html = html.replace(/##MIN_BET##/g, valueMin);\n\n        const valueMax = this.formatMinMax(this.findMaxPossibleBet());\n\n        html = html.replace(/##MAX_BET##/g, valueMax);\n\n        const hasBellLinkBuyBonus =\n            Core.hasFeature(Features.BL_JACKPOT) &&\n            Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS) &&\n            !Core.flags.isActive(FeatureFlags.HIDE_BUY_BONUS);\n\n        html = html.replace(\n            /##EXTENDED_MULTIPLE_BUY_BONUS_MAX_BET##/g,\n            hasBellLinkBuyBonus ? Core.translator.translate('PAYTABLE.EXTENDED_MULTIPLE_BUY_BONUS_MAX_BET') : '',\n        );\n\n        html = html.replace(/##VERSION##/g, this.formatVesrion());\n\n        return html;\n    }\n\n    protected findMaxPossibleBet(): number {\n        const { denominations, bets } = this.rootStore.uiStore;\n        const maxBetLimit = this.getMaxBet(this.factor);\n\n        let valueMax = 0;\n        const length =\n            this.gameInitSettings.buyBonusDenominations &&\n            this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value\n                ? this.gameInitSettings.buyBonusDenominations.length\n                : denominations.length;\n        for (let i = 0; i < length; i++) {\n            for (let j = 0; j < bets.length; j++) {\n                const currentValue = bets[j] * denominations[i] * this.factor;\n                if (valueMax < currentValue && currentValue <= maxBetLimit) {\n                    valueMax = currentValue;\n                }\n            }\n        }\n        return valueMax;\n    }\n\n    protected findMaxPossibleBetForBLBB(): number {\n        const bets = this.rootStore.uiStore.bets ?? [];\n        const denominations = this.rootStore.settings.buyBonusDenominations ?? [];\n        const factors = this.rootStore.settings.factors ?? [];\n\n        const maxBet = bets.length ? Math.max(...bets) : 0;\n        const maxDenomination = denominations.length ? Math.max(...denominations) : 0;\n        const maxFactor = factors.length ? Math.max(...factors) : 0;\n\n        return maxBet * maxDenomination * maxFactor;\n    }\n\n    private getMaxBet(factor: number): number {\n        const maxBetLimits = this.rootStore.settings.clientSettings?.maxBetLimits?.hasOwnProperty(\n            this.rootStore.settings.currency,\n        )\n            ? this.rootStore.settings.clientSettings.maxBetLimits[this.rootStore.settings.currency]\n            : undefined;\n        const isDoubleChanceFactor =\n            this.rootStore.settings.haveGameMode('DOUBLE_CHANCE') &&\n            factor === this.rootStore.settings.getFactorByUniqueGameMode('DOUBLE_CHANCE');\n        const maxBet =\n            maxBetLimits && !isDoubleChanceFactor && this.rootStore.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value\n                ? maxBetLimits * Core.PLAYER_BALANCE.value.units\n                : Infinity;\n        const maxJurisdictionalBet = this.rootStore.settings.maxBet\n            ? this.rootStore.settings.maxBet * Core.PLAYER_BALANCE.value.units\n            : Infinity;\n\n        return Math.min(maxBet, maxJurisdictionalBet);\n    }\n\n    protected formatVesrion(): string {\n        const version = `##GAME_NAME##<br>\n        ${Core.translator.translate('PAYTABLE.GAME_CLIENT_VERSION')} ${Core.configuration.version}`;\n        if (this.gameInitSettings.gameVersion !== '') {\n            return (\n                version +\n                `<br>${Core.translator.translate('PAYTABLE.GAME_VERSION')} ${this.gameInitSettings.gameVersion}`\n            );\n        }\n        return version;\n    }\n\n    private setGameKeysInAssetPaths(html: string): string {\n        html = html.replace(/##GAME_KEY##/g, this.gameKey);\n        return html;\n    }\n\n    private setBuyBonusBetValues(html: string): string {\n        if (this.gameInitSettings.haveGameMode('BUY_BONUS')) {\n            html = html.replace(\n                /##BUY_BONUS_BET_VALUE##/g,\n                (\n                    this.gameInitSettings.getFactorByUniqueGameMode('BUY_BONUS') /\n                    this.gameInitSettings.getFactorByUniqueGameMode('NORMAL_MODE')\n                ).toString(),\n            );\n        }\n        return html;\n    }\n\n    private setSuperBuyBonusBetValues(html: string): string {\n        if (this.gameInitSettings.haveGameMode('SUPER_BUY_BONUS')) {\n            html = html.replace(\n                /##SUPER_BUY_BONUS_BET_VALUE##/g,\n                (\n                    this.gameInitSettings.getFactorByUniqueGameMode('SUPER_BUY_BONUS') /\n                    this.gameInitSettings.getFactorByUniqueGameMode('NORMAL_MODE')\n                ).toString(),\n            );\n        }\n        return html;\n    }\n\n    private setMegaBuyBonusBetValues(html: string): string {\n        if (this.gameInitSettings.haveGameMode('MEGA_BUY_BONUS')) {\n            html = html.replace(\n                /##MEGA_BUY_BONUS_BET_VALUE##/g,\n                (\n                    this.gameInitSettings.getFactorByUniqueGameMode('MEGA_BUY_BONUS') /\n                    this.gameInitSettings.getFactorByUniqueGameMode('NORMAL_MODE')\n                ).toString(),\n            );\n        }\n        return html;\n    }\n\n    private setDoubleChanceBetValues(html: string): string {\n        if (this.gameInitSettings.haveGameMode('DOUBLE_CHANCE')) {\n            html = html.replace(\n                /##DOUBLE_CHANCE_BET_VALUE##/g,\n                (\n                    this.gameInitSettings.getFactorByUniqueGameMode('DOUBLE_CHANCE') /\n                    this.gameInitSettings.getFactorByUniqueGameMode('NORMAL_MODE')\n                ).toString(),\n            );\n        }\n        return html;\n    }\n\n    private setMultiplierBetValues(html: string): string {\n        // const currentBet = this.rootStore.uiStore.SELECTED_BET.value * Core.SELECTED_DENOMINATION.value;\n        if (this.gameInitSettings.haveGameMode('HIGH_MULTIPLIER')) {\n            html = html.replace(\n                /##BET_VALUE_MULTIPLIER_10##/g,\n                (\n                    this.gameInitSettings.getFactorByUniqueGameMode('HIGH_MULTIPLIER') /\n                    this.gameInitSettings.getFactorByUniqueGameMode('NORMAL_MODE')\n                ).toString(),\n            );\n        }\n        if (this.gameInitSettings.haveGameMode('MEDIUM_MULTIPLIER')) {\n            html = html.replace(\n                /##BET_VALUE_MULTIPLIER_5##/g,\n                (\n                    this.gameInitSettings.getFactorByUniqueGameMode('MEDIUM_MULTIPLIER') /\n                    this.gameInitSettings.getFactorByUniqueGameMode('NORMAL_MODE')\n                ).toString(),\n            );\n        }\n        if (this.gameInitSettings.haveGameMode('LOW_MULTIPLIER')) {\n            html = html.replace(\n                /##BET_VALUE_RANDOM_MULTIPLIER##/g,\n                (\n                    this.gameInitSettings.getFactorByUniqueGameMode('LOW_MULTIPLIER') /\n                    this.gameInitSettings.getFactorByUniqueGameMode('NORMAL_MODE')\n                ).toString(),\n            );\n        }\n        return html;\n    }\n\n    private setLanguageInAssetPaths(html: string): string {\n        const currentLanguage = Core.configuration.language;\n        const defaultLanguage = Core.translator.defaultLanguage;\n\n        const localizedImagePattern =\n            /<img\\b([^>]*\\bsrc=[\"'])([^\"']*\\/translations\\/)##LANGUAGE##(\\/[^\"']+)([\"'][^>]*)>/i;\n        if (localizedImagePattern.test(html)) {\n            html = html.replace(\n                /<img\\b([^>]*\\bsrc=[\"'])([^\"']*\\/translations\\/)##LANGUAGE##(\\/[^\"']+)([\"'][^>]*)>/gi,\n                (_match, attributes, path, imagePath, quoteAndAttributes) => {\n                    const currentPath = `${path}${currentLanguage}${imagePath}`;\n                    const defaultPath = `${path}${defaultLanguage}${imagePath}`;\n                    const fallbackHandler = `this.onerror=null;var currentSrc=this.getAttribute('src')||'';var suffix=currentSrc.includes('?')?currentSrc.slice(currentSrc.indexOf('?')):'';this.src='${defaultPath}' + suffix;`;\n                    return `<img${attributes}${currentPath}${quoteAndAttributes} onerror=\"${fallbackHandler}\">`;\n                },\n            );\n        }\n\n        return html.replace(/##LANGUAGE##/g, currentLanguage);\n    }\n\n    private setJackpotLimits(html: string): string {\n        if (!this.gameInitSettings.jackpotStats || this.gameInitSettings.jackpotStats.length === 0) {\n            [1, 2, 3, 4].forEach((jpNumber: number) => {\n                html = html.replace(`##JACKPOTLIMIT${jpNumber}##`, '');\n            });\n            return html;\n        }\n\n        const hasPremiumLink = this.gameInitSettings.jackpotStats.some(\n            (jackpot) => jackpot.jackpotName === 'Premium Link',\n        );\n\n        if (hasPremiumLink) {\n            return this.setPremiumLinkJackpotLimits(html);\n        }\n\n        const jpLimitText = Core.translator.translate('PAYTABLE.JACKPOT_LIMIT');\n        const foundLimits = new Set<number>();\n        this.gameInitSettings.jackpotStats.forEach((jackpot) => {\n            jackpot.levelStats?.forEach((l) => {\n                if (l.limit && l.limit > 0) {\n                    foundLimits.add(l.levelId);\n\n                    const moneyValue = new Money(l.limit);\n                    const jpLevelLimitText = jpLimitText.replace('##LIMIT_AMOUNT##', moneyValue.htmlMoneyWithCurrency);\n\n                    html = html.replace(`##JACKPOTLIMIT${l.levelId}##`, `<br /> ${jpLevelLimitText}`);\n                }\n            });\n        });\n        [1, 2, 3, 4].forEach((jpNumber: number) => {\n            if (!foundLimits.has(jpNumber)) {\n                html = html.replace(`##JACKPOTLIMIT${jpNumber}##`, '');\n            }\n        });\n\n        return html;\n    }\n\n    private setPremiumLinkJackpotLimits(html: string): string {\n        const jpLimitText = Core.translator.translate('PAYTABLE.JACKPOT_LIMIT');\n        const foundLimits = new Set<number>();\n        const premiumLink = this.gameInitSettings.jackpotStats.find(\n            (jackpot) => jackpot.jackpotName === 'Premium Link',\n        );\n\n        if (!premiumLink) {\n            return html;\n        }\n\n        premiumLink.levelStats?.forEach((level) => {\n            if (level.levelId >= 1 && level.levelId <= 3 && level.limit > 0) {\n                const placeholderNumber = level.levelId + 1;\n                const moneyValue = new Money(level.limit);\n                const jpLevelLimitText = jpLimitText.replace('##LIMIT_AMOUNT##', moneyValue.htmlMoneyWithCurrency);\n\n                foundLimits.add(placeholderNumber);\n                html = html.replace(`##JACKPOTLIMIT${placeholderNumber}##`, `<br /> ${jpLevelLimitText}`);\n            }\n        });\n\n        const progressiveLimit = this.gameInitSettings.jackpotStats\n            .filter((jackpot) => jackpot.jackpotName !== 'Premium Link')\n            .flatMap((jackpot) => jackpot.levelStats ?? [])\n            .find((level) => level.limit > 0)?.limit;\n\n        if (progressiveLimit) {\n            foundLimits.add(1);\n\n            const moneyValue = new Money(progressiveLimit);\n            const jpLevelLimitText = jpLimitText.replace('##LIMIT_AMOUNT##', moneyValue.htmlMoneyWithCurrency);\n\n            html = html.replace('##JACKPOTLIMIT1##', `<br /> ${jpLevelLimitText}`);\n        }\n\n        [1, 2, 3, 4].forEach((jpNumber: number) => {\n            if (!foundLimits.has(jpNumber)) {\n                html = html.replace(`##JACKPOTLIMIT${jpNumber}##`, '');\n            }\n        });\n\n        return html;\n    }\n\n    private setBuyBonusText(html: string): string {\n        let buyBonusText: string = '';\n        if (this.gameInitSettings.clientSettings?.maxBetLimits || this.gameInitSettings.maxBet) {\n            const maxBetForBonus: number = Math.min(\n                this.gameInitSettings.clientSettings?.maxBetLimits\n                    ? this.gameInitSettings.clientSettings?.maxBetLimits[Core.PLAYER_BALANCE.value.currency]\n                    : Infinity,\n                this.gameInitSettings.maxBet ?? Infinity,\n            );\n            if (maxBetForBonus) {\n                const formatedValue = this.formatMinMax(maxBetForBonus * this.gameInitSettings.units);\n                buyBonusText =\n                    '<br>' +\n                    Core.translator.translate('PAYTABLE.FREE_SPINS_MAX_BET') +\n                    ` <span class=\"noWrap\">${formatedValue}.</span><br>`;\n            }\n        }\n        html = html.replace(/##BUY_BONUS##/g, buyBonusText);\n        return html;\n    }\n\n    private setSuperBuyBonusText(html: string): string {\n        let buyBonusText: string = '';\n        if (this.gameInitSettings.clientSettings?.maxBetLimits || this.gameInitSettings.maxBet) {\n            const maxBetForBonus: number = Math.min(\n                this.gameInitSettings.clientSettings?.maxBetLimits\n                    ? this.gameInitSettings.clientSettings?.maxBetLimits[Core.PLAYER_BALANCE.value.currency]\n                    : Infinity,\n                this.gameInitSettings.maxBet ?? Infinity,\n            );\n            if (maxBetForBonus) {\n                const formatedValue = this.formatMinMax(maxBetForBonus * this.gameInitSettings.units);\n                buyBonusText =\n                    '<br>' +\n                    Core.translator.translate('PAYTABLE.SUPER_SPINS_MAX_BET') +\n                    ` <span class=\"noWrap\">${formatedValue}.</span><br>`;\n            }\n        }\n        html = html.replace(/##SUPER_BUY_BONUS##/g, buyBonusText);\n        return html;\n    }\n\n    private setMaxBetBuyBonusText(html: string): string {\n        let buyBonusText: string = '';\n        if (this.gameInitSettings.clientSettings?.maxBetLimits || this.gameInitSettings.maxBet) {\n            const maxBetForBonus: number = Math.min(\n                this.gameInitSettings.clientSettings?.maxBetLimits\n                    ? this.gameInitSettings.clientSettings?.maxBetLimits[Core.PLAYER_BALANCE.value.currency]\n                    : Infinity,\n                this.gameInitSettings.maxBet ?? Infinity,\n            );\n            if (maxBetForBonus) {\n                const formatedValue = this.formatMinMax(maxBetForBonus * this.gameInitSettings.units);\n                buyBonusText = formatedValue;\n            }\n        }\n        html = html.replace(/##MAX_BET_BUY_BONUS##/g, buyBonusText);\n        return html;\n    }\n\n    private setMaxBetBellLinkBuyBonusText(html: string): string {\n        let buyBonusText: string = '';\n        const bb = this.findMaxPossibleBetForBLBB();\n        let finalValue: number = bb;\n\n        if (this.gameInitSettings.clientSettings?.maxBetLimits || this.gameInitSettings.maxBet) {\n            const maxBetForBonus: number = Math.min(\n                this.gameInitSettings.clientSettings?.maxBetLimits\n                    ? this.gameInitSettings.clientSettings?.maxBetLimits[Core.PLAYER_BALANCE.value.currency]\n                    : Infinity,\n                this.gameInitSettings.maxBet ?? Infinity,\n            );\n            if (maxBetForBonus) {\n                finalValue = Math.min(maxBetForBonus * this.gameInitSettings.units, bb);\n            }\n        }\n\n        const formatedValue = this.formatMinMax(finalValue);\n        buyBonusText = formatedValue;\n\n        html = html.replace(/##MAX_BET_BELL_LINK_BUY_BONUS##/g, buyBonusText);\n        return html;\n    }\n\n    // Generate HTML for each Payout element\n    private setPayoutItem(obj: any): string {\n        const symbol = obj.symbol;\n        const img = this.slotConfiguration.symbolsConfig[symbol].texture;\n        let html: string = '';\n        if (!obj.noImage) {\n            html += ' <img class=\"width-100\" src=\"../assets/' + this.gameKey + '/paytable/images/' + img + '\"/>';\n        }\n\n        const coef = this.gameInitSettings.paytable[symbol];\n        const payoutsArrayReversed = coef.coef.slice(0).reverse();\n\n        const moneyConfig: MoneyTextConfig = new MoneyTextConfig();\n        moneyConfig.shouldFitInBounds = true;\n        moneyConfig.showCurrency = !Core.MONEY_MODE_IN_CREDITS.value;\n        moneyConfig.showCredits = Core.MONEY_MODE_IN_CREDITS.value;\n        moneyConfig.units = this.rootStore.uiStore.units;\n        moneyConfig.currency = this.rootStore.uiStore.currency;\n        moneyConfig.denomination = Core.SELECTED_DENOMINATION.value;\n        const isScatter = obj.isScatter ? true : false;\n        const maxSymbols = obj.maxSymbols ? obj.maxSymbols : this.rootStore.subjects.NUMBER_OF_REELS.value;\n        const startValue: number = !isScatter ? maxSymbols : this.maxScattersValue(obj.symbol);\n\n        let duplicates = '';\n\n        if (obj.duplicateValues) {\n            duplicates += '<div class=\"payoutDuplicateValues noWrap flex-col\">';\n            payoutsArrayReversed.forEach((money) => {\n                const duplicatePayoutValue = this.formatMoney(\n                    this.rootStore.uiStore.SELECTED_BET.value * money * obj.duplicateValues,\n                    moneyConfig,\n                );\n\n                duplicates += '<c>' + duplicatePayoutValue + '</c>';\n            });\n            duplicates += '</div>';\n            html += '<div class=\"flex width-100 justify-evenly\">';\n            html += '<div class=\"payoutValues duplicates \">';\n        } else {\n            html += '<div class=\"payoutValues\">';\n        }\n\n        payoutsArrayReversed.forEach((money, symbolCountIndex) => {\n            const payoutCount = (startValue - symbolCountIndex).toString();\n            const betMoney = this.rootStore.uiStore.SELECTED_BET.value * money;\n            const formatted = this.formatMoney(betMoney, moneyConfig, isScatter);\n            if (\n                obj.maxBetSubstitute &&\n                symbolCountIndex === 0 &&\n                this.rootStore.uiStore.bets[this.rootStore.uiStore.bets.length - 1] ===\n                    this.rootStore.uiStore.SELECTED_BET.value\n            ) {\n                html +=\n                    '<span class=\"payoutValue flex align-items-center\"><b class=\"payoutXColors\">x' +\n                    payoutCount +\n                    '</b><img class=\"maxBetSubstitute\" src=\"../assets/' +\n                    this.gameKey +\n                    '/paytable/images/' +\n                    obj.maxBetSubstitute +\n                    '\"/></span>';\n            } else {\n                html +=\n                    '<span class=\"payoutValue noWrap flex\"><b class=\"payoutXColors\">x' +\n                    payoutCount +\n                    '</b>' +\n                    '<span class=\"flex align-items-baseline\">' +\n                    formatted +\n                    '</span>' +\n                    '</span>';\n            }\n        });\n\n        html += '</div>';\n        html += duplicates;\n        if (obj.duplicateValues) {\n            html += '</div>';\n        }\n        return html;\n    }\n\n    // Generate HTML for each Payout element\n    private setCascadePayoutItem(obj: any, step: number, minWinSymbols: number, moreThenSymbols: number): string {\n        const symbol = obj.symbol;\n        let html: string = '';\n\n        const coef = this.gameInitSettings.paytable[symbol];\n        let payoutsArray = coef.coef.slice(0);\n\n        const moneyConfig: MoneyTextConfig = new MoneyTextConfig();\n        moneyConfig.shouldFitInBounds = true;\n        moneyConfig.showCurrency = !Core.MONEY_MODE_IN_CREDITS.value;\n        moneyConfig.showCredits = Core.MONEY_MODE_IN_CREDITS.value;\n        moneyConfig.units = this.rootStore.uiStore.units;\n        moneyConfig.currency = this.rootStore.uiStore.currency;\n        moneyConfig.denomination = Core.SELECTED_DENOMINATION.value;\n\n        html += '<div class=\"payoutValues\">';\n\n        if (obj.isScatter && obj.groupScattersIfSameValues) {\n            payoutsArray = payoutsArray.slice(0, 3);\n        }\n        for (let i: number = payoutsArray.length - 1; i >= 0; i -= step) {\n            const minSymbolsToWin: number = minWinSymbols;\n            const betMoney: number = this.rootStore.uiStore.SELECTED_BET.value * payoutsArray[i];\n            const formatted: string = this.formatMoney(betMoney, moneyConfig);\n\n            let _duplicates: number = 0;\n            if (payoutsArray[i] === payoutsArray[i - 1]) {\n                _duplicates = 1;\n                i--;\n            }\n            let symbols: number = i;\n            if (i === payoutsArray.length - 1) {\n                symbols =\n                    this.rootStore.subjects.NUMBER_OF_REELS.value *\n                        this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value -\n                    minSymbolsToWin -\n                    1;\n            }\n\n            html += '<span class=\"payoutValue noWrap flex\"><b class=\"payoutXColors\">';\n            if (obj.isScatter) {\n                const scatterConfig = this.slotConfiguration.scattersConfig.find((el) => el.index === obj.symbol);\n                if (obj.groupScattersIfSameValues && payoutsArray.length - 1 === i) {\n                    html += (scatterConfig.minCount + i + 1).toString() + '+';\n                } else {\n                    html += 'x' + (scatterConfig.minCount + i + 1).toString();\n                }\n            } else if (Number(minSymbolsToWin) + i >= moreThenSymbols) {\n                html += Number(minSymbolsToWin + i) + '+';\n            } else {\n                html += Number(minSymbolsToWin + i) + ' - ' + Number(minSymbolsToWin + symbols + step);\n            }\n            html += '</b>' + '<span class=\"flex align-items-baseline\">' + formatted + '</span>' + '</span>';\n        }\n\n        html += '</div>';\n        if (obj.duplicateValues) {\n            html += '</div>';\n        }\n        return html;\n    }\n\n    // Generate HTML for each Payout element\n    private setClusterPayoutItem(obj: any): string {\n        const symbol = obj.symbol;\n        let html: string = '';\n\n        const coef = this.gameInitSettings.paytable[symbol];\n        let payoutsArray = coef.coef.slice(0);\n\n        const moneyConfig: MoneyTextConfig = new MoneyTextConfig();\n        moneyConfig.shouldFitInBounds = true;\n        moneyConfig.showCurrency = !Core.MONEY_MODE_IN_CREDITS.value;\n        moneyConfig.showCredits = Core.MONEY_MODE_IN_CREDITS.value;\n        moneyConfig.units = this.rootStore.uiStore.units;\n        moneyConfig.currency = this.rootStore.uiStore.currency;\n        moneyConfig.denomination = Core.SELECTED_DENOMINATION.value;\n\n        html += '<div class=\"payoutValues\">';\n\n        if (obj.isScatter && obj.groupScattersIfSameValues) {\n            payoutsArray = payoutsArray.slice(0, 3);\n        }\n        for (let i: number = payoutsArray.length - 1; i >= 0; i--) {\n            const minSymbolsToWin: number = 5;\n            const betMoney: number = this.rootStore.uiStore.SELECTED_BET.value * payoutsArray[i];\n            const formatted: string = this.formatMoney(betMoney, moneyConfig);\n\n            const upperI: number = i;\n            let isDuplicate: boolean = false;\n            if (payoutsArray[i] === payoutsArray[i - 1]) {\n                isDuplicate = true;\n                i--;\n            }\n            const lowerLabel: number = minSymbolsToWin + i;\n            const upperLabel: number = minSymbolsToWin + upperI;\n            const isMaxEntry: boolean = upperI === payoutsArray.length - 1;\n\n            html +=\n                '<span class=\"payoutValue noWrap flex\"><b class=\"payoutXColors\" style=\"display:inline-block;min-width:3.5em;text-align:right;\">';\n            if (obj.isScatter) {\n                const scatterConfig = this.slotConfiguration.scattersConfig.find((el) => el.index === obj.symbol);\n                if (obj.groupScattersIfSameValues && payoutsArray.length - 1 === i) {\n                    html += (scatterConfig.minCount + i + 1).toString() + '+';\n                } else {\n                    html += 'x' + (scatterConfig.minCount + i + 1).toString();\n                }\n            } else if (isMaxEntry) {\n                html += upperLabel + '+';\n            } else if (isDuplicate) {\n                html += lowerLabel + '-' + upperLabel;\n            } else if (lowerLabel < 10) {\n                html += `&nbsp;&nbsp;` + lowerLabel;\n            } else {\n                html += lowerLabel;\n            }\n            html += '</b>' + '<span class=\"flex align-items-baseline\">' + formatted + '</span>' + '</span>';\n        }\n\n        html += '</div>';\n        if (obj.duplicateValues) {\n            html += '</div>';\n        }\n        return html;\n    }\n\n    // Correct max scatters value\n    private maxScattersValue(scatterIndex: number): number {\n        const { validReels, maxPerReel = 1 } = this.slotConfiguration.scattersConfig.find(\n            (el) => el.index === scatterIndex,\n        );\n        const startValue =\n            validReels.reduce((acc: number, el: boolean) => {\n                return el === true ? acc + 1 : acc;\n            }, 0) * maxPerReel;\n\n        return startValue;\n    }\n\n    private setPickMeValues(html: string, pickMeArray: RegExpMatchArray): string {\n        const totalBet: number = this.rootStore.uiStore.SELECTED_BET.value * this.gameInitSettings.factor;\n        const scatterCoefs = [...this.gameInitSettings.scatterCoefs].reverse();\n        const moneyConfig: MoneyTextConfig = new MoneyTextConfig();\n        moneyConfig.shouldFitInBounds = true;\n        moneyConfig.showCurrency = !Core.MONEY_MODE_IN_CREDITS.value;\n        moneyConfig.showCredits = Core.MONEY_MODE_IN_CREDITS.value;\n        moneyConfig.units = this.rootStore.uiStore.units;\n        moneyConfig.currency = this.rootStore.uiStore.currency;\n        moneyConfig.denomination = Core.SELECTED_DENOMINATION.value;\n        pickMeArray.map((el) => {\n            const configJson = /\\{.*?\\}/.exec(el);\n            const config = configJson ? JSON.parse(configJson[0]) : {};\n\n            const correctValuesArray = scatterCoefs[config.valuesArrayOffset].map((coef) => coef * totalBet);\n            if (config.from) {\n                html = html.replace(el, this.formatMoney(correctValuesArray[0], moneyConfig));\n                return el;\n            }\n            if (config.to) {\n                html = html.replace(\n                    el,\n                    this.formatMoney(correctValuesArray[correctValuesArray.length - 1], moneyConfig),\n                );\n                return el;\n            }\n            const formated = correctValuesArray.map(\n                (value) => `<span class=\"noWrap\">${this.formatMoney(value, moneyConfig)}</span>`,\n            );\n            const last = formated.pop();\n            const pickMeValues = `${formated.join(', ')}\n            <c>#{PAYTABLE.OR}#</c>\n            ${last}`;\n\n            html = html.replace(el, pickMeValues);\n\n            return el;\n        });\n\n        return html;\n    }\n    private setScriptResult(html: string, scriptsArray: RegExpMatchArray): string {\n        scriptsArray.map((el) => {\n            const configJson = /\\{.*?\\}/.exec(el);\n            const config = configJson ? JSON.parse(configJson[0]) : {};\n\n            const scriptResult = this.paytableScript[config.func](config.params);\n            html = html.replace(el, scriptResult);\n\n            return el;\n        });\n        return html;\n    }\n\n    private replaceGambleXTwoImage(html: string): string {\n        return html.replace(\"<img src='../assets/paytable/images/x2.png'/>\", this.paytableScript.gambleXTwoImage());\n    }\n\n    private applyRestrictions(html: string): string {\n        let result = html;\n        Core.flags.all.forEach((flag, key) => {\n            if (!flag.isActive) return;\n            // Explicit map, not `RestrictionType[key]`: the enums do not share key names, so\n            // indexing by the flag key resolved to undefined for HIDE_JACKPOT, HIDE_DOUBLE_CHANCE\n            // and USE_SA_FEATURE — the three that actually gate paytable sections.\n            const restrictionValue = RESTRICTION_TYPE_BY_FEATURE_FLAG[key];\n            if (restrictionValue) {\n                result = result.replace('restriction:' + restrictionValue, 'display-none');\n            }\n        });\n        return result;\n    }\n\n    private formatRTP(): string {\n        let html = '';\n        if (this.gameInitSettings.rtp && Object.keys(this.gameInitSettings.rtp).length) {\n            html = `\n            <div class=\"sectionContainer\">\n                <span class=\"sectionTitle\">\n                    <span>${Core.translator.translate('PAYTABLE.RTP')}</span>\n                </span>\n                <img src=\"../assets/${this.gameKey}/paytable/images/lineLong.png\" class=\"titleLine\">\n                <span class=\"sectionDescription\"> \n            `;\n            const showTotals: boolean = this.gameInitSettings.rtp.hasOwnProperty('showTotals')\n                ? this.gameInitSettings.rtp.showTotals\n                : false;\n            const jp: number = this.gameInitSettings.rtp.hasOwnProperty('jp') ? this.gameInitSettings.rtp.jp / 1000 : 0;\n            const min: number = this.gameInitSettings.rtp.hasOwnProperty('min')\n                ? showTotals\n                    ? this.gameInitSettings.rtp.min / 100 + jp\n                    : this.gameInitSettings.rtp.min / 100\n                : -1;\n            const max: number = this.gameInitSettings.rtp.hasOwnProperty('max')\n                ? showTotals\n                    ? this.gameInitSettings.rtp.max / 100 + jp\n                    : this.gameInitSettings.rtp.max / 100\n                : -1;\n\n            const digitsMin = Number(min.toFixed(2)) === Number(min.toFixed(3)) ? 2 : 3;\n            const digitsMax = Number(max.toFixed(2)) === Number(max.toFixed(3)) ? 2 : 3;\n            const digitsJP = Number(jp.toFixed(2)) === Number(jp.toFixed(3)) ? 2 : 3;\n            if (min > 0 && max > 0 && min !== max) {\n                html += `<p>${Core.translator\n                    .translate('PAYTABLE.RTP_MIN')\n                    .replace('##VALUE##', '<c>' + min.toFixed(digitsMin) + '%</c>')}</p>`;\n\n                html += `<p><br>${Core.translator\n                    .translate('PAYTABLE.RTP_MAX')\n                    .replace('##VALUE##', '<c>' + max.toFixed(digitsMax) + '%</c>')}</p>`;\n\n                if (jp > 0 && !showTotals) {\n                    html += `<p><br>${Core.translator\n                        .translate('PAYTABLE.RTP_JACKPOT')\n                        .replace('##VALUE##', '<c>' + jp.toFixed(digitsJP) + '%</c>')}</p>`;\n                }\n            } else if (min > 0) {\n                if (jp > 0 && !showTotals) {\n                    const rtpMainSentenceKey: string = this.hasMultipleRTP\n                        ? 'PAYTABLE.RTP_MULTIPLE'\n                        : 'PAYTABLE.RTP_VALUE_AND_JACKPOT';\n\n                    html += `<p><br>${Core.translator\n                        .translate(rtpMainSentenceKey)\n                        .replace('##VALUE##', '<c>' + min.toFixed(digitsMin) + '%</c>')\n                        .replace('##VALUE2##', '<c>' + jp.toFixed(digitsJP) + '%</c>')}</p>`;\n                } else {\n                    const rtpMainSentenceKey: string = this.hasMultipleRTP\n                        ? 'PAYTABLE.RTP_MULTIPLE'\n                        : 'PAYTABLE.RTP_VALUE';\n\n                    html += `${Core.translator\n                        .translate(rtpMainSentenceKey)\n                        .replace('##VALUE##', '<c>' + min.toFixed(digitsMin) + '%</c>')}`;\n                }\n            } else if (max > 0) {\n                if (jp > 0 && !showTotals) {\n                    const rtpMainSentenceKey: string = this.hasMultipleRTP\n                        ? 'PAYTABLE.RTP_MULTIPLE'\n                        : 'PAYTABLE.RTP_VALUE_AND_JACKPOT';\n\n                    html += `<p><br>${Core.translator\n                        .translate(rtpMainSentenceKey)\n                        .replace('##VALUE##', '<c>' + max.toFixed(digitsMax) + '%</c>')\n                        .replace('##VALUE2##', '<c>' + jp.toFixed(digitsJP) + '%</c>')}</p>`;\n                } else {\n                    const rtpMainSentenceKey: string = this.hasMultipleRTP\n                        ? 'PAYTABLE.RTP_MULTIPLE'\n                        : 'PAYTABLE.RTP_VALUE';\n\n                    html += `${Core.translator\n                        .translate(rtpMainSentenceKey)\n                        .replace('##VALUE##', '<c>' + max.toFixed(digitsMax) + '%</c>')}`;\n                }\n            }\n\n            if (this.hasMultipleRTP) {\n                html += this.addMultipleRTPInfo(jp, digitsJP, showTotals);\n            }\n\n            html += '</span></div>';\n        }\n        return html;\n    }\n    private addMultipleRTPInfo(jpRTP: number, digitsJP: number, showTotals?: boolean): string {\n        let { doubleChance: doubleChanceRTP, buyBonus: buyBonusRTP, modes } = this.multipleRTPDetails;\n\n        let html = '';\n        if (this.slotConfiguration.hasOldBuyBonusRTPs) {\n            if (buyBonusRTP && !Core.flags.isActive(FeatureFlags.HIDE_BUY_BONUS)) {\n                buyBonusRTP /= 100;\n                const calculatedBuyBonusRTP: number = showTotals ? buyBonusRTP + jpRTP : buyBonusRTP;\n                if (!(jpRTP > 0 && !showTotals)) {\n                    html += `<br>${Core.translator\n                        .translate('PAYTABLE.RTP_BUY_BONUS')\n                        .replace(/##VALUE_BUY_BONUS##/g, calculatedBuyBonusRTP.toFixed(2) + '%')}`;\n                } else {\n                    html += `${Core.translator\n                        .translate('PAYTABLE.RTP_BUY_BONUS')\n                        .replace(/##VALUE_BUY_BONUS##/g, calculatedBuyBonusRTP.toFixed(2) + '%')}`;\n                }\n            }\n\n            if (doubleChanceRTP && !Core.flags.isActive(FeatureFlags.HIDE_DOUBLE_CHANCE)) {\n                doubleChanceRTP /= 100;\n                const calculatedDoubleChanceRTP: number = showTotals ? doubleChanceRTP + jpRTP : doubleChanceRTP;\n\n                const hasBuyBonusAbove = buyBonusRTP && !Core.flags.isActive(FeatureFlags.HIDE_BUY_BONUS);\n\n                if (hasBuyBonusAbove || !(jpRTP > 0 && !showTotals)) {\n                    html += `<br>${Core.translator\n                        .translate('PAYTABLE.RTP_DOUBLE_CHANCE')\n                        .replace(/##VALUE_DOUBLE_CHANCE##/g, calculatedDoubleChanceRTP.toFixed(2) + '%')}`;\n                } else {\n                    html += `${Core.translator\n                        .translate('PAYTABLE.RTP_DOUBLE_CHANCE')\n                        .replace(/##VALUE_DOUBLE_CHANCE##/g, calculatedDoubleChanceRTP.toFixed(2) + '%')}`;\n                }\n            }\n        }\n\n        if (modes && Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS)) {\n            const modesRTP = modes;\n            // const legacyModeKeys: Record<string, boolean> = {\n            //     BUY_BONUS: !!buyBonusRTP,\n            //     DOUBLE_CHANCE: !!doubleChanceRTP,\n            // };\n            const modeDisplayOrder = [\n                'BUY_1_WILD',\n                'BUY_1_WILD_LOCK_WIN',\n                'BUY_2_WILDS',\n                'BUY_2_WILDS_LOCK_WIN',\n                'BUY_3_WILDS_LOCK_WIN',\n                'SUPER_BUY_BONUS',\n                'BUY_BONUS',\n                'DOUBLE_CHANCE',\n                'BUY_1_SPECIAL_SYMBOL',\n            ];\n            const modeKeys = Object.keys(modesRTP);\n            const orderedModeKeys = [\n                ...modeDisplayOrder.filter((modeKey) => modeKeys.includes(modeKey)),\n                ...modeKeys.filter((modeKey) => !modeDisplayOrder.includes(modeKey)),\n            ];\n\n            let isFirstModeLine = jpRTP > 0 && !buyBonusRTP && !doubleChanceRTP;\n            orderedModeKeys.forEach((modeKey) => {\n                // if (legacyModeKeys[modeKey]) {\n                //     return;\n                // }\n\n                const exitConditionFlag =\n                    modeKey === 'DOUBLE_CHANCE' ? FeatureFlags.HIDE_DOUBLE_CHANCE : FeatureFlags.HIDE_BUY_BONUS;\n                if (Core.flags.isActive(exitConditionFlag)) return;\n\n                let modeRTP = modesRTP[modeKey];\n                const translationKey = 'PAYTABLE.RTP_MODE_' + modeKey;\n                if (!modeRTP || !Core.translator.hasTranslateFor(translationKey)) {\n                    return;\n                }\n                modeRTP /= 100;\n                const calculatedModeRTP: number = showTotals ? modeRTP + jpRTP : modeRTP;\n                if (isFirstModeLine && !showTotals) {\n                    html += `${Core.translator\n                        .translate(translationKey)\n                        .replace(/##VALUE##/g, calculatedModeRTP.toFixed(2) + '%')}`;\n                } else {\n                    html += `<br>${Core.translator\n                        .translate(translationKey)\n                        .replace(/##VALUE##/g, calculatedModeRTP.toFixed(2) + '%')}`;\n                }\n                isFirstModeLine = false;\n            });\n        }\n\n        if (jpRTP) {\n            html += `<br>${Core.translator\n                .translate('PAYTABLE.RTP_JACKPOT_CONTRIBUTION')\n                .replace(/##VALUE##/g, jpRTP.toFixed(digitsJP) + '%')}`;\n        }\n        return html;\n    }\n\n    private formatMaxWinLimit(): string {\n        let html =\n            this.gameInitSettings.limit === undefined\n                ? ''\n                : `\n        <div class=\"sectionContainer\">\n            <span class=\"sectionTitle\">\n                <span>${Core.translator.translate('PAYTABLE.MAX_WIN_LIMIT')}</span>\n            </span>\n            <img src=\"../assets/${this.gameKey}/paytable/images/lineLong.png\" class=\"titleLine\" />\n            <span class=\"sectionDescription\">\n                ${\n                    this.gameInitSettings.limit.jpExcluded\n                        ? Core.translator.translate('PAYTABLE.MAX_WIN_LIMIT_JP_EXCLUDEE_DESC')\n                        : Core.translator.translate('PAYTABLE.MAX_WIN_LIMIT_DESC')\n                }\n            </span>\n        </div>\n        `;\n        if (this.gameInitSettings.limit !== undefined) {\n            html = html.replace(\n                new RegExp('##MAX_WIN_LIMIT##', 'g'),\n                `<c>${this.formatMinMax(this.gameInitSettings.limit.amount)}</c>`,\n            );\n        }\n        return html;\n    }\n\n    private formatMoney(credits: number, moneyConfig, isScatter: boolean = false): string {\n        let formatted;\n        const moneyValues = new Money(credits * Core.SELECTED_DENOMINATION.value);\n\n        if (isScatter) {\n            if (this.slotConfiguration.gameType === GameTypes.JUMBO_WAYS_SLOT) {\n                moneyValues.amountMoney = credits * Core.SELECTED_DENOMINATION.value;\n            } else if (Core.hasComponent(SlotComponents.BUY_BONUS, BuyBonusModes.EXTENDED_MULTIPLE_BUY_BONUS)) {\n                moneyValues.amountMoney =\n                    credits *\n                    Core.SELECTED_DENOMINATION.value *\n                    this.gameInitSettings.getFactorByUniqueGameMode('NORMAL_MODE');\n            } else {\n                moneyValues.amountMoney = credits * Core.SELECTED_DENOMINATION.value * this.factor;\n            }\n        }\n\n        if (!moneyConfig.showCredits) {\n            formatted = moneyValues.stringMoney;\n        } else {\n            formatted = moneyValues.stringCredits;\n        }\n\n        if (!moneyConfig.showCredits && moneyConfig.showCurrency && moneyConfig.currency) {\n            formatted = moneyValues.htmlMoneyWithCurrency;\n        }\n\n        return formatted;\n    }\n\n    private onErrorShown(): void {\n        if (this.paytableHTMLDiv) {\n            this.paytableHTMLDiv.style.display = 'none';\n        }\n    }\n\n    private onErrorClosed(): void {\n        if (this.paytableHTMLDiv) {\n            this.paytableHTMLDiv.style.display = 'block';\n        }\n    }\n\n    private get factor(): number {\n        let factor: number;\n        if (this.rootStore.settings.factor) {\n            factor = this.rootStore.settings.factor;\n        } else {\n            factor = this.rootStore.uiStore.LINES.value;\n        }\n        return factor;\n    }\n\n    private generatePaytableContainer(): void {\n        this.config = {} as ITitledWindowConfig;\n        this.config.width = this.componentConfiguration.paytableViewProps.widthBounds;\n        this.config.height = this.componentConfiguration.paytableViewProps.heightBounds;\n\n        this.config.borderLeftUpTexture = Core.assets.getTextureFromSpriteSheet('miscellaneous', 'windowCornerLu.png');\n        this.config.title = Core.translator.translate('PAYTABLE');\n        this.config.titleStyle = this.componentConfiguration.tabNameProps.textStyle;\n        this.menuBody = new TitledWindow(this.config);\n        this.menuBody.x = 0;\n        this.menuBody.y = 0;\n        this.menuBody.interactive = true;\n        this.addChild(this.menuBody);\n    }\n    private setGameName(html: string): string {\n        const gameTitle = this.slotConfiguration.gameTitle\n            .replace(' G&K', ' Gods & Kings')\n            .replace(' JW', ' Jumboways')\n            .replace(' CH', ' Cash Heat')\n            .replace(' BL', ' Bell Link')\n            .replace(' HC', ' High Cash');\n        html = html.replace(/##GAME_NAME##/g, gameTitle);\n\n        return html;\n    }\n    private setBuyBonusBets(html: string): string {\n        if (this.gameInitSettings.haveGameMode('BUY_BONUS')) {\n            html = html.replace(\n                /##BUY_BONUS_BET_VALUE##/g,\n                (\n                    this.gameInitSettings.getFactorByUniqueGameMode('BUY_BONUS') /\n                    this.gameInitSettings.getFactorByUniqueGameMode('NORMAL_MODE')\n                ).toString(),\n            );\n        }\n        if (this.gameInitSettings.haveGameMode('SUPER_BUY_BONUS')) {\n            html = html.replace(\n                /##SUPER_BUY_BONUS_BET_VALUE##/g,\n                (\n                    this.gameInitSettings.getFactorByUniqueGameMode('SUPER_BUY_BONUS') /\n                    this.gameInitSettings.getFactorByUniqueGameMode('NORMAL_MODE')\n                ).toString(),\n            );\n        }\n        if (this.gameInitSettings.haveGameMode('MEGA_BUY_BONUS')) {\n            html = html.replace(\n                /##MEGA_BUY_BONUS_BET_VALUE##/g,\n                (\n                    this.gameInitSettings.getFactorByUniqueGameMode('MEGA_BUY_BONUS') /\n                    this.gameInitSettings.getFactorByUniqueGameMode('NORMAL_MODE')\n                ).toString(),\n            );\n        }\n        return html;\n    }\n\n    private setWildHuntBets(html: string): string {\n        if (this.gameInitSettings.haveGameMode('BUY_3_WILDS_LOCK_WIN')) {\n            html = html.replace(\n                /##BUY_WILDS_VALUE_0##/g,\n                (\n                    this.gameInitSettings.getFactorByUniqueGameMode('BUY_3_WILDS_LOCK_WIN') /\n                    this.gameInitSettings.getFactorByUniqueGameMode('NORMAL_MODE')\n                ).toString(),\n            );\n        }\n        if (this.gameInitSettings.haveGameMode('BUY_2_WILDS')) {\n            html = html.replace(\n                /##BUY_WILDS_VALUE_1##/g,\n                (\n                    this.gameInitSettings.getFactorByUniqueGameMode('BUY_2_WILDS') /\n                    this.gameInitSettings.getFactorByUniqueGameMode('NORMAL_MODE')\n                ).toString(),\n            );\n        }\n        if (this.gameInitSettings.haveGameMode('BUY_2_WILDS_LOCK_WIN')) {\n            html = html.replace(\n                /##BUY_WILDS_VALUE_2##/g,\n                (\n                    this.gameInitSettings.getFactorByUniqueGameMode('BUY_2_WILDS_LOCK_WIN') /\n                    this.gameInitSettings.getFactorByUniqueGameMode('NORMAL_MODE')\n                ).toString(),\n            );\n        }\n        if (this.gameInitSettings.haveGameMode('BUY_1_WILD')) {\n            html = html.replace(\n                /##BUY_WILDS_VALUE_3##/g,\n                (\n                    this.gameInitSettings.getFactorByUniqueGameMode('BUY_1_WILD') /\n                    this.gameInitSettings.getFactorByUniqueGameMode('NORMAL_MODE')\n                ).toString(),\n            );\n        }\n        if (this.gameInitSettings.haveGameMode('BUY_1_WILD_LOCK_WIN')) {\n            html = html.replace(\n                /##BUY_WILDS_VALUE_4##/g,\n                (\n                    this.gameInitSettings.getFactorByUniqueGameMode('BUY_1_WILD_LOCK_WIN') /\n                    this.gameInitSettings.getFactorByUniqueGameMode('NORMAL_MODE')\n                ).toString(),\n            );\n        }\n        if (this.gameInitSettings.haveGameMode('BUY_1_WILD_LOCK_WIN')) {\n            html = html.replace(\n                /##BUY_WILDS_VALUE_4##/g,\n                (\n                    this.gameInitSettings.getFactorByUniqueGameMode('BUY_1_WILD_LOCK_WIN') /\n                    this.gameInitSettings.getFactorByUniqueGameMode('NORMAL_MODE')\n                ).toString(),\n            );\n        }\n\n        return html;\n    }\n}\n","import Core from '@egt/core';\nimport { Features, InitialSettings } from '@egt/slot';\nimport { injectable } from 'tsyringe';\n\n@injectable()\nexport default class PaytableScript {\n    public gambleXTwoImage(): string {\n        return '<img src=\"../assets/features/slot/gamble/paytable/images/x2.png\"/>';\n    }\n    /**\n     *\n     * @returns\n     *  This is a map of image placeholders to their corresponding images. For usage in translation files. To avoid hardcoding images paths.\n     *  Ex: <<IMG.SCATTER>> in the en.json file will be replaced with \"<img class='scatterOrMultiplier' src='../assets/##GAME_KEY##/paytable/images/scatter.png'/>\"\n     */\n    public imageMap(): Record<string, string> {\n        return {\n            // 'IMG.SCATTER': \"<img class='scatterOrMultiplier' src='../assets/##GAME_KEY##/paytable/images/scatter.png'/>\",\n            // 'IMG.SCATTER_SMALL': \"<img class='scatterOrMultiplier' src='../assets/##GAME_KEY##/paytable/images/scatterSmall.png'/>\",\n        };\n    }\n    protected checkForCountrySpecificKeys(): string {\n        let translation = '';\n\n        if (Core.hasFeature(Features.MYSTERY_JACKPOT)) {\n            const settings: InitialSettings = Core.gameDependencyContainer.resolve('InitialSettings');\n\n            switch (settings?.country) {\n                case 'Sweden':\n                    translation =\n                        '<div class=\"mystery-propability\"><span>#{MYSTERY.PROBABILITIES_OF_WINNING}#</span></div>';\n                    break;\n                default:\n                    break;\n            }\n        }\n\n        return translation;\n    }\n}\n","import Core, { IOrientation, MoneyFormatter } from '@egt/core';\nimport { FeatureController, InitialSettings, RootStore } from '@egt/slot';\nimport {\n    Button,\n    ButtonStates,\n    IInputFieldObject,\n    InputField,\n    IViewVisibilityContainer,\n    MoneyText,\n    MoneyTextConfig,\n    KeyboardNumeric,\n    KeyboardActionButtonNumeric,\n    KeyboardButtonNumeric,\n    SteppedSlider,\n    Text,\n    TextConfig,\n    ViewContainer,\n    ViewVisibilityContainer,\n} from '@egt/ui-lib';\nimport { Container, Sprite, TextStyle, Texture, Text as PixiText, Graphics } from 'pixi.js';\nimport { merge } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { ISettingsPopupComponentConfiguration } from '../../interfaces/SettingsInterfaces';\nimport SettingsPopup from '../../views/SettingsPopup';\nimport { MandatoryValuesNumeric } from '@egt/autoplay-popup';\n\nimport gsap from 'gsap';\n\nconst enum InputFieldsConfigKeys {\n    MAX_LOSS = 'maxLossAmountContainerConfig',\n    BALANCE_LESS = 'balanceLessThanContainerConfig',\n    BALANCE_MORE = 'balanceMoreThanContainerConfig',\n    WIN_OVER = 'winOverContainerConfig',\n}\n\n@injectable()\nexport default class SpinSettingsNumericInputView extends ViewVisibilityContainer implements IViewVisibilityContainer {\n    // ==============================\n    // STOP ON TEXT\n    // ==============================\n    protected stopOnText: Text;\n    protected stopOnStyle: TextStyle;\n    protected stopOnConfig: TextConfig = new TextConfig();\n\n    // ==============================\n    // INPUT FIELDS\n    // ==============================\n    private activeInputField: InputField | null = null;\n    public indputFieldsContainer: Container;\n    public inputFields: InputField[] = [];\n    private underTitleTexts: Map<InputField, PixiText> = new Map();\n\n    private maxLossAmountFieldContainer: ViewContainer;\n    private maxLossAmountField: InputField;\n    private maxLossUnderTitle: PixiText;\n\n    private balanceLessThanFieldContainer: ViewContainer;\n    private balanceLessThanField: InputField;\n    private balanceLessUnderTitle: PixiText;\n\n    private balanceMoreThanFieldContainer: ViewContainer;\n    private balanceMoreThanField: InputField;\n    private balanceMoreUnderTitle: PixiText;\n\n    private winOverFieldContainer: ViewContainer;\n    private winOverField: InputField;\n    private winOverUnderTitle: PixiText;\n    private minBet = 0;\n    // ==============================\n    // SPINS SLIDER\n    // ==============================\n    protected spinsSliderContainer: ViewContainer;\n    protected sliderContainerWidth: number;\n    protected sliderContainerHeight: number;\n\n    protected spinsSlider: SteppedSlider;\n    protected spinSliderInitialWidth: number;\n    protected sliderWidth: number;\n    protected sliderHeight: number;\n    protected sliderTopOffset: number;\n\n    protected numberOfSpinsText: Text;\n    protected numberOfSpinsValue: Text;\n    protected numberOfSpinsValues: number[];\n    protected infinityValueTexture: Sprite;\n    protected spinsConfig: TextConfig = new TextConfig();\n    protected spinsStyle: TextStyle;\n    protected spinsValueConfig: TextConfig = new TextConfig();\n    protected spinsValueStyle: TextStyle;\n    protected colorValues: number;\n    // ==============================\n    // START BUTTON\n    // ==============================\n    protected startAutoplayButton: Button;\n    protected startButtonText: Text;\n    protected startButtonTextConfig: TextConfig = new TextConfig();\n    protected startButtonTextStyle: TextStyle;\n    // ==============================\n    // BALANCE FIELD\n    // ==============================\n    protected balanceContainer: ViewContainer;\n    protected balanceText: Text;\n    protected balanceValue: MoneyText;\n    protected balanceTextConfig: TextConfig = new TextConfig();\n    protected balanceTextStyle: TextStyle;\n    protected balanceValueConfig: MoneyTextConfig = new MoneyTextConfig();\n    protected balanceValueStyle: TextStyle;\n    // ==============================\n    // BET FIELD\n    // ==============================\n    protected betContainer: ViewContainer;\n    protected betContent: ViewContainer;\n    protected betText: Text;\n    protected betValue: MoneyText;\n    protected betTextConfig: TextConfig = new TextConfig();\n    protected betTextStyle: TextStyle;\n    protected betValueConfig: MoneyTextConfig = new MoneyTextConfig();\n    protected betValueStyle: TextStyle;\n    // ==============================\n    // GENERAL CONFIG\n    // ==============================\n    protected autoSpinsSelected: number = 0;\n    private mandatory: MandatoryValuesNumeric[];\n\n    private maxLoss: number;\n    public balanceLess: number;\n    public balanceMore: number;\n    public winOver: number;\n    // ==============================\n    // KEYBOARD\n    // ==============================\n    private numericKeyboard: KeyboardNumeric;\n    private currentField: InputField;\n    private numericKeyboardTween: gsap.core.Timeline;\n    private isKeyboardVisible: boolean = false;\n    private startingPoint: number = 250;\n    private settingsMenuCover: Graphics;\n    // ==============================\n    // Utils\n    // ==============================\n    public shouldSetUiStoreFieldValues = true;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('FeatureController') protected feature: FeatureController,\n        @inject('SettingsPopupComponentConfiguration')\n        protected componentConfiguration: ISettingsPopupComponentConfiguration,\n    ) {\n        super();\n        this.init();\n        this.setOrientation(Core.ORIENTATION.value);\n    }\n\n    public init(): void {\n        if (!this.settings.autoplay) {\n            return;\n        }\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/slot-components/settings-popup/src/egt/settings-views/spin/SpinSettingsNumericInputView.ts:160:9\",(Core.stage.stage),\"pointertap\"]), Core.stage.stage.on('pointertap', this.onPopUpClick, this));\n        this.interactive = true;\n\n        this.mandatory = this.settings.autoplayRestrictions.mandatory;\n        this.initSizesAndStyles();\n        this.initStopOnText();\n        this.initInputFields();\n        this.initSpinsSlider();\n        this.initStartButton();\n        this.initBalanceField();\n        this.initBetField();\n        this.initSettingsMenuCover();\n        this.resetInputFields();\n        this.setEventListeners();\n        this.setOrientation(Core.ORIENTATION.value);\n        this.show = false;\n\n        this.rootStore.subjects.RESET_AUTOPLAY_RESTRICTIONS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.resetAutoPlayRestrictions.bind(this),\n        );\n        this.rootStore.uiStore.SELECTED_SETTINGS_TAB.pipe(takeUntil(this.DESTROY)).subscribe(this.selectTab.bind(this));\n    }\n\n    // ==============================\n    // INIT\n    // ==============================\n\n    protected initSizesAndStyles(): void {\n        this.stopOnStyle = this.componentConfiguration.autoplayViewProps.stopOnStyle;\n        this.sliderContainerWidth = this.componentConfiguration.autoplayViewProps.sliderContainerWidth;\n        this.sliderContainerHeight = this.componentConfiguration.autoplayViewProps.sliderContainerHeight;\n        this.sliderWidth = this.componentConfiguration.autoplayViewProps.sliderWidth;\n        this.sliderHeight = this.componentConfiguration.autoplayViewProps.sliderHeight;\n        this.sliderTopOffset = this.componentConfiguration.autoplayViewProps.sliderTopOffset;\n        this.colorValues = this.componentConfiguration.autoplayViewProps.slidersValuesColor;\n        this.spinsStyle = this.componentConfiguration.autoplayViewProps.spinsStyle;\n        this.spinsValueStyle = this.componentConfiguration.autoplayViewProps.spinsValueStyle;\n        this.startButtonTextStyle = this.componentConfiguration.autoplayViewProps.startButtonTextStyle;\n        this.balanceTextStyle = this.componentConfiguration.autoplayViewProps.balanceTextStyle;\n        this.betTextStyle = this.componentConfiguration.autoplayViewProps.betTextStyle;\n        this.betValueStyle = this.componentConfiguration.autoplayViewProps.betValueStyle;\n        this.balanceValueStyle = this.componentConfiguration.autoplayViewProps.balanceValueStyle;\n        this.numberOfSpinsValues = this.settings.autoplayRestrictions.autoPlays;\n    }\n\n    protected onPopUpClick(e): void {\n        if (!this.visible) {\n            return;\n        }\n        if (\n            !(\n                e.target.parent instanceof InputField ||\n                e.target.parent instanceof KeyboardButtonNumeric ||\n                (e.target.parent?.parent instanceof KeyboardNumeric && e.target.name !== 'shadowBackground') ||\n                e.target.parent instanceof KeyboardActionButtonNumeric\n            )\n        ) {\n            this.selectTab();\n            if (this.numericKeyboard && this.numericKeyboard.visible) {\n                this.hideNumericKeyboardField(true);\n            }\n        }\n    }\n\n    protected selectTab(): void {\n        for (const inputField of this.inputFields) {\n            inputField.setInactive();\n        }\n    }\n\n    protected initStopOnText(): void {\n        this.stopOnText = new Text(this.stopOnConfig, Core.translator.translate('STOP ON'), this.stopOnStyle);\n        const bounds = this.stopOnText.getLocalBounds();\n        this.stopOnText.pivot.set(bounds.x, bounds.y);\n        this.addChild(this.stopOnText);\n    }\n\n    protected initInputFields(): void {\n        // FIELDS MAIN CONTAINER\n        this.indputFieldsContainer = new Container();\n        this.indputFieldsContainer.pivot.set(0, 0);\n        this.addChild(this.indputFieldsContainer);\n\n        // MAX LOSS FIELD\n        this.maxLossAmountFieldContainer = new ViewContainer();\n        this.maxLossAmountFieldContainer.pivot.set(0, 0);\n        this.maxLossAmountField = this.createInputField(\n            this.maxLossAmountFieldContainer,\n            InputFieldsConfigKeys.MAX_LOSS,\n        );\n\n        this.maxLossAmountField.INPUT.pipe(takeUntil(this.DESTROY)).subscribe((value: string) => {\n            this.maxLoss = Number(value);\n            if (this.shouldSetUiStoreFieldValues) {\n                this.rootStore.uiStore.maxTotalLossLimit = this.maxLoss * 100;\n            }\n            this.checkForMandatory();\n        });\n\n        this.maxLossAmountField.ERROR.subscribe((isError) => {\n            if (!this.maxLossUnderTitle) return;\n            this.maxLossUnderTitle.style = isError\n                ? new TextStyle({ ...this.maxLossUnderTitle.style, fill: '#FF0000' })\n                : this.componentConfiguration.autoplayNumericInputsViewProps.maxLossAmountContainerConfig.get(\n                      'underTitleTextStyle',\n                  );\n            this.checkForMandatory();\n        });\n\n        this.maxLossAmountField.setMaxValue(this.rootStore.uiStore.BALANCE.value);\n\n        // BALANCE LESS FIELD\n        this.balanceLessThanFieldContainer = new ViewContainer();\n        this.balanceLessThanFieldContainer.pivot.set(0, 0);\n        this.balanceLessThanField = this.createInputField(\n            this.balanceLessThanFieldContainer,\n            InputFieldsConfigKeys.BALANCE_LESS,\n        );\n\n        this.balanceLessThanField.INPUT.pipe(takeUntil(this.DESTROY)).subscribe((value: string) => {\n            this.balanceLess = Number(value);\n            if (this.shouldSetUiStoreFieldValues) {\n                this.rootStore.uiStore.balanceDecreaseValue = this.balanceLess * 100;\n            }\n            this.checkForMandatory();\n        });\n\n        this.balanceLessThanField.ERROR.subscribe((isError) => {\n            if (!this.balanceLessUnderTitle) return;\n            this.balanceLessUnderTitle.style = isError\n                ? new TextStyle({ ...this.balanceLessUnderTitle.style, fill: '#FF0000' })\n                : this.componentConfiguration.autoplayNumericInputsViewProps.balanceLessThanContainerConfig.get(\n                      'underTitleTextStyle',\n                  );\n            this.checkForMandatory();\n        });\n\n        this.balanceLessThanField.setMaxValue(this.getLessBalance());\n\n        // BALANCE MORE FIELD\n        this.balanceMoreThanFieldContainer = new ViewContainer();\n        this.balanceMoreThanFieldContainer.pivot.set(0, 0);\n        this.balanceMoreThanField = this.createInputField(\n            this.balanceMoreThanFieldContainer,\n            InputFieldsConfigKeys.BALANCE_MORE,\n        );\n\n        this.balanceMoreThanField.INPUT.pipe(takeUntil(this.DESTROY)).subscribe((value: string) => {\n            this.balanceMore = Number(value);\n            if (this.shouldSetUiStoreFieldValues) {\n                this.rootStore.uiStore.balanceIncreaseValue = this.balanceMore * 100;\n            }\n            this.checkForMandatory();\n        });\n\n        this.balanceMoreThanField.ERROR.subscribe((isError) => {\n            if (!this.balanceMoreUnderTitle) return;\n            this.balanceMoreUnderTitle.style = isError\n                ? new TextStyle({ ...this.balanceMoreUnderTitle.style, fill: '#FF0000' })\n                : this.componentConfiguration.autoplayNumericInputsViewProps.balanceMoreThanContainerConfig.get(\n                      'underTitleTextStyle',\n                  );\n            this.checkForMandatory();\n        });\n\n        this.balanceMoreThanField.setMaxValue(this.getMoreBalance());\n\n        // BALANCE WIN OVER\n        this.winOverFieldContainer = new ViewContainer();\n        this.winOverFieldContainer.pivot.set(0, 0);\n        this.winOverField = this.createInputField(this.winOverFieldContainer, InputFieldsConfigKeys.WIN_OVER);\n\n        this.winOverField.INPUT.pipe(takeUntil(this.DESTROY)).subscribe((value: string) => {\n            this.winOver = Number(value);\n            if (this.shouldSetUiStoreFieldValues) {\n                this.rootStore.uiStore.winLimitValue = this.winOver * 100;\n            }\n            this.checkForMandatory();\n        });\n\n        this.winOverField.ERROR.subscribe((isError) => {\n            if (!this.winOverUnderTitle) return;\n            this.winOverUnderTitle.style = isError\n                ? new TextStyle({ ...this.winOverUnderTitle.style, fill: '#FF0000' })\n                : this.componentConfiguration.autoplayNumericInputsViewProps.winOverContainerConfig.get(\n                      'underTitleTextStyle',\n                  );\n            this.checkForMandatory();\n        });\n\n        this.winOverField.setMaxValue(this.getWinOver());\n\n        // TITELS AND TEXTS\n        this.crateInputsTexts();\n        this.underTitleTexts.set(this.maxLossAmountField, this.maxLossUnderTitle);\n        this.underTitleTexts.set(this.balanceLessThanField, this.balanceLessUnderTitle);\n        this.underTitleTexts.set(this.balanceMoreThanField, this.balanceMoreUnderTitle);\n        this.underTitleTexts.set(this.winOverField, this.winOverUnderTitle);\n    }\n\n    private createInputField(container: Container, configKey: string): InputField {\n        this.indputFieldsContainer.addChild(container);\n        const config = this.componentConfiguration.autoplayNumericInputsViewProps[configKey] as IInputFieldObject;\n        const inputField = new InputField({\n            containerX: config.containerX,\n            containerY: config.containerY,\n            fieldX: config.fieldX,\n            fieldY: config.fieldY,\n            fieldWidth: config.fieldWidth,\n            fieldHeight: config.fieldHeight,\n            fieldNormalTextStyle: config.fieldNormalTextStyle,\n            fieldHilightedTextStyle: config.fieldHilightedTextStyle,\n            currencyHilightedTextStyle: config.currencyHilightedTextStyle,\n            currencyNormaTextStyle: config.currencyNormaTextStyle,\n            normalTexture: Core.assets.getTextureFromSpriteSheet('numericInput', 'inputNormal.png'),\n            hilightedTexture: Core.assets.getTextureFromSpriteSheet('numericInput', 'inputSelected.png'),\n            inputErrorTexture: Core.assets.getTextureFromSpriteSheet('numericInput', 'inputError.png'),\n            currency: this.rootStore.settings.currency,\n        });\n        container.addChild(inputField);\n\n        this.inputFields.push(inputField);\n\n        return inputField;\n    }\n\n    private crateInputsTexts(): void {\n        const currency = this.rootStore.settings.currency;\n        // MAX LOSS\n        this.createInputTitle(\n            this.maxLossAmountFieldContainer,\n            new PixiText(),\n            this.toSentenceCase(Core.translator.translate('MAX LOSS')),\n            this.componentConfiguration.autoplayNumericInputsViewProps.maxLossAmountContainerConfig.get(\n                'titleTextStyle',\n            ),\n            this.componentConfiguration.autoplayNumericInputsViewProps.maxLossAmountContainerConfig.get('titleX'),\n            this.componentConfiguration.autoplayNumericInputsViewProps.maxLossAmountContainerConfig.get('titleY'),\n            MandatoryValuesNumeric.MAX_LOSS,\n        );\n        this.maxLossUnderTitle = this.createUnderTitleText(\n            this.maxLossAmountFieldContainer,\n            this.getRangeText(this.minBet, this.rootStore.uiStore.BALANCE.value, currency),\n            this.componentConfiguration.autoplayNumericInputsViewProps.maxLossAmountContainerConfig.get(\n                'underTitleTextStyle',\n            ),\n            this.componentConfiguration.autoplayNumericInputsViewProps.maxLossAmountContainerConfig.get('underTitleX'),\n            this.componentConfiguration.autoplayNumericInputsViewProps.maxLossAmountContainerConfig.get('underTitleY'),\n        );\n\n        // BALANCE LESS THAN\n        this.createInputTitle(\n            this.balanceLessThanFieldContainer,\n            new PixiText(),\n            this.toSentenceCase(Core.translator.translate('LOSS LIMIT')),\n            this.componentConfiguration.autoplayNumericInputsViewProps.balanceLessThanContainerConfig.get(\n                'titleTextStyle',\n            ),\n            this.componentConfiguration.autoplayNumericInputsViewProps.balanceLessThanContainerConfig.get('titleX'),\n            this.componentConfiguration.autoplayNumericInputsViewProps.balanceLessThanContainerConfig.get('titleY'),\n            MandatoryValuesNumeric.BALANCE_LES,\n        );\n        this.balanceLessUnderTitle = this.createUnderTitleText(\n            this.balanceLessThanFieldContainer,\n            this.getRangeText(this.minBet, this.getLessBalance(), currency),\n            this.componentConfiguration.autoplayNumericInputsViewProps.balanceLessThanContainerConfig.get(\n                'underTitleTextStyle',\n            ),\n            this.componentConfiguration.autoplayNumericInputsViewProps.balanceLessThanContainerConfig.get(\n                'underTitleX',\n            ),\n            this.componentConfiguration.autoplayNumericInputsViewProps.balanceLessThanContainerConfig.get(\n                'underTitleY',\n            ),\n        );\n\n        // BALANCE MORE THAN\n        this.createInputTitle(\n            this.balanceMoreThanFieldContainer,\n            new PixiText(),\n            this.toSentenceCase(Core.translator.translate('WINS LIMIT')),\n            this.componentConfiguration.autoplayNumericInputsViewProps.balanceMoreThanContainerConfig.get(\n                'titleTextStyle',\n            ),\n            this.componentConfiguration.autoplayNumericInputsViewProps.balanceMoreThanContainerConfig.get('titleX'),\n            this.componentConfiguration.autoplayNumericInputsViewProps.balanceMoreThanContainerConfig.get('titleY'),\n            MandatoryValuesNumeric.BALANCE_MORE,\n        );\n        this.balanceMoreUnderTitle = this.createUnderTitleText(\n            this.balanceMoreThanFieldContainer,\n            this.getRangeText(this.minBet, this.getMoreBalance(), currency),\n            this.componentConfiguration.autoplayNumericInputsViewProps.balanceMoreThanContainerConfig.get(\n                'underTitleTextStyle',\n            ),\n            this.componentConfiguration.autoplayNumericInputsViewProps.balanceMoreThanContainerConfig.get(\n                'underTitleX',\n            ),\n            this.componentConfiguration.autoplayNumericInputsViewProps.balanceMoreThanContainerConfig.get(\n                'underTitleY',\n            ),\n        );\n\n        // WIN OVER\n        this.createInputTitle(\n            this.winOverFieldContainer,\n            new PixiText(),\n            this.toSentenceCase(Core.translator.translate('STOP ON WIN')),\n            this.componentConfiguration.autoplayNumericInputsViewProps.winOverContainerConfig.get('titleTextStyle'),\n            this.componentConfiguration.autoplayNumericInputsViewProps.winOverContainerConfig.get('titleX'),\n            this.componentConfiguration.autoplayNumericInputsViewProps.winOverContainerConfig.get('titleY'),\n            MandatoryValuesNumeric.WIN_OVER,\n        );\n        this.winOverUnderTitle = this.createUnderTitleText(\n            this.winOverFieldContainer,\n            this.getRangeText(this.minBet, this.getWinOver(), currency),\n            this.componentConfiguration.autoplayNumericInputsViewProps.winOverContainerConfig.get(\n                'underTitleTextStyle',\n            ),\n            this.componentConfiguration.autoplayNumericInputsViewProps.winOverContainerConfig.get('underTitleX'),\n            this.componentConfiguration.autoplayNumericInputsViewProps.winOverContainerConfig.get('underTitleY'),\n        );\n    }\n\n    private createInputTitle(\n        container: ViewContainer,\n        title: PixiText,\n        titleTextKey: string,\n        titleStyle: TextStyle,\n        titleX: number,\n        titleY: number,\n        mandatoryKey: string,\n    ): void {\n        this.setTextProps(\n            title,\n            this.toSentenceCase(Core.translator.translate(titleTextKey)),\n            titleStyle,\n            { x: 0, y: 0 },\n            titleX,\n            titleY,\n        );\n        const mandatorySign = new PixiText(\n            '*',\n            this.componentConfiguration.autoplayNumericInputsViewProps.mandatorySignStyle,\n        );\n        mandatorySign.x =\n            title.width + this.componentConfiguration.autoplayNumericInputsViewProps.mandatorySignPosition.get('x');\n        mandatorySign.y = this.componentConfiguration.autoplayNumericInputsViewProps.mandatorySignPosition.get('y');\n\n        title.addChild(mandatorySign);\n\n        if (this.settings.autoplayRestrictions.mandatory.indexOf(mandatoryKey) === -1) {\n            mandatorySign.visible = false;\n        }\n\n        container.addChild(title);\n    }\n\n    private createUnderTitleText(\n        container: ViewContainer,\n        textValue: string,\n        style: TextStyle,\n        x: number,\n        y: number,\n    ): PixiText {\n        const underTitle = new PixiText(textValue, style);\n        underTitle.anchor.set(0, 1);\n        underTitle.x = x;\n        underTitle.y = container.height + y;\n        container.addChild(underTitle);\n        return underTitle;\n    }\n\n    private setTextProps(\n        text: PixiText,\n        textValue: string,\n        style: TextStyle,\n        anchor: { x: number; y: number },\n        x: number,\n        y: number,\n    ): void {\n        text.text = textValue;\n        text.style = style;\n        text.resolution = 2;\n        text.anchor.set(anchor.x, anchor.y);\n        text.x = x;\n        text.y = y;\n    }\n\n    private getRangeText(min: number, max: number, currency: string): string {\n        const minStr = new MoneyFormatter(min).stringMoney;\n        const maxStr = new MoneyFormatter(max).stringMoney;\n        return `min. ${minStr} - max. ${maxStr} ${currency}`;\n    }\n\n    private toSentenceCase(str: string): string {\n        return str.charAt(0).toUpperCase() + str.substring(1).toLowerCase();\n    }\n\n    protected initSpinsSlider(): void {\n        // --- Texts and Value\n        this.numberOfSpinsText = new Text(\n            this.spinsConfig,\n            Core.translator.translate('NUMBER OF SPINS'),\n            this.spinsStyle,\n        );\n        const noLimitText = Core.translator.translate('NO LIMIT');\n        if (this.numberOfSpinsValues.indexOf(0) !== -1) {\n            this.numberOfSpinsValue = new Text(this.spinsValueConfig, noLimitText, this.spinsValueStyle);\n        } else {\n            this.numberOfSpinsValue = new Text(\n                this.spinsValueConfig,\n                this.numberOfSpinsValues[0].toString(),\n                this.spinsValueStyle,\n            );\n        }\n        this.addChild(this.numberOfSpinsText);\n        this.addChild(this.numberOfSpinsValue);\n\n        // --- Infinity Texture\n        this.infinityValueTexture = new Sprite();\n        this.infinityValueTexture.texture = Core.assets.getAsset(\n            this.componentConfiguration.autoplayViewProps.infinityValueTexture,\n        ).texture;\n        this.infinityValueTexture.tint = this.colorValues;\n        this.infinityValueTexture.visible = false;\n\n        // --- Slider\n        let inactiveDotTexture;\n        let activeDotTexture;\n        if (this.componentConfiguration.autoplayViewProps.useTexturesForDots) {\n            inactiveDotTexture = Core.assets.getAsset(\n                this.componentConfiguration.autoplayViewProps.inactiveDotTexture,\n            ).texture;\n            activeDotTexture = Core.assets.getAsset(\n                this.componentConfiguration.autoplayViewProps.activeDotTexture,\n            ).texture;\n        }\n\n        let sliderNotSelectedTexture;\n        let sliderSelectedTexture;\n        if (this.componentConfiguration.autoplayViewProps.useCanvasForSliders) {\n            const canvas = document.createElement('canvas');\n            canvas.height = this.sliderHeight;\n            canvas.width = this.sliderWidth;\n            const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;\n            const inactiveGradient = ctx.createLinearGradient(0, 0, 0, this.sliderHeight);\n            for (let i = 0; i < this.componentConfiguration.autoplayViewProps.canvasSlidersNumberOfStops; i++) {\n                inactiveGradient.addColorStop(\n                    this.componentConfiguration.autoplayViewProps.canvasNotSelectedSliderStops[i],\n                    this.componentConfiguration.autoplayViewProps.canvasNotSelectedSlidersColors[i],\n                );\n            }\n            ctx.fillStyle = inactiveGradient;\n            ctx.fillRect(0, 0, this.sliderWidth, this.sliderHeight);\n            sliderNotSelectedTexture = Texture.from(canvas);\n            canvas.remove();\n\n            const canvas2 = document.createElement('canvas');\n            canvas2.height = this.sliderHeight;\n            canvas2.width = this.sliderWidth;\n            const ctx2 = canvas2.getContext('2d') as CanvasRenderingContext2D;\n            const activeGradient = ctx2.createLinearGradient(0, 0, 0, this.sliderHeight);\n            for (let i = 0; i < this.componentConfiguration.autoplayViewProps.canvasSlidersNumberOfStops; i++) {\n                activeGradient.addColorStop(\n                    this.componentConfiguration.autoplayViewProps.canvasSelectedSliderStops[i],\n                    this.componentConfiguration.autoplayViewProps.canvasSelectedSlidersColors[i],\n                );\n            }\n            ctx2.fillStyle = activeGradient;\n            ctx2.fillRect(0, 0, this.sliderWidth, this.sliderHeight);\n            sliderSelectedTexture = Texture.from(canvas2);\n            canvas2.remove();\n        }\n\n        this.spinsSliderContainer = new ViewContainer();\n        this.spinsSlider = new SteppedSlider({\n            sliderWidth: this.sliderWidth,\n            sliderHeight: this.sliderHeight,\n            minValue: this.numberOfSpinsValues[0],\n            stepsNotSelectedTexture: sliderNotSelectedTexture,\n            stepsSelectedTexture: sliderSelectedTexture,\n            inactiveHandleTexture: Core.assets.getAsset(\n                this.componentConfiguration.autoplayViewProps.inactiveHandleTexture[0],\n            ).texture,\n            activeHandleTexture: Core.assets.getAsset(this.componentConfiguration.autoplayViewProps.activeHandleTexture)\n                .texture,\n            inactiveDotTexture,\n            activeDotTexture,\n            steps: this.numberOfSpinsValues,\n            notSelectedFill: this.componentConfiguration.autoplayViewProps.slidersNotSelectedColor,\n            selectedFill: this.componentConfiguration.autoplayViewProps.slidersSelectedColor,\n            handleDimensions: this.componentConfiguration.autoplayNumericInputsViewProps.sliderHandleDimensions,\n        });\n\n        this.spinsSlider.CHANGE.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            if (this.spinsSlider.CHANGE.value === -1) {\n                this.numberOfSpinsValue.visible = false;\n                this.infinityValueTexture.visible = true;\n            } else {\n                this.numberOfSpinsValue.visible = true;\n                this.infinityValueTexture.visible = false;\n                this.numberOfSpinsValue.text =\n                    this.spinsSlider.CHANGE.value > 0 ? this.spinsSlider.CHANGE.value.toString() : noLimitText;\n                const bounds = this.numberOfSpinsValue.getLocalBounds();\n                this.numberOfSpinsValue.x = this.spinSliderInitialWidth - (bounds.x + bounds.width);\n                this.numberOfSpinsValue.y = -bounds.y;\n            }\n            this.makeSpinsSelection(this.spinsSlider.CHANGE.value);\n        });\n\n        this.spinsSlider.init();\n        this.spinSliderInitialWidth = this.spinsSlider.width;\n\n        this.spinsSliderContainer.addChild(this.spinsSlider);\n        this.spinsSliderContainer.addChild(this.numberOfSpinsText);\n        this.spinsSliderContainer.addChild(this.numberOfSpinsValue);\n        this.spinsSliderContainer.addChild(this.infinityValueTexture);\n        this.addChild(this.spinsSliderContainer);\n        //POSITIONING\n        const sliderBounds = this.spinsSlider.getLocalBounds();\n        this.spinsSlider.x = Math.abs(sliderBounds.x);\n        this.spinsSlider.y =\n            Math.abs(sliderBounds.y) +\n            this.numberOfSpinsText.height +\n            this.componentConfiguration.autoplayNumericInputsViewProps.spinSliderTopOffset;\n        this.numberOfSpinsValue.x = this.spinsSlider.width - this.numberOfSpinsValue.width;\n        this.infinityValueTexture.x = this.spinsSlider.width - this.infinityValueTexture.width;\n    }\n\n    protected initStartButton(): void {\n        this.startAutoplayButton = new Button([\n            Core.assets.getAsset(\n                this.componentConfiguration.autoplayViewProps.startAutoplayButtonTextures[ButtonStates.Normal],\n            ).texture,\n            Core.assets.getAsset(\n                this.componentConfiguration.autoplayViewProps.startAutoplayButtonTextures[ButtonStates.Pressed],\n            ).texture,\n            Core.assets.getAsset(\n                this.componentConfiguration.autoplayViewProps.startAutoplayButtonTextures[ButtonStates.Normal],\n            ).texture,\n            Core.assets.getAsset(\n                this.componentConfiguration.autoplayViewProps.startAutoplayButtonTextures[ButtonStates.Disabled],\n            ).texture,\n        ]);\n\n        this.setTextsConfigs();\n        this.startButtonText = new Text(\n            this.startButtonTextConfig,\n            Core.translator.translate('START AUTOPLAY'),\n            this.startButtonTextStyle,\n        );\n        this.startAutoplayButton.addChild(this.startButtonText);\n        this.addChild(this.startAutoplayButton);\n\n        this.setStartButtonOrientation();\n    }\n\n    protected initBalanceField(): void {\n        this.balanceContainer = new ViewContainer();\n        this.balanceText = new Text(\n            this.balanceTextConfig,\n            Core.translator.translate('BALANCE') + ':',\n            this.balanceTextStyle,\n        );\n        this.balanceValue = new MoneyText(\n            this.balanceValueConfig,\n            this.rootStore.uiStore.BALANCE.value,\n            this.balanceValueStyle,\n        );\n        this.balanceContainer.addChild(this.balanceText);\n        this.balanceContainer.addChild(this.balanceValue);\n        this.addChild(this.balanceContainer);\n    }\n\n    protected initBetField(): void {\n        this.betContainer = new ViewContainer();\n        this.betContent = new ViewContainer();\n        this.betText = new Text(this.betTextConfig, Core.translator.translate('BET') + ':', this.betTextStyle);\n        this.betValue = new MoneyText(this.betValueConfig, this.getTotalBet(), this.betValueStyle);\n        this.betContent.addChild(this.betText);\n        this.betContent.addChild(this.betValue);\n        this.betContainer.addChild(this.betContent);\n        this.addChild(this.betContainer);\n    }\n\n    protected initSettingsMenuCover(): void {\n        if (Core.isDesktopMode) {\n            return;\n        }\n        const coverWidth = this.componentConfiguration.autoplayNumericInputsViewProps.settingsMenuCover.get('width');\n        const coverHeight = this.componentConfiguration.autoplayNumericInputsViewProps.settingsMenuCover.get('height');\n        const coverColor = this.componentConfiguration.autoplayNumericInputsViewProps.settingsMenuCover.get('color');\n        this.settingsMenuCover = new Graphics().beginFill(coverColor).drawRect(0, 0, coverWidth, coverHeight).endFill();\n        this.settingsMenuCover.x =\n            this.componentConfiguration.autoplayNumericInputsViewProps.settingsMenuCover.get('x');\n        this.settingsMenuCover.y =\n            this.componentConfiguration.autoplayNumericInputsViewProps.settingsMenuCover.get('y');\n        this.settingsMenuCover.alpha = 0;\n        this.settingsMenuCover.visible = false;\n        this.settingsMenuCover.interactive = false;\n        this.addChild(this.settingsMenuCover);\n    }\n\n    protected setEventListeners(): void {\n        this.startAutoplayButton.CLICK.pipe(takeUntil(this.DESTROY)).subscribe(this.startAutoplayFromMenu.bind(this));\n        this.rootStore.uiStore.STATE.pipe(takeUntil(this.DESTROY)).subscribe(this.stateChanged.bind(this));\n        this.rootStore.uiStore.BALANCE.pipe(takeUntil(this.DESTROY)).subscribe(this.onBalanceChange.bind(this));\n        const betChange = merge(\n            Core.SELECTED_DENOMINATION,\n            this.rootStore.uiStore.LINES,\n            this.rootStore.uiStore.SELECTED_BET,\n            this.rootStore.subjects.FACTOR_CHANGED,\n        );\n        betChange.pipe(takeUntil(this.DESTROY)).subscribe(this.onBetChange.bind(this));\n        if (Core.isDesktopMode) {\n            this.rootStore.subjects.KEY_DOWN.pipe(takeUntil(this.DESTROY)).subscribe(this.onKeyDown.bind(this));\n        }\n        this.addInputFieldsEventListeners();\n    }\n\n    private addInputFieldsEventListeners(): void {\n        for (const field of this.inputFields) {\n            field.FOCUS.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n                this.handleInputFieldFocus(field);\n                this.showNumericKeyboardField(field);\n            });\n        }\n    }\n\n    private handleInputFieldFocus(selectedField: InputField): void {\n        for (const field of this.inputFields) {\n            if (field === selectedField) {\n                field.setActive();\n                this.activeInputField = field;\n            } else {\n                field.setInactive();\n            }\n        }\n    }\n\n    private onKeyDown = (event: KeyboardEvent) => {\n        if (event === null || !this.activeInputField) {\n            return;\n        }\n\n        if (/^[0-9.]$/.test(event.key)) {\n            const newValue = this.activeInputField.getValue() + event.key;\n            this.activeInputField.setValue(newValue);\n        } else if (event.key === 'Backspace') {\n            const value = this.activeInputField.getValue();\n            // const newValue = value.slice(0, -1);\n            this.activeInputField.setValue(value.slice(0, -1));\n\n            // if (newValue.length === 0) {\n            //     this.activeInputField.setInactive();\n            // }\n        }\n    };\n    // ==============================\n    // KEYBOARD\n    // ==============================\n    public showNumericKeyboardField(field: InputField): void {\n        if (Core.isDesktopMode) return;\n\n        if (this.numericKeyboard && this.isKeyboardVisible) {\n            this.currentField = field;\n            this.numericKeyboard.setCurrentField(field);\n            return;\n        }\n\n        if (!this.numericKeyboard) {\n            this.numericKeyboard = new KeyboardNumeric(this.componentConfiguration);\n            this.addChild(this.numericKeyboard);\n\n            this.numericKeyboard.ON_DONE.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n                this.hideNumericKeyboardField(true);\n            });\n            this.numericKeyboard.ON_CANCEL.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n                this.hideNumericKeyboardField(true);\n            });\n            this.numericKeyboard.ON_INPUT.pipe(takeUntil(this.DESTROY)).subscribe((value: string) => {\n                if (this.currentField) {\n                    this.currentField.setValue(value);\n                }\n            });\n        }\n\n        if (this.numericKeyboard) {\n            this.numericKeyboard.updateKeyboardBalanceValue(\n                this.extractNumberString(this.balanceValue.getMoneyTextValue()),\n            );\n            this.numericKeyboard.updateKeyboardBetValue(this.extractNumberString(this.betValue.getMoneyTextValue()));\n            this.numericKeyboard.updateCurrency(this.rootStore.settings.currency);\n        }\n\n        this.currentField = field;\n        this.numericKeyboard.setCurrentField(field);\n\n        this.numericKeyboard.visible = true;\n\n        if (this.numericKeyboard) {\n            this.numericKeyboard.showShadowBackground();\n        }\n\n        this.animateShowKeyboard();\n        this.setOrientation(Core.ORIENTATION.value);\n    }\n\n    private extractNumberString(input: string): string {\n        return input.replace(/[^0-9.]/g, '');\n    }\n\n    public hideNumericKeyboardField(animate: boolean = false): void {\n        if (this.numericKeyboard) {\n            this.killNumericKeyboardTween();\n            if (animate) {\n                this.animateHideKeyboard();\n            } else {\n                this.numericKeyboard.visible = false;\n                this.numericKeyboard.alpha = 0;\n                this.numericKeyboard.y = this.startingPoint;\n                this.isKeyboardVisible = false;\n                this.numericKeyboard.hideShadowBackground();\n            }\n        }\n    }\n\n    private animateShowKeyboard(): void {\n        const axis = Core.ORIENTATION.value.isPortrait ? 'y' : 'x';\n        const startingPoint = Core.ORIENTATION.value.isPortrait ? this.startingPoint : Core.stage.stage.width;\n        // this.setInputFieldsInteractive(false);\n        this.numericKeyboard.alpha = 0;\n        this.numericKeyboard[axis] = startingPoint;\n\n        this.numericKeyboardTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/slot-components/settings-popup/src/egt/settings-views/spin/SpinSettingsNumericInputView.ts:894:37\",null]), gsap.timeline({\n            onComplete: () => {\n                // this.setInputFieldsInteractive(true);\n                this.isKeyboardVisible = true;\n            },\n        }));\n\n        this.settingsMenuCover.visible = true;\n        this.numericKeyboardTween\n            .to(this.numericKeyboard, { alpha: 1, duration: 0.2 }, 0)\n            .to(this.numericKeyboard, { [axis]: 0, duration: 0.25, ease: 'power1.out' }, 0)\n            .to(\n                this.settingsMenuCover,\n                {\n                    alpha: 1,\n                    duration: 0.25,\n                    ease: 'power1.out',\n                    onComplete: () => {\n                        this.settingsMenuCover.interactive = true;\n                    },\n                },\n                '<',\n            );\n    }\n\n    private animateHideKeyboard(onComplete?: () => void): void {\n        const axis = Core.ORIENTATION.value.isPortrait ? 'y' : 'x';\n        const resetValue = Core.ORIENTATION.value.isPortrait ? this.numericKeyboard.y : this.numericKeyboard.x;\n        // this.setInputFieldsInteractive(false);\n        const startingPoint = Core.ORIENTATION.value.isPortrait ? this.startingPoint : Core.stage.stage.width;\n\n        this.numericKeyboardTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/slot-components/settings-popup/src/egt/settings-views/spin/SpinSettingsNumericInputView.ts:925:37\",null]), gsap.timeline({\n            onComplete: () => {\n                // this.setInputFieldsInteractive(true);\n                this.numericKeyboard.visible = false;\n                this.numericKeyboard[axis] = resetValue;\n                this.isKeyboardVisible = false;\n                if (onComplete) onComplete();\n            },\n        }));\n\n        this.numericKeyboardTween\n            .to(this.numericKeyboard, { alpha: 0, duration: 0.25 }, 0)\n            .to(this.numericKeyboard, { [axis]: startingPoint, duration: 0.25, ease: 'power1.in' }, 0)\n            .to(\n                this.settingsMenuCover,\n                {\n                    alpha: 0,\n                    duration: 0.25,\n                    ease: 'power1.out',\n                    onComplete: () => {\n                        this.settingsMenuCover.visible = false;\n                        this.settingsMenuCover.interactive = false;\n                    },\n                },\n                '<',\n            );\n    }\n\n    // private setInputFieldsInteractive(interactive: boolean = true): void {\n    //     for (const field of this.inputFields) {\n    //         field.setInteractive(interactive);\n    //     }\n    // }\n\n    private killNumericKeyboardTween(): void {\n        if (this.numericKeyboardTween) {\n            this.numericKeyboardTween.kill();\n            //@ts-ignore\n            this.numericKeyboardTween = null;\n        }\n    }\n\n    // ==============================\n    // ORIENTATION\n    // ==============================\n\n    protected setOrientation(_orientation: IOrientation): void {\n        this.setTextsConfigs();\n        this.setStopOnTextOrientation();\n        this.setInputFieldsOrientation();\n        this.setSpinsSliderOrientation();\n        this.setStartButtonOrientation();\n        this.setBalanceOrientation();\n        this.setBetOrientation();\n        this.setKeyboardOrientation();\n    }\n\n    protected setStopOnTextOrientation(): void {\n        this.stopOnText.x = this.componentConfiguration.autoplayNumericInputsViewProps.stopOnText.get('x');\n        this.stopOnText.y = this.componentConfiguration.autoplayNumericInputsViewProps.stopOnText.get('y');\n    }\n\n    protected setInputFieldsOrientation() {\n        this.indputFieldsContainer.x =\n            this.componentConfiguration.autoplayNumericInputsViewProps.inputFieldsContainer.get('x');\n        this.indputFieldsContainer.y =\n            this.componentConfiguration.autoplayNumericInputsViewProps.inputFieldsContainer.get('y');\n\n        this.maxLossAmountFieldContainer.x =\n            this.componentConfiguration.autoplayNumericInputsViewProps.maxLossAmountContainerConfig.get('containerX');\n        this.maxLossAmountFieldContainer.y =\n            this.componentConfiguration.autoplayNumericInputsViewProps.maxLossAmountContainerConfig.get('containerY');\n\n        this.balanceLessThanFieldContainer.x =\n            this.componentConfiguration.autoplayNumericInputsViewProps.balanceLessThanContainerConfig.get('containerX');\n        this.balanceLessThanFieldContainer.y =\n            this.componentConfiguration.autoplayNumericInputsViewProps.balanceLessThanContainerConfig.get('containerY');\n\n        this.balanceMoreThanFieldContainer.x =\n            this.componentConfiguration.autoplayNumericInputsViewProps.balanceMoreThanContainerConfig.get('containerX');\n        this.balanceMoreThanFieldContainer.y =\n            this.componentConfiguration.autoplayNumericInputsViewProps.balanceMoreThanContainerConfig.get('containerY');\n\n        this.winOverFieldContainer.x =\n            this.componentConfiguration.autoplayNumericInputsViewProps.winOverContainerConfig.get('containerX');\n        this.winOverFieldContainer.y =\n            this.componentConfiguration.autoplayNumericInputsViewProps.winOverContainerConfig.get('containerY');\n    }\n\n    protected setSpinsSliderOrientation(): void {\n        this.spinsSliderContainer.x =\n            this.componentConfiguration.autoplayNumericInputsViewProps.spinsSliderContainerPosition.get('x');\n        this.spinsSliderContainer.y =\n            this.componentConfiguration.autoplayNumericInputsViewProps.spinsSliderContainerPosition.get('y');\n    }\n\n    protected setStartButtonOrientation(): void {\n        this.startAutoplayButton.x =\n            this.componentConfiguration.autoplayNumericInputsViewProps.startAutoplayButton.get('x');\n        this.startAutoplayButton.y =\n            this.componentConfiguration.autoplayNumericInputsViewProps.startAutoplayButton.get('y');\n        const bounds = this.startButtonText.getLocalBounds();\n        this.startButtonText.pivot.set(bounds.x + bounds.width / 2, bounds.y + bounds.height / 2);\n        this.startButtonText.x = this.startAutoplayButton.width / 2;\n        this.startButtonText.y = this.startAutoplayButton.height / 2;\n    }\n\n    protected setBalanceOrientation(): void {\n        const balanceField = this.componentConfiguration.autoplayNumericInputsViewProps.balanceField;\n        this.balanceValue.config = this.balanceValueConfig;\n\n        this.balanceText.x = balanceField.get('textPosition').x;\n        this.balanceText.y = balanceField.get('textPosition').y;\n        this.balanceValue.x = balanceField.get('valuePostion').x + this.balanceText.width;\n        this.balanceValue.y = balanceField.get('valuePostion').y;\n        this.balanceContainer.x = balanceField.get('containerPosition').x;\n        this.balanceContainer.y = balanceField.get('containerPosition').y;\n    }\n\n    protected setBetOrientation(): void {\n        const betField = this.componentConfiguration.autoplayNumericInputsViewProps.betField;\n        this.betValue.config = this.betValueConfig;\n\n        this.betText.x = betField.get('textPosition').x;\n        this.betText.y = betField.get('textPosition').y;\n        this.betValue.x = betField.get('valuePostion').x + this.betText.width;\n        this.betValue.y = betField.get('valuePostion').y;\n\n        const bounds = this.betContent.getLocalBounds();\n        this.betContent.position.x = -bounds.width;\n        this.betContainer.x = betField.get('containerPosition').x;\n        this.betContainer.y = betField.get('containerPosition').y;\n    }\n\n    protected setKeyboardOrientation(): void {\n        if (this.numericKeyboard) {\n            this.numericKeyboard.reposition();\n        }\n        if (this.settingsMenuCover && this.settingsMenuCover.interactive) {\n            this.settingsMenuCover.visible = Core.ORIENTATION.value.isLandscape;\n        }\n    }\n    // ==============================\n    // CONFIG HELPERS\n    // ==============================\n    protected setTextsConfigs(): void {\n        this.stopOnConfig.bounds.width =\n            Core.display.stage.width - this.componentConfiguration.autoplayViewProps.decreaseConfig.boundsWidth;\n        this.stopOnConfig.bounds.height = this.componentConfiguration.autoplayViewProps.decreaseConfig.boundsHeight;\n        this.stopOnConfig.minFontSize = this.componentConfiguration.autoplayViewProps.decreaseConfig.minFontSize;\n        this.stopOnConfig.shouldFitInBounds =\n            this.componentConfiguration.autoplayViewProps.decreaseConfig.shouldFitInBounds;\n\n        this.spinsConfig.bounds.width =\n            Core.display.stage.width - this.componentConfiguration.autoplayViewProps.spinsConfig.boundsWidth;\n        this.spinsConfig.bounds.height = this.componentConfiguration.autoplayViewProps.spinsConfig.boundsHeight;\n        this.spinsConfig.minFontSize = this.componentConfiguration.autoplayViewProps.spinsConfig.minFontSize;\n        this.spinsConfig.shouldFitInBounds =\n            this.componentConfiguration.autoplayViewProps.spinsConfig.shouldFitInBounds;\n\n        this.spinsValueConfig.bounds.width =\n            Core.display.stage.width / 10 - this.componentConfiguration.autoplayViewProps.spinsValueConfig.boundsWidth;\n        this.spinsValueConfig.bounds.height =\n            this.componentConfiguration.autoplayViewProps.spinsValueConfig.boundsHeight;\n        this.spinsValueConfig.minFontSize = this.componentConfiguration.autoplayViewProps.spinsValueConfig.minFontSize;\n        this.spinsValueConfig.shouldFitInBounds =\n            this.componentConfiguration.autoplayViewProps.spinsValueConfig.shouldFitInBounds;\n        this.spinsValueConfig.align = this.componentConfiguration.autoplayViewProps.spinsValueConfig.align;\n\n        this.startButtonTextConfig.bounds.width =\n            this.startAutoplayButton.width -\n            this.componentConfiguration.autoplayViewProps.startButtonTextConfig.boundsWidth;\n        this.startButtonTextConfig.bounds.height =\n            this.componentConfiguration.autoplayViewProps.startButtonTextConfig.boundsHeight;\n        this.startButtonTextConfig.minFontSize =\n            this.componentConfiguration.autoplayViewProps.startButtonTextConfig.minFontSize;\n        this.startButtonTextConfig.shouldFitInBounds =\n            this.componentConfiguration.autoplayViewProps.startButtonTextConfig.shouldFitInBounds;\n        this.startButtonTextConfig.align = this.componentConfiguration.autoplayViewProps.startButtonTextConfig.align;\n\n        this.balanceValueConfig.currency = this.betValueConfig.currency = this.rootStore.uiStore.currency;\n        this.balanceValueConfig.bounds.width =\n            this.componentConfiguration.autoplayViewProps.balanceValueConfig.boundsWidth;\n        this.betValueConfig.bounds.width = this.componentConfiguration.autoplayViewProps.betValueConfig.boundsWidth;\n        this.balanceValueConfig.moneyFontSize =\n            this.balanceValueConfig.centsFontSize =\n            this.betValueConfig.centsFontSize =\n            this.betValueConfig.moneyFontSize =\n                22;\n        this.balanceValueConfig.bounds.height =\n            this.betValueConfig.bounds.height =\n            this.betTextConfig.bounds.height =\n            this.balanceTextConfig.bounds.height =\n                50;\n        this.balanceValueConfig.spaceBetweenMoneyAndCurrency = this.betValueConfig.spaceBetweenMoneyAndCurrency = 4;\n    }\n    // ==============================\n    // BUSINESS LOGIC\n    // ==============================\n    public redrawView(): void {\n        this.setOrientation(Core.ORIENTATION.value);\n    }\n\n    protected getTotalBet(): number {\n        const factor = this.rootStore.settings.factor\n            ? this.rootStore.settings.factor\n            : this.rootStore.uiStore.LINES.value;\n        return Core.SELECTED_DENOMINATION.value * this.rootStore.uiStore.SELECTED_BET.value * factor;\n    }\n\n    private getLessBalance(): number {\n        return (this.rootStore.uiStore.BALANCE.value * this.settings.autoplayRestrictions.lossLimits) / 100;\n    }\n\n    private getMoreBalance(): number {\n        return (this.rootStore.uiStore.BALANCE.value * this.settings.autoplayRestrictions.winLimits) / 100;\n    }\n\n    private getWinOver(): number {\n        return this.getTotalBet() * this.settings.autoplayRestrictions.singleWinLimit;\n    }\n\n    protected onBalanceChange(): void {\n        if (this.balanceValue) {\n            this.balanceValue.money = this.rootStore.uiStore.BALANCE.value;\n        }\n        this.updateUnderTitleTexts();\n    }\n\n    private onBetChange(): void {\n        if (this.betValue) {\n            this.betValue.money = this.getTotalBet();\n        }\n        this.updateUnderTitleTexts();\n    }\n\n    private stateChanged(): void {\n        if (this.settings.autoplayRestrictions.mandatory.length === 0) {\n            this.setAutoplayButtonState(true);\n        }\n    }\n\n    private setAutoplayButtonState(active: boolean): void {\n        if (active) {\n            this.startAutoplayButton.enabled = true;\n            this.startButtonText.alpha = this.componentConfiguration.autoplayViewProps.startButtonTextActiveAlpha;\n        } else {\n            this.startAutoplayButton.enabled = false;\n            this.startButtonText.alpha = this.componentConfiguration.autoplayViewProps.startButtonTextInactiveAlpha;\n        }\n    }\n\n    protected makeSpinsSelection(value: number): void {\n        this.autoSpinsSelected = value;\n    }\n\n    protected startAutoplayFromMenu(): void {\n        if (this.VISIBLE.value) {\n            (this.parent as SettingsPopup).clearTabSelection();\n            this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.next(this.autoSpinsSelected);\n            this.rootStore.subjects.CLOSE_SETTINGS_POPUP.next();\n            this.rootStore.uiStore.SHOW_SETTINGS.next(false);\n            this.rootStore.subjects.START_AUTOPLAY.next(this.autoSpinsSelected);\n            this.rootStore.subjects.SETTINGS_POPUP_CLOSED.next();\n            this.shouldSetUiStoreFieldValues = false;\n            this.resetInputFields();\n            this.spinsSlider.resetSlider();\n        }\n    }\n\n    private checkForMandatory() {\n        let mandatoryChecked: boolean = true;\n        for (const mandatory of this.mandatory) {\n            if (mandatory === MandatoryValuesNumeric.BALANCE_LES && this.balanceLess === 0) {\n                mandatoryChecked = false;\n            } else if (mandatory === MandatoryValuesNumeric.BALANCE_MORE && this.balanceMore === 0) {\n                mandatoryChecked = false;\n            } else if (mandatory === MandatoryValuesNumeric.WIN_OVER && this.winOver === 0) {\n                mandatoryChecked = false;\n            } else if (mandatory === MandatoryValuesNumeric.MAX_LOSS && this.maxLoss === 0) {\n                mandatoryChecked = false;\n            }\n        }\n\n        for (const field of this.inputFields) {\n            if (field.hasError && field.getValue() !== '') {\n                mandatoryChecked = false;\n                break;\n            }\n        }\n\n        if (mandatoryChecked) {\n            this.startAutoplayButton.enabled = true;\n            this.startAutoplayButton.state = ButtonStates.Normal;\n            this.startButtonText.alpha = this.componentConfiguration.autoplayViewProps.startButtonTextActiveAlpha;\n            if (this.numericKeyboard && this.numericKeyboard.doneButton) {\n                this.numericKeyboard.doneButton.untintBtn();\n            }\n        } else {\n            this.startAutoplayButton.enabled = false;\n            this.startAutoplayButton.state = ButtonStates.Disabled;\n            this.startButtonText.alpha = this.componentConfiguration.autoplayViewProps.startButtonTextInactiveAlpha;\n            if (this.numericKeyboard && this.numericKeyboard.doneButton) {\n                this.numericKeyboard.doneButton.tintBtn();\n            }\n        }\n    }\n\n    protected resetAutoPlayRestrictions(): void {\n        this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.next(0);\n        this.rootStore.uiStore.autoPlayFromSettings = false;\n        this.shouldSetUiStoreFieldValues = true;\n        if (this.activeInputField) {\n            this.activeInputField.resetToInitial();\n            this.activeInputField.setInactive();\n            this.activeInputField = null;\n        }\n        this.resetInputFields();\n        this.spinsSlider.resetSlider();\n    }\n\n    private resetInputFields(): void {\n        this.maxLossAmountField.resetToInitial();\n        this.balanceLessThanField.resetToInitial();\n        this.balanceMoreThanField.resetToInitial();\n        this.winOverField.resetToInitial();\n    }\n\n    private updateUnderTitleTexts(): void {\n        const currency = this.rootStore.settings.currency;\n        if (this.maxLossUnderTitle) {\n            this.maxLossUnderTitle.text = this.getRangeText(\n                this.getTotalBet(),\n                this.rootStore.uiStore.BALANCE.value,\n                currency,\n            );\n        }\n        if (this.balanceLessUnderTitle) {\n            this.balanceLessUnderTitle.text = this.getRangeText(this.minBet, this.getLessBalance(), currency);\n        }\n        if (this.balanceMoreUnderTitle) {\n            this.balanceMoreUnderTitle.text = this.getRangeText(this.minBet, this.getMoreBalance(), currency);\n        }\n        if (this.winOverUnderTitle) {\n            this.winOverUnderTitle.text = this.getRangeText(this.minBet, this.getWinOver(), currency);\n        }\n        this.maxLossAmountField.setMaxValue(this.rootStore.uiStore.BALANCE.value);\n        this.maxLossAmountField.setMinValue(this.getTotalBet());\n        this.balanceLessThanField.setMaxValue(this.getLessBalance());\n        this.balanceMoreThanField.setMaxValue(this.getMoreBalance());\n        this.winOverField.setMaxValue(this.getWinOver());\n    }\n}\n","import Core, { ErrorTypes, IErrorData, IOrientation } from '@egt/core';\nimport { FeatureController, InitialSettings, RootStore } from '@egt/slot';\nimport {\n    Button,\n    ButtonStates,\n    IViewVisibilityContainer,\n    MoneyText,\n    MoneyTextConfig,\n    SteppedSlider,\n    Text,\n    TextConfig,\n    ViewContainer,\n    ViewVisibilityContainer,\n} from '@egt/ui-lib';\nimport { Sprite, TextStyle, Texture } from 'pixi.js';\nimport { merge } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { ISettingsPopupComponentConfiguration } from '../../interfaces/SettingsInterfaces';\nimport SettingsPopup from '../../views/SettingsPopup';\n\n@injectable()\nexport default class SpinSettingsView extends ViewVisibilityContainer implements IViewVisibilityContainer {\n    public balanceDecreaseValue: MoneyText;\n    public balanceIncreaseValue: MoneyText;\n    protected zeroValueStyle: TextStyle;\n    protected mandatorySignConfig: TextConfig = new TextConfig();\n    protected mandatorySignStyle: TextStyle;\n    protected spinsConfig: TextConfig = new TextConfig();\n    protected spinsStyle: TextStyle;\n    protected spinsValueConfig: TextConfig = new TextConfig();\n    protected spinsValueStyle: TextStyle;\n    protected decreaseConfig: TextConfig = new TextConfig();\n    protected decreaseStyle: TextStyle;\n    protected decreaseValueStyle: TextStyle;\n    protected increaseConfig: TextConfig = new TextConfig();\n    protected increaseStyle: TextStyle;\n    protected increaseValueStyle: TextStyle;\n    protected singleWinConfig: TextConfig = new TextConfig();\n    protected singleWinStyle: TextStyle;\n    protected noLimitConfig: TextConfig = new TextConfig();\n    protected limitsValuesConfig: MoneyTextConfig = new MoneyTextConfig();\n    protected singleWinValueStyle: TextStyle;\n    protected startButtonTextConfig: TextConfig = new TextConfig();\n    protected startButtonTextStyle: TextStyle;\n    protected balanceTextStyle: TextStyle;\n    protected balanceTextConfig: TextConfig = new TextConfig();\n    protected betTextStyle: TextStyle;\n    protected betTextConfig: TextConfig = new TextConfig();\n    protected balanceValueConfig: MoneyTextConfig = new MoneyTextConfig();\n    protected betValueConfig: MoneyTextConfig = new MoneyTextConfig();\n    protected betValueStyle: TextStyle;\n    protected balanceValueStyle: TextStyle;\n    protected stopOnStyle: TextStyle;\n    //\n    protected decreaseMandatorySign: Text;\n    protected increaseMandatorySign: Text;\n    protected winMandatorySign: Text;\n    protected startButtonText: Text;\n    protected numberOfSpinsText: Text;\n    protected numberOfSpinsValue: Text;\n    protected stopOnText: Text;\n    protected balanceDecreaseText: Text;\n    protected balanceDecreaseZeroValue: Text;\n    protected balanceIncreaseText: Text;\n    protected balanceIncreaseZeroValue: Text;\n    protected singleWinLimitText: Text;\n    protected singleWinLimitValue: MoneyText;\n    protected singleWinZeroValue: Text;\n    protected balanceText: Text;\n    protected betText: Text;\n    //\n    protected balanceValue: MoneyText;\n    protected betValue: MoneyText;\n    //\n    protected numberOfSpinsValues: number[];\n    protected balanceDecreaseValues: number;\n    protected balanceIncreaseValues: number;\n    protected singleWinLimitValues: number;\n    //\n    protected startAutoplayButton: Button;\n    protected infinityValueTexture: Sprite;\n    //\n    protected spinsSlider: SteppedSlider;\n    protected lossSlider: SteppedSlider;\n    protected winsSlider: SteppedSlider;\n    protected singleWinSlider: SteppedSlider;\n    //\n    protected spinsSliderContainer: ViewContainer;\n    protected lossSliderContainer: ViewContainer;\n    protected winsSliderContainer: ViewContainer;\n    protected singleWinSliderContainer: ViewContainer;\n    protected balanceContainer: ViewContainer;\n    protected betContainer: ViewContainer;\n    //\n    protected sliderContainerWidth: number;\n    protected sliderContainerHeight: number;\n    protected sliderWidth: number;\n    protected sliderHeight: number;\n    protected sliderTopOffset: number;\n    protected autoSpinsSelected: number = 0;\n    protected textTopOffset: number;\n    //\n    protected headers: any[] = [];\n    protected values: any[] = [];\n    protected selectedMandatoryFields: string[] = [];\n\n    protected stateDisabled = false;\n\n    protected colorValues: number;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('FeatureController') protected feature: FeatureController,\n        @inject('SettingsPopupComponentConfiguration')\n        protected componentConfiguration: ISettingsPopupComponentConfiguration,\n    ) {\n        super();\n        this.init();\n    }\n\n    public init(): void {\n        this.sliderContainerWidth = this.componentConfiguration.autoplayViewProps.sliderContainerWidth;\n        this.sliderContainerHeight = this.componentConfiguration.autoplayViewProps.sliderContainerHeight;\n        this.sliderWidth = this.componentConfiguration.autoplayViewProps.sliderWidth;\n        this.sliderHeight = this.componentConfiguration.autoplayViewProps.sliderHeight;\n        this.sliderTopOffset = this.componentConfiguration.autoplayViewProps.sliderTopOffset;\n        this.textTopOffset = this.componentConfiguration.autoplayViewProps.textTopOffset;\n        this.colorValues = this.componentConfiguration.autoplayViewProps.slidersValuesColor;\n        /// TEXT STYLES ///\n        this.zeroValueStyle = this.componentConfiguration.autoplayViewProps.zeroValueStyle;\n        this.mandatorySignStyle = this.componentConfiguration.autoplayViewProps.mandatorySignStyle;\n        this.spinsStyle = this.componentConfiguration.autoplayViewProps.spinsStyle;\n        this.spinsValueStyle = this.componentConfiguration.autoplayViewProps.spinsValueStyle;\n        // this.spinsValueStyle.fill = this.componentConfiguration.autoplayViewProps.slidersValuesColor;\n        this.decreaseStyle = this.componentConfiguration.autoplayViewProps.decreaseStyle;\n        this.decreaseValueStyle = this.componentConfiguration.autoplayViewProps.decreaseValueStyle;\n        this.increaseStyle = this.componentConfiguration.autoplayViewProps.increaseStyle;\n        this.increaseValueStyle = this.componentConfiguration.autoplayViewProps.increaseValueStyle;\n        this.singleWinStyle = this.componentConfiguration.autoplayViewProps.singleWinStyle;\n        this.singleWinValueStyle = this.componentConfiguration.autoplayViewProps.singleWinValueStyle;\n        this.startButtonTextStyle = this.componentConfiguration.autoplayViewProps.startButtonTextStyle;\n        this.balanceTextStyle = this.componentConfiguration.autoplayViewProps.balanceTextStyle;\n        this.betTextStyle = this.componentConfiguration.autoplayViewProps.betTextStyle;\n        this.betValueStyle = this.componentConfiguration.autoplayViewProps.betValueStyle;\n        this.balanceValueStyle = this.componentConfiguration.autoplayViewProps.balanceValueStyle;\n        this.stopOnStyle = this.componentConfiguration.autoplayViewProps.stopOnStyle;\n        /// TEXT STYLES ///\n\n        this.balanceDecreaseValues = this.settings.autoplayRestrictions.lossLimits;\n        this.balanceIncreaseValues = this.settings.autoplayRestrictions.winLimits;\n        this.singleWinLimitValues = this.getTotalBet() * this.settings.autoplayRestrictions.singleWinLimit;\n\n        this.numberOfSpinsValues = this.settings.autoplayRestrictions.autoPlays;\n\n        if (this.settings.autoplayRestrictions.mandatory.length === 0) {\n            this.rootStore.uiStore.allRestrictionsApplied = true;\n        }\n\n        this.initialRender();\n\n        // Core.ORIENTATION.pipe(\n        //     filter(x=> this.VISIBLE.value),\n        //     takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n        this.rootStore.uiStore.STATE.pipe(takeUntil(this.DESTROY)).subscribe(this.stateChanged.bind(this));\n        this.rootStore.uiStore.BALANCE.pipe(takeUntil(this.DESTROY)).subscribe(this.onBalanceChange.bind(this));\n        this.rootStore.subjects.RESET_AUTOPLAY_RESTRICTIONS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.resetAutoPlayRestrictions.bind(this),\n        );\n\n        const betChange = merge(\n            Core.SELECTED_DENOMINATION,\n            this.rootStore.uiStore.LINES,\n            this.rootStore.uiStore.SELECTED_BET,\n            this.rootStore.subjects.FACTOR_CHANGED,\n        );\n\n        betChange.pipe(takeUntil(this.DESTROY)).subscribe(this.onBetChange.bind(this));\n        this.show = false;\n    }\n\n    public destroy(_options?: { children?: boolean; texture?: boolean; baseTexture?: boolean }): void {\n        super.destroy.apply(this, arguments);\n        Object.keys(this).forEach((key: string) => {\n            if (this[key] && !key.includes('_') && !(this[key] instanceof Function)) {\n                this[key] = null;\n            }\n        });\n    }\n\n    public redrawView(): void {\n        this.setOrientation(Core.ORIENTATION.value);\n    }\n\n    protected setOrientation(orientation: IOrientation): void {\n        this.setTextsConfigs();\n\n        this.numberOfSpinsValue.textBounds.width =\n            Core.display.stage.width / this.componentConfiguration.autoplayViewProps.numberOfSpinsValueDevider;\n\n        this.balanceDecreaseValue.config = this.limitsValuesConfig;\n        this.balanceIncreaseValue.config = this.limitsValuesConfig;\n        this.singleWinLimitValue.config = this.limitsValuesConfig;\n        this.balanceDecreaseZeroValue.config = this.noLimitConfig;\n        this.balanceIncreaseZeroValue.config = this.noLimitConfig;\n        this.singleWinZeroValue.config = this.noLimitConfig;\n        this.numberOfSpinsText.config = this.spinsConfig;\n        this.stopOnText.config = this.decreaseConfig;\n        this.balanceDecreaseText.config = this.decreaseConfig;\n        this.balanceIncreaseText.config = this.increaseConfig;\n        this.singleWinLimitText.config = this.singleWinConfig;\n        this.numberOfSpinsValue.config = this.spinsValueConfig;\n        this.startButtonText.config = this.startButtonTextConfig;\n        this.balanceValue.config = this.balanceValueConfig;\n        this.betValue.config = this.betValueConfig;\n        this.decreaseMandatorySign.config = this.mandatorySignConfig;\n        this.increaseMandatorySign.config = this.mandatorySignConfig;\n        this.winMandatorySign.config = this.mandatorySignConfig;\n\n        this.stopOnText.x = this.componentConfiguration.autoplayViewProps.stopOnTextX;\n        this.stopOnText.y = this.componentConfiguration.autoplayViewProps.stopOnTextY;\n        this.balanceDecreaseText.x = this.componentConfiguration.autoplayViewProps.balanceDecreaseTextX;\n        this.balanceDecreaseText.y = this.componentConfiguration.autoplayViewProps.balanceDecreaseTextY;\n        this.balanceDecreaseValue.x = this.componentConfiguration.autoplayViewProps.balanceDecreaseValueX;\n        this.balanceDecreaseValue.y = this.componentConfiguration.autoplayViewProps.balanceDecreaseValueY;\n        this.lossSliderContainer.x = orientation.isLandscape\n            ? this.componentConfiguration.autoplayViewProps.sliderContainersX\n            : (Core.display.stage.width - this.sliderContainerWidth) / 2;\n        this.lossSliderContainer.y =\n            this.balanceDecreaseValue.y + this.balanceDecreaseValue.height + this.sliderTopOffset;\n        this.lossSlider.x = (this.sliderContainerWidth - this.sliderWidth) / 2;\n        this.lossSlider.y = (this.sliderContainerHeight - this.sliderHeight) / 2;\n        this.balanceIncreaseText.x = this.componentConfiguration.autoplayViewProps.balanceIncreaseTextX;\n        this.balanceIncreaseText.y = this.lossSliderContainer.y + this.lossSliderContainer.height + this.textTopOffset;\n        this.balanceIncreaseValue.x = this.componentConfiguration.autoplayViewProps.balanceIncreaseValueX;\n        this.balanceIncreaseValue.y = this.lossSliderContainer.y + this.lossSliderContainer.height + this.textTopOffset;\n        this.winsSliderContainer.x = orientation.isLandscape\n            ? this.componentConfiguration.autoplayViewProps.sliderContainersX\n            : (Core.display.stage.width - this.sliderContainerWidth) / 2;\n        this.winsSliderContainer.y =\n            this.balanceIncreaseValue.y + this.balanceIncreaseValue.height + this.sliderTopOffset;\n        this.winsSlider.x = (this.sliderContainerWidth - this.sliderWidth) / 2;\n        this.winsSlider.y = (this.sliderContainerHeight - this.sliderHeight) / 2;\n        this.singleWinLimitText.x = this.componentConfiguration.autoplayViewProps.singleWinLimitTextX;\n        this.singleWinLimitText.y = this.winsSliderContainer.y + this.winsSliderContainer.height + this.textTopOffset;\n        this.singleWinLimitValue.x = this.componentConfiguration.autoplayViewProps.singleWinLimitValueX;\n        this.singleWinLimitValue.y = this.singleWinLimitText.y;\n        this.singleWinSliderContainer.x = orientation.isLandscape\n            ? this.componentConfiguration.autoplayViewProps.sliderContainersX\n            : (Core.display.stage.width - this.sliderContainerWidth) / 2;\n        this.singleWinSliderContainer.y =\n            this.singleWinLimitValue.y + this.singleWinLimitValue.height + this.sliderTopOffset;\n        this.singleWinSlider.x = (this.sliderContainerWidth - this.sliderWidth) / 2;\n        this.singleWinSlider.y = (this.sliderContainerHeight - this.sliderHeight) / 2;\n        this.numberOfSpinsText.x = orientation.isLandscape\n            ? Core.display.stage.width -\n              this.sliderContainerWidth -\n              this.componentConfiguration.autoplayViewProps.numberOfSpinsTextX\n            : this.componentConfiguration.autoplayViewProps.numberOfSpinsTextX;\n        this.numberOfSpinsText.y = orientation.isLandscape\n            ? this.componentConfiguration.autoplayViewProps.numberOfSpinsTextY\n            : this.singleWinSliderContainer.y +\n              this.singleWinSliderContainer.height +\n              this.componentConfiguration.autoplayViewProps.numberOfSpinsTextY;\n        this.numberOfSpinsValue.x = orientation.isLandscape\n            ? Core.display.stage.width - this.componentConfiguration.autoplayViewProps.numberOfSpinsValueX\n            : this.componentConfiguration.autoplayViewProps.numberOfSpinsValueX;\n        this.numberOfSpinsValue.y = orientation.isLandscape\n            ? this.componentConfiguration.autoplayViewProps.numberOfSpinsValueY\n            : this.singleWinSliderContainer.y +\n              this.singleWinSliderContainer.height +\n              this.componentConfiguration.autoplayViewProps.numberOfSpinsValueY;\n        this.infinityValueTexture.x =\n            Core.display.stage.width - this.componentConfiguration.autoplayViewProps.infinityValueTextureX;\n        this.infinityValueTexture.y =\n            this.numberOfSpinsValue.y + this.componentConfiguration.autoplayViewProps.infinityValueTextureY;\n        this.spinsSliderContainer.x = orientation.isLandscape\n            ? Core.display.stage.width -\n              this.sliderContainerWidth -\n              this.componentConfiguration.autoplayViewProps.sliderContainersX\n            : (Core.display.stage.width - this.sliderContainerWidth) / 2;\n        this.spinsSliderContainer.y = orientation.isLandscape\n            ? this.componentConfiguration.autoplayViewProps.spinsSliderContainerY +\n              this.balanceDecreaseValue.height +\n              this.sliderTopOffset\n            : this.numberOfSpinsText.y + this.numberOfSpinsText.height + this.sliderTopOffset;\n        this.spinsSlider.x = (this.sliderContainerWidth - this.sliderWidth) / 2;\n        this.spinsSlider.y = (this.sliderContainerHeight - this.sliderHeight) / 2;\n        this.startAutoplayButton.x = orientation.isLandscape\n            ? this.componentConfiguration.autoplayViewProps.startAutoplayButtonX\n            : (Core.display.stage.width - this.startAutoplayButton.width) / 2;\n        this.startAutoplayButton.y = orientation.isLandscape\n            ? this.spinsSliderContainer.y +\n              this.sliderContainerHeight +\n              this.componentConfiguration.autoplayViewProps.startAutoplayButtonY\n            : this.spinsSliderContainer.y +\n              this.spinsSliderContainer.height +\n              this.componentConfiguration.autoplayViewProps.startAutoplayButtonY;\n\n        this.startButtonText.pivot.set(0, this.startButtonText.textBounds.height / 2);\n        this.startButtonText.x = this.componentConfiguration.autoplayViewProps.startButtonTextX;\n        this.startButtonText.y = this.startAutoplayButton.height / 2;\n\n        this.balanceText.x = this.componentConfiguration.autoplayViewProps.balanceTextX;\n        this.balanceText.y = this.componentConfiguration.autoplayViewProps.balanceTextY;\n        this.balanceValue.x = this.componentConfiguration.autoplayViewProps.balanceValueX + this.balanceText.width;\n        this.balanceValue.y = this.componentConfiguration.autoplayViewProps.balanceValueY;\n        this.balanceContainer.x = orientation.isLandscape\n            ? Core.display.stage.width -\n              this.sliderContainerWidth -\n              this.componentConfiguration.autoplayViewProps.balanceContainerX\n            : this.componentConfiguration.autoplayViewProps.balanceContainerX;\n        this.balanceContainer.y = orientation.isLandscape\n            ? this.singleWinSliderContainer.y + this.componentConfiguration.autoplayViewProps.balanceContainerY\n            : this.componentConfiguration.autoplayViewProps.balanceContainerY;\n        this.betText.x = this.componentConfiguration.autoplayViewProps.betTextX;\n        this.betText.y = this.componentConfiguration.autoplayViewProps.betTextY;\n        this.betValue.x = this.componentConfiguration.autoplayViewProps.betValueX + this.betText.width;\n        this.betValue.y = this.componentConfiguration.autoplayViewProps.betValueY;\n        this.betContainer.x = this.componentConfiguration.autoplayViewProps.betContainerX - this.betContainer.width;\n        this.betContainer.y = this.balanceContainer.y + this.componentConfiguration.autoplayViewProps.betContainerY;\n\n        this.balanceDecreaseZeroValue.x =\n            this.balanceDecreaseValue.x + this.componentConfiguration.autoplayViewProps.balanceDecreaseZeroValueX;\n        this.balanceDecreaseZeroValue.y =\n            this.balanceDecreaseValue.y + this.componentConfiguration.autoplayViewProps.balanceDecreaseZeroValueY;\n\n        this.balanceIncreaseZeroValue.x =\n            this.balanceIncreaseValue.x + this.componentConfiguration.autoplayViewProps.balanceIncreaseZeroValueX;\n        this.balanceIncreaseZeroValue.y =\n            this.balanceIncreaseValue.y + this.componentConfiguration.autoplayViewProps.balanceIncreaseZeroValueY;\n\n        this.singleWinZeroValue.x =\n            this.singleWinLimitValue.x + this.componentConfiguration.autoplayViewProps.singleWinZeroValueX;\n        this.singleWinZeroValue.y =\n            this.singleWinLimitValue.y + this.componentConfiguration.autoplayViewProps.singleWinZeroValueY;\n\n        this.decreaseMandatorySign.x =\n            this.balanceDecreaseText.textWidth + this.componentConfiguration.autoplayViewProps.decreaseMandatorySignX;\n        this.decreaseMandatorySign.y = this.componentConfiguration.autoplayViewProps.decreaseMandatorySignY;\n\n        this.increaseMandatorySign.x =\n            this.balanceIncreaseText.textWidth + this.componentConfiguration.autoplayViewProps.increaseMandatorySignX;\n        this.increaseMandatorySign.y = this.componentConfiguration.autoplayViewProps.increaseMandatorySignY;\n\n        this.winMandatorySign.x =\n            this.singleWinLimitText.textWidth + this.componentConfiguration.autoplayViewProps.winMandatorySignX;\n        this.winMandatorySign.y = this.componentConfiguration.autoplayViewProps.winMandatorySignY;\n    }\n\n    protected initialRender(): void {\n        this.startAutoplayButton = new Button([\n            Core.assets.getAsset(\n                this.componentConfiguration.autoplayViewProps.startAutoplayButtonTextures[ButtonStates.Normal],\n            ).texture,\n            Core.assets.getAsset(\n                this.componentConfiguration.autoplayViewProps.startAutoplayButtonTextures[ButtonStates.Pressed],\n            ).texture,\n            Core.assets.getAsset(\n                this.componentConfiguration.autoplayViewProps.startAutoplayButtonTextures[ButtonStates.Normal],\n            ).texture,\n            Core.assets.getAsset(\n                this.componentConfiguration.autoplayViewProps.startAutoplayButtonTextures[ButtonStates.Disabled],\n            ).texture,\n        ]);\n        this.startAutoplayButton.name = 'startAutoplayButton';\n\n        this.setTextsConfigs();\n\n        this.decreaseMandatorySign = new Text(this.mandatorySignConfig, '*', this.mandatorySignStyle);\n        this.increaseMandatorySign = new Text(this.mandatorySignConfig, '*', this.mandatorySignStyle);\n        this.winMandatorySign = new Text(this.mandatorySignConfig, '*', this.mandatorySignStyle);\n\n        this.numberOfSpinsText = new Text(\n            this.spinsConfig,\n            Core.translator.translate('NUMBER OF SPINS'),\n            this.spinsStyle,\n        );\n        const noLimitText = Core.translator.translate('NO LIMIT');\n        if (this.numberOfSpinsValues.indexOf(0) !== -1) {\n            this.numberOfSpinsValue = new Text(this.spinsValueConfig, noLimitText, this.spinsValueStyle);\n        } else {\n            this.numberOfSpinsValue = new Text(\n                this.spinsValueConfig,\n                this.numberOfSpinsValues[0].toString(),\n                this.spinsValueStyle,\n            );\n        }\n        this.addChild(this.numberOfSpinsText);\n        this.headers.push(this.numberOfSpinsText);\n\n        this.addChild(this.numberOfSpinsValue);\n\n        // const stopOnStyle = Object.assign({}, this.decreaseStyle);\n        // stopOnStyle.fontWeight = 'bold';\n\n        this.stopOnText = new Text(this.decreaseConfig, Core.translator.translate('STOP ON'), this.stopOnStyle);\n        this.addChild(this.stopOnText);\n        this.balanceDecreaseText = new Text(\n            this.decreaseConfig,\n            Core.translator.translate('LOSS LIMIT'),\n            this.decreaseStyle,\n        );\n        this.balanceDecreaseText.addChild(this.decreaseMandatorySign);\n        // if (this.stopOnText.width > 150) {\n        //     this.stopOnText.style.fontSize = 32;\n        // }\n        if (this.settings.autoplayRestrictions.mandatory.indexOf('lossLimits') === -1) {\n            this.decreaseMandatorySign.visible = false;\n        }\n\n        this.addChild(this.balanceDecreaseText);\n        this.headers.push(this.balanceDecreaseText);\n\n        this.balanceDecreaseValue = new MoneyText(this.limitsValuesConfig, 0, this.decreaseValueStyle);\n        this.addChild(this.balanceDecreaseValue);\n        this.values.push(this.balanceDecreaseValue);\n\n        this.balanceDecreaseZeroValue = new Text(this.noLimitConfig, noLimitText, this.zeroValueStyle);\n        this.addChild(this.balanceDecreaseZeroValue);\n        this.values.push(this.balanceDecreaseZeroValue);\n\n        this.balanceIncreaseText = new Text(\n            this.increaseConfig,\n            Core.translator.translate('WINS LIMIT'),\n            this.increaseStyle,\n        );\n\n        this.balanceIncreaseText.addChild(this.increaseMandatorySign);\n        if (this.settings.autoplayRestrictions.mandatory.indexOf('winLimits') === -1) {\n            this.increaseMandatorySign.visible = false;\n        }\n\n        this.addChild(this.balanceIncreaseText);\n        this.headers.push(this.balanceIncreaseText);\n\n        this.balanceIncreaseValue = new MoneyText(this.limitsValuesConfig, 0, this.increaseValueStyle);\n        this.addChild(this.balanceIncreaseValue);\n        this.values.push(this.balanceIncreaseValue);\n\n        this.balanceIncreaseZeroValue = new Text(this.noLimitConfig, noLimitText, this.zeroValueStyle);\n        this.values.push(this.balanceIncreaseZeroValue);\n        this.addChild(this.balanceIncreaseZeroValue);\n\n        this.singleWinLimitText = new Text(\n            this.singleWinConfig,\n            Core.translator.translate('STOP ON WIN'),\n            this.singleWinStyle,\n        );\n\n        this.singleWinLimitText.addChild(this.winMandatorySign);\n        if (this.settings.autoplayRestrictions.mandatory.indexOf('singleWinLimit') === -1) {\n            this.winMandatorySign.visible = false;\n        }\n\n        this.addChild(this.singleWinLimitText);\n        this.headers.push(this.singleWinLimitText);\n\n        this.singleWinLimitValue = new MoneyText(this.limitsValuesConfig, 0, this.singleWinValueStyle);\n        this.addChild(this.singleWinLimitValue);\n        this.values.push(this.singleWinLimitValue);\n\n        this.singleWinZeroValue = new Text(this.noLimitConfig, noLimitText, this.zeroValueStyle);\n        this.values.push(this.singleWinZeroValue);\n        this.addChild(this.singleWinZeroValue);\n\n        this.startAutoplayButton.CLICK.pipe(takeUntil(this.DESTROY)).subscribe(this.startAutoplayFromMenu.bind(this));\n\n        this.startButtonText = new Text(\n            this.startButtonTextConfig,\n            Core.translator.translate('START AUTOPLAY'),\n            this.startButtonTextStyle,\n        );\n        this.startAutoplayButton.addChild(this.startButtonText);\n\n        this.addChild(this.startAutoplayButton);\n\n        this.infinityValueTexture = new Sprite();\n        this.infinityValueTexture.texture = Core.assets.getAsset(\n            this.componentConfiguration.autoplayViewProps.infinityValueTexture,\n        ).texture;\n        this.infinityValueTexture.tint = this.colorValues;\n        this.infinityValueTexture.visible = false;\n        this.addChild(this.infinityValueTexture);\n\n        this.balanceContainer = new ViewContainer();\n\n        this.balanceText = new Text(\n            this.balanceTextConfig,\n            Core.translator.translate('BALANCE') + ':',\n            this.balanceTextStyle,\n        );\n        this.balanceValue = new MoneyText(\n            this.balanceValueConfig,\n            this.rootStore.uiStore.BALANCE.value,\n            this.balanceValueStyle,\n        );\n\n        this.balanceContainer.addChild(this.balanceText);\n        this.balanceContainer.addChild(this.balanceValue);\n        this.addChild(this.balanceContainer);\n\n        this.betContainer = new ViewContainer();\n\n        this.betText = new Text(this.betTextConfig, Core.translator.translate('BET') + ':', this.betTextStyle);\n\n        this.betValue = new MoneyText(this.betValueConfig, this.getTotalBet(), this.betValueStyle);\n        this.betContainer.addChild(this.betText);\n        this.betContainer.addChild(this.betValue);\n        this.addChild(this.betContainer);\n\n        let inactiveDotTexture;\n        let activeDotTexture;\n        if (this.componentConfiguration.autoplayViewProps.useTexturesForDots) {\n            inactiveDotTexture = Core.assets.getAsset(\n                this.componentConfiguration.autoplayViewProps.inactiveDotTexture,\n            ).texture;\n            activeDotTexture = Core.assets.getAsset(\n                this.componentConfiguration.autoplayViewProps.activeDotTexture,\n            ).texture;\n        }\n\n        let sliderNotSelectedTexture;\n        let sliderSelectedTexture;\n        if (this.componentConfiguration.autoplayViewProps.useCanvasForSliders) {\n            let canvas = document.createElement('canvas');\n            canvas.height = this.sliderHeight;\n            canvas.width = this.sliderWidth;\n            const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;\n\n            const inactiveGradient = ctx.createLinearGradient(0, 0, 0, this.sliderHeight);\n            for (let i = 0; i < this.componentConfiguration.autoplayViewProps.canvasSlidersNumberOfStops; i++) {\n                inactiveGradient.addColorStop(\n                    this.componentConfiguration.autoplayViewProps.canvasNotSelectedSliderStops[i],\n                    this.componentConfiguration.autoplayViewProps.canvasNotSelectedSlidersColors[i],\n                );\n            }\n            ctx.fillStyle = inactiveGradient;\n            ctx.fillRect(0, 0, this.sliderWidth, this.sliderHeight);\n\n            sliderNotSelectedTexture = Texture.from(canvas);\n            canvas.remove();\n            // @ts-ignore\n            canvas = null;\n\n            let canvas2 = document.createElement('canvas');\n            canvas2.height = this.sliderHeight;\n            canvas2.width = this.sliderWidth;\n            const ctx2 = canvas2.getContext('2d') as CanvasRenderingContext2D;\n\n            const activeGradient = ctx2.createLinearGradient(0, 0, 0, this.sliderHeight);\n            for (let i = 0; i < this.componentConfiguration.autoplayViewProps.canvasSlidersNumberOfStops; i++) {\n                activeGradient.addColorStop(\n                    this.componentConfiguration.autoplayViewProps.canvasSelectedSliderStops[i],\n                    this.componentConfiguration.autoplayViewProps.canvasSelectedSlidersColors[i],\n                );\n            }\n            ctx2.fillStyle = activeGradient;\n            ctx2.fillRect(0, 0, this.sliderWidth, this.sliderHeight);\n\n            sliderSelectedTexture = Texture.from(canvas2);\n            canvas2.remove();\n            // @ts-ignore\n            canvas2 = null;\n        }\n\n        this.spinsSliderContainer = new ViewContainer();\n        this.spinsSliderContainer.name = 'numberOfSpinsSlider';\n        this.spinsSlider = new SteppedSlider({\n            sliderWidth: this.sliderWidth,\n            sliderHeight: this.sliderHeight,\n            minValue: this.numberOfSpinsValues[0],\n            stepsNotSelectedTexture: sliderNotSelectedTexture,\n            stepsSelectedTexture: sliderSelectedTexture,\n            inactiveHandleTexture: Core.assets.getAsset(\n                this.componentConfiguration.autoplayViewProps.inactiveHandleTexture[0],\n            ).texture,\n            activeHandleTexture: Core.assets.getAsset(this.componentConfiguration.autoplayViewProps.activeHandleTexture)\n                .texture,\n            inactiveDotTexture,\n            activeDotTexture,\n            steps: this.numberOfSpinsValues,\n            notSelectedFill: this.componentConfiguration.autoplayViewProps.slidersNotSelectedColor,\n            selectedFill: this.componentConfiguration.autoplayViewProps.slidersSelectedColor,\n        });\n        this.spinsSliderContainer.addChild(this.spinsSlider);\n\n        this.spinsSlider.CHANGE.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            if (this.spinsSlider.CHANGE.value === -1) {\n                this.numberOfSpinsValue.visible = false;\n                this.infinityValueTexture.visible = true;\n            } else {\n                this.numberOfSpinsValue.visible = true;\n                this.infinityValueTexture.visible = false;\n                this.numberOfSpinsValue.text =\n                    this.spinsSlider.CHANGE.value > 0 ? this.spinsSlider.CHANGE.value.toString() : noLimitText;\n            }\n\n            this.makeSpinsSelection(this.spinsSlider.CHANGE.value);\n        });\n\n        this.spinsSlider.init();\n\n        //\n\n        this.lossSliderContainer = new ViewContainer();\n        this.lossSliderContainer.name = 'lossSlider';\n        const minBalanceValue = (this.getCurrentBalance() * this.balanceDecreaseValues) / 100;\n        this.lossSlider = new SteppedSlider({\n            sliderWidth: this.sliderWidth,\n            sliderHeight: this.sliderHeight,\n            minValue: 0,\n            stepsNotSelectedTexture: sliderNotSelectedTexture,\n            stepsSelectedTexture: sliderSelectedTexture,\n            useSteps: false,\n            inactiveHandleTexture:\n                this.settings.autoplayRestrictions.mandatory.indexOf('lossLimits') !== -1\n                    ? Core.assets.getAsset(this.componentConfiguration.autoplayViewProps.inactiveHandleTexture[0])\n                          .texture\n                    : Core.assets.getAsset(this.componentConfiguration.autoplayViewProps.inactiveHandleTexture[1])\n                          .texture,\n            activeHandleTexture: Core.assets.getAsset(this.componentConfiguration.autoplayViewProps.activeHandleTexture)\n                .texture,\n            inactiveDotTexture,\n            activeDotTexture,\n            steps: [0, minBalanceValue],\n            notSelectedFill: this.componentConfiguration.autoplayViewProps.slidersNotSelectedColor,\n            selectedFill: this.componentConfiguration.autoplayViewProps.slidersSelectedColor,\n        });\n        this.lossSliderContainer.addChild(this.lossSlider);\n        this.lossSlider.init();\n\n        this.lossSlider.CHANGE.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            if (this.lossSlider.CHANGE.value === 0) {\n                this.balanceDecreaseValue.visible = false;\n                this.balanceDecreaseValue.money = 0;\n                this.balanceDecreaseZeroValue.visible = true;\n            } else {\n                this.balanceDecreaseZeroValue.visible = false;\n                this.balanceDecreaseValue.visible = true;\n                this.balanceDecreaseValue.money = this.lossSlider.CHANGE.value;\n            }\n            this.makeDecreaseSelection(this.balanceDecreaseValue.money);\n        });\n\n        this.winsSliderContainer = new ViewContainer();\n        this.winsSliderContainer.name = 'winsSlider';\n        const maxBalanceValue =\n            (this.getCurrentBalance() * this.balanceIncreaseValues) / 100 - this.getCurrentBalance();\n        this.winsSlider = new SteppedSlider({\n            sliderWidth: this.sliderWidth,\n            sliderHeight: this.sliderHeight,\n            minValue: 0,\n            stepsNotSelectedTexture: sliderNotSelectedTexture,\n            stepsSelectedTexture: sliderSelectedTexture,\n            inactiveHandleTexture:\n                this.settings.autoplayRestrictions.mandatory.indexOf('winLimits') !== -1\n                    ? Core.assets.getAsset(this.componentConfiguration.autoplayViewProps.inactiveHandleTexture[0])\n                          .texture\n                    : Core.assets.getAsset(this.componentConfiguration.autoplayViewProps.inactiveHandleTexture[1])\n                          .texture,\n            activeHandleTexture: Core.assets.getAsset(this.componentConfiguration.autoplayViewProps.activeHandleTexture)\n                .texture,\n            steps: [0, maxBalanceValue],\n            inactiveDotTexture,\n            activeDotTexture,\n            useSteps: false,\n            notSelectedFill: this.componentConfiguration.autoplayViewProps.slidersNotSelectedColor,\n            selectedFill: this.componentConfiguration.autoplayViewProps.slidersSelectedColor,\n        });\n\n        this.winsSliderContainer.addChild(this.winsSlider);\n        this.winsSlider.init();\n\n        this.winsSlider.CHANGE.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            if (this.winsSlider.CHANGE.value === 0) {\n                this.balanceIncreaseZeroValue.visible = true;\n                this.balanceIncreaseValue.money = 0;\n            } else {\n                this.balanceIncreaseZeroValue.visible = false;\n                this.balanceIncreaseValue.money = this.getCurrentBalance() + this.winsSlider.CHANGE.value;\n            }\n            this.makeIncreaseSelection(this.balanceIncreaseValue.money);\n        });\n\n        this.singleWinSliderContainer = new ViewContainer();\n        this.singleWinSliderContainer.name = 'singleWinSlider';\n\n        this.singleWinSlider = new SteppedSlider({\n            sliderWidth: this.sliderWidth,\n            sliderHeight: this.sliderHeight,\n            minValue: 0,\n            stepsNotSelectedTexture: sliderNotSelectedTexture,\n            stepsSelectedTexture: sliderSelectedTexture,\n            inactiveHandleTexture:\n                this.settings.autoplayRestrictions.mandatory.indexOf('singleWinLimit') !== -1\n                    ? Core.assets.getAsset(this.componentConfiguration.autoplayViewProps.inactiveHandleTexture[0])\n                          .texture\n                    : Core.assets.getAsset(this.componentConfiguration.autoplayViewProps.inactiveHandleTexture[1])\n                          .texture,\n            activeHandleTexture: Core.assets.getAsset(this.componentConfiguration.autoplayViewProps.activeHandleTexture)\n                .texture,\n            steps: [0, this.singleWinLimitValues],\n            useSteps: false,\n            inactiveDotTexture,\n            activeDotTexture,\n            notSelectedFill: this.componentConfiguration.autoplayViewProps.slidersNotSelectedColor,\n            selectedFill: this.componentConfiguration.autoplayViewProps.slidersSelectedColor,\n        });\n        this.singleWinSliderContainer.addChild(this.singleWinSlider);\n        this.singleWinSlider.init();\n\n        this.singleWinSlider.CHANGE.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            if (this.singleWinSlider.CHANGE.value === 0) {\n                this.singleWinZeroValue.visible = true;\n                this.singleWinLimitValue.money = 0;\n            } else {\n                this.singleWinZeroValue.visible = false;\n                this.singleWinLimitValue.money = this.singleWinSlider.CHANGE.value;\n            }\n            this.makeWinLimitSelection(this.singleWinLimitValue.money);\n        });\n        this.addChild(this.spinsSliderContainer);\n        this.addChild(this.lossSliderContainer);\n        this.addChild(this.winsSliderContainer);\n        this.addChild(this.singleWinSliderContainer);\n        this.setOrientation(Core.ORIENTATION.value);\n    }\n\n    protected startAutoplayFromMenu(numberOfFreeSpins?: number): void {\n        const freeSpinsCount = numberOfFreeSpins ? numberOfFreeSpins : this.spinsSlider.CHANGE.value;\n        if (this.settings.settings.settings.jurisdiction?.autoplayRestrictions?.confirmationModal) {\n            const modalData = this.rootStore.getModalData(freeSpinsCount);\n            const messData = {} as IErrorData;\n\n            (messData.code = Core.translator\n                .translate('AUTOPLAY.MODAL.MESSAGE')\n                .replace('<<totalAmount>>', modalData.totalBetAmount.toString().replace(/\\s+/g, '\\u00A0'))\n\n                .replace('<<numberOfSpins>>', freeSpinsCount.toString())\n                .replace('<<betAmount>>', modalData.betAmount)),\n                (messData.btnText = Core.translator.translate('AUTOPLAY.MODAL.CANCEL_BUTTON')),\n                (messData.type = ErrorTypes.CONFIRMATION),\n                (messData.hasConfirmButton = true),\n                (messData.confirmButtonText = Core.translator.translate('AUTOPLAY.MODAL.CONFIRM_BUTTON')),\n                (messData.callback = this.confirmStartAutoplay.bind(this)),\n                Core.SHOW_ERROR.next(messData);\n            return;\n        }\n\n        this.confirmStartAutoplay();\n    }\n\n    protected confirmStartAutoplay(): void {\n        if (this.VISIBLE.value) {\n            (this.parent as SettingsPopup).clearTabSelection();\n            this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.next(this.autoSpinsSelected);\n            this.rootStore.subjects.CLOSE_SETTINGS_POPUP.next();\n            this.rootStore.uiStore.SHOW_SETTINGS.next(false);\n            this.rootStore.subjects.START_AUTOPLAY.next(this.autoSpinsSelected);\n            this.rootStore.subjects.SETTINGS_POPUP_CLOSED.next();\n        }\n    }\n\n    protected makeDecreaseSelection(value: number): void {\n        if (value > 0) {\n            this.onFieldSelected('lossLimits');\n        } else {\n            this.onFieldDeselected('lossLimits');\n        }\n        this.rootStore.uiStore.balanceDecreaseValue = value * this.rootStore.uiStore.units;\n        this.setAutoplayState();\n    }\n\n    protected getCurrentBalance(): number {\n        return this.rootStore.uiStore.BALANCE.value;\n    }\n\n    protected makeWinLimitSelection(value: number): void {\n        if (value > 0) {\n            this.onFieldSelected('singleWinLimit');\n        } else {\n            this.onFieldDeselected('singleWinLimit');\n        }\n\n        this.rootStore.uiStore.winLimitValue = value * this.rootStore.uiStore.units;\n        this.setAutoplayState();\n    }\n\n    protected makeIncreaseSelection(value: number): void {\n        if (value > 0) {\n            this.onFieldSelected('winLimits');\n        } else {\n            this.onFieldDeselected('winLimits');\n        }\n        this.rootStore.uiStore.balanceIncreaseValue = value * this.rootStore.uiStore.units;\n        this.setAutoplayState();\n    }\n\n    protected makeSpinsSelection(value: number): void {\n        this.autoSpinsSelected = value;\n        this.setAutoplayState();\n    }\n\n    protected onBalanceChange(): void {\n        if (this.balanceValue) {\n            this.balanceValue.money = this.rootStore.uiStore.BALANCE.value;\n        }\n\n        const minBalanceValue = (this.getCurrentBalance() * this.balanceDecreaseValues) / 100;\n        this.lossSlider.steps = [0, minBalanceValue];\n        if (this.lossSlider.getSliderValue() !== 0) {\n            this.balanceDecreaseValue.money = this.lossSlider.getSliderValue();\n        }\n        const maxBalanceValue =\n            (this.getCurrentBalance() * this.balanceIncreaseValues) / 100 - this.getCurrentBalance();\n        this.winsSlider.steps = [0, maxBalanceValue];\n        if (this.winsSlider.getSliderValue() !== 0) {\n            this.balanceIncreaseValue.money = this.balanceIncreaseValue.money =\n                this.getCurrentBalance() + this.winsSlider.getSliderValue();\n        }\n    }\n\n    protected resetAutoPlayRestrictions(): void {\n        this.spinsSlider.resetSlider();\n        this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.next(0);\n        this.rootStore.uiStore.autoPlayFromSettings = false;\n        this.lossSlider.resetSlider();\n        this.winsSlider.resetSlider();\n        this.singleWinSlider.resetSlider();\n    }\n\n    protected setAutoplayState(): void {\n        if (\n            (this.autoSpinsSelected > 0 || this.autoSpinsSelected === -1) &&\n            this.selectedMandatoryFields.length === this.settings.autoplayRestrictions.mandatory.length\n            // && !this.feature.isInGiftSpins\n        ) {\n            this.setAutoplayFromSettings(this.autoSpinsSelected);\n            this.setAutoplayButtonState(true);\n        } else {\n            this.setAutoplayFromSettings(0);\n            this.setAutoplayButtonState(false);\n        }\n    }\n\n    protected setTextsConfigs(): void {\n        this.limitsValuesConfig.bounds.width =\n            Core.display.stage.width / this.componentConfiguration.autoplayViewProps.valuesWidthDevider -\n            this.componentConfiguration.autoplayViewProps.limitsValuesConfig.boundsWidth;\n        this.limitsValuesConfig.bounds.height =\n            this.componentConfiguration.autoplayViewProps.limitsValuesConfig.boundsHeight;\n        this.limitsValuesConfig.minFontSize =\n            this.componentConfiguration.autoplayViewProps.limitsValuesConfig.minFontSize;\n        this.limitsValuesConfig.shouldFitInBounds =\n            this.componentConfiguration.autoplayViewProps.limitsValuesConfig.shouldFitInBounds;\n        this.limitsValuesConfig.align = this.componentConfiguration.autoplayViewProps.limitsValuesConfig.align;\n        this.limitsValuesConfig.shouldHideWhenMoneyValueIsZero =\n            this.componentConfiguration.autoplayViewProps.limitsValuesConfig.shouldHideWhenMoneyValueIsZero;\n        // this.limitsValuesConfig.showRoundedValue = false;\n        this.limitsValuesConfig.useMoneyMode =\n            this.componentConfiguration.autoplayViewProps.limitsValuesConfig.useMoneyMode;\n        this.limitsValuesConfig.moneyFontSize =\n            this.componentConfiguration.autoplayViewProps.limitsValuesConfig.moneyFontSize;\n        this.limitsValuesConfig.centsFontSize =\n            this.componentConfiguration.autoplayViewProps.limitsValuesConfig.centsFontSize;\n        this.limitsValuesConfig.currencyFontSize =\n            this.componentConfiguration.autoplayViewProps.limitsValuesConfig.currencyFontSize;\n\n        this.noLimitConfig.bounds.width =\n            Core.display.stage.width / this.componentConfiguration.autoplayViewProps.valuesWidthDevider -\n            this.componentConfiguration.autoplayViewProps.noLimitConfig.boundsWidth;\n        this.noLimitConfig.bounds.height = this.componentConfiguration.autoplayViewProps.noLimitConfig.boundsHeight;\n        this.noLimitConfig.minFontSize = this.componentConfiguration.autoplayViewProps.noLimitConfig.minFontSize;\n        this.noLimitConfig.align = this.componentConfiguration.autoplayViewProps.noLimitConfig.align;\n\n        this.spinsConfig.bounds.width =\n            Core.display.stage.width / this.componentConfiguration.autoplayViewProps.headersWidthDevider -\n            this.componentConfiguration.autoplayViewProps.spinsConfig.boundsWidth;\n        this.spinsConfig.bounds.height = this.componentConfiguration.autoplayViewProps.spinsConfig.boundsHeight;\n        this.spinsConfig.minFontSize = this.componentConfiguration.autoplayViewProps.spinsConfig.minFontSize;\n        this.spinsConfig.shouldFitInBounds =\n            this.componentConfiguration.autoplayViewProps.spinsConfig.shouldFitInBounds;\n\n        this.decreaseConfig.bounds.width =\n            Core.display.stage.width / this.componentConfiguration.autoplayViewProps.headersWidthDevider -\n            this.componentConfiguration.autoplayViewProps.decreaseConfig.boundsWidth;\n        this.decreaseConfig.bounds.height = this.componentConfiguration.autoplayViewProps.decreaseConfig.boundsHeight;\n        this.decreaseConfig.minFontSize = this.componentConfiguration.autoplayViewProps.decreaseConfig.minFontSize;\n        this.decreaseConfig.shouldFitInBounds =\n            this.componentConfiguration.autoplayViewProps.decreaseConfig.shouldFitInBounds;\n\n        this.increaseConfig.bounds.width =\n            Core.display.stage.width / this.componentConfiguration.autoplayViewProps.headersWidthDevider -\n            this.componentConfiguration.autoplayViewProps.increaseConfig.boundsWidth;\n        this.increaseConfig.bounds.height = this.componentConfiguration.autoplayViewProps.increaseConfig.boundsHeight;\n        this.increaseConfig.minFontSize = this.componentConfiguration.autoplayViewProps.increaseConfig.minFontSize;\n        this.increaseConfig.shouldFitInBounds =\n            this.componentConfiguration.autoplayViewProps.increaseConfig.shouldFitInBounds;\n\n        this.singleWinConfig.bounds.width =\n            Core.display.stage.width / this.componentConfiguration.autoplayViewProps.headersWidthDevider -\n            this.componentConfiguration.autoplayViewProps.singleWinConfig.boundsWidth;\n        this.singleWinConfig.bounds.height = this.componentConfiguration.autoplayViewProps.singleWinConfig.boundsHeight;\n        this.singleWinConfig.minFontSize = this.componentConfiguration.autoplayViewProps.singleWinConfig.minFontSize;\n        this.singleWinConfig.shouldFitInBounds =\n            this.componentConfiguration.autoplayViewProps.singleWinConfig.shouldFitInBounds;\n\n        this.spinsValueConfig.bounds.width =\n            Core.display.stage.width / 10 - this.componentConfiguration.autoplayViewProps.spinsValueConfig.boundsWidth;\n        this.spinsValueConfig.bounds.height =\n            this.componentConfiguration.autoplayViewProps.spinsValueConfig.boundsHeight;\n        this.spinsValueConfig.minFontSize = this.componentConfiguration.autoplayViewProps.spinsValueConfig.minFontSize;\n        this.spinsValueConfig.shouldFitInBounds =\n            this.componentConfiguration.autoplayViewProps.spinsValueConfig.shouldFitInBounds;\n        this.spinsValueConfig.align = this.componentConfiguration.autoplayViewProps.spinsValueConfig.align;\n\n        // this.startButtonTextConfig.bounds.width = this.componentConfiguration.autoplayViewProps.startButtonTextConfig.boundsWidth;\n        this.startButtonTextConfig.bounds.width =\n            this.startAutoplayButton.width -\n            this.componentConfiguration.autoplayViewProps.startButtonTextConfig.boundsWidth;\n        this.startButtonTextConfig.bounds.height =\n            this.componentConfiguration.autoplayViewProps.startButtonTextConfig.boundsHeight;\n        this.startButtonTextConfig.minFontSize =\n            this.componentConfiguration.autoplayViewProps.startButtonTextConfig.minFontSize;\n        this.startButtonTextConfig.shouldFitInBounds =\n            this.componentConfiguration.autoplayViewProps.startButtonTextConfig.shouldFitInBounds;\n        this.startButtonTextConfig.align = this.componentConfiguration.autoplayViewProps.startButtonTextConfig.align;\n\n        this.balanceValueConfig.currency =\n            this.betValueConfig.currency =\n            this.limitsValuesConfig.currency =\n                this.rootStore.uiStore.currency;\n        this.balanceValueConfig.bounds.width =\n            this.componentConfiguration.autoplayViewProps.balanceValueConfig.boundsWidth;\n        this.betValueConfig.bounds.width = this.componentConfiguration.autoplayViewProps.betValueConfig.boundsWidth;\n\n        this.balanceValueConfig.moneyFontSize =\n            this.balanceValueConfig.centsFontSize =\n            this.betValueConfig.centsFontSize =\n            this.betValueConfig.moneyFontSize =\n                22;\n        this.balanceValueConfig.bounds.height =\n            this.betValueConfig.bounds.height =\n            this.betTextConfig.bounds.height =\n            this.balanceTextConfig.bounds.height =\n                50;\n        this.balanceValueConfig.spaceBetweenMoneyAndCurrency = this.betValueConfig.spaceBetweenMoneyAndCurrency = 4;\n\n        this.mandatorySignConfig.bounds.width =\n            this.componentConfiguration.autoplayViewProps.mandatorySignConfig.boundsWidth;\n        this.mandatorySignConfig.shouldFitInBounds =\n            this.componentConfiguration.autoplayViewProps.mandatorySignConfig.shouldFitInBounds;\n        this.mandatorySignConfig.align = this.componentConfiguration.autoplayViewProps.mandatorySignConfig.align;\n    }\n\n    // TODO: Export this in UTIL, it is used in a lot of classes\n    protected getTotalBet(): number {\n        const factor = this.rootStore.settings.factor\n            ? this.rootStore.settings.factor\n            : this.rootStore.uiStore.LINES.value;\n        return Core.SELECTED_DENOMINATION.value * this.rootStore.uiStore.SELECTED_BET.value * factor;\n    }\n\n    private stateChanged(): void {\n        /*  if (this.rootStore.uiStore.STATE.value === UIState.BONUS_IDLE || this.feature.isInGiftSpins) {\n            this.setAutoplayButtonState(false);\n            this.stateDisabled = true;\n        } else { */\n        if (this.settings.autoplayRestrictions.mandatory.length === 0) {\n            this.setAutoplayButtonState(true);\n        }\n        if (this.stateDisabled) {\n            this.setAutoplayState();\n            this.stateDisabled = false;\n        }\n    }\n\n    private setAutoplayFromSettings(value: number): void {\n        if (value > 0) {\n            this.rootStore.uiStore.autoPlayFromSettings = true;\n        } else {\n            this.rootStore.uiStore.autoPlayFromSettings = false;\n        }\n    }\n\n    private setAutoplayButtonState(active: boolean): void {\n        if (active) {\n            // && this.rootStore.uiStore.STATE.value !== UIState.BONUS_IDLE\n            this.startAutoplayButton.enabled = true;\n            this.startButtonText.alpha = this.componentConfiguration.autoplayViewProps.startButtonTextActiveAlpha;\n        } else {\n            this.startAutoplayButton.enabled = false;\n            this.startButtonText.alpha = this.componentConfiguration.autoplayViewProps.startButtonTextInactiveAlpha;\n        }\n    }\n\n    private onBetChange(): void {\n        if (this.betValue) {\n            this.betValue.money = this.getTotalBet();\n        }\n        this.singleWinLimitValues = this.getTotalBet() * this.settings.autoplayRestrictions.singleWinLimit;\n\n        this.singleWinSlider.steps = [0, this.singleWinLimitValues];\n        if (this.feature.isInGiftSpins) {\n            return;\n        }\n        this.singleWinSlider.resetSlider();\n    }\n\n    private onFieldSelected(fieldName: string): void {\n        if (\n            this.settings.autoplayRestrictions.mandatory.length > 0 &&\n            this.settings.autoplayRestrictions.mandatory.indexOf(fieldName) !== -1 &&\n            this.selectedMandatoryFields.indexOf(fieldName) === -1\n        ) {\n            this.selectedMandatoryFields.push(fieldName);\n        }\n        if (this.settings.autoplayRestrictions.mandatory.length === this.selectedMandatoryFields.length) {\n            this.rootStore.uiStore.allRestrictionsApplied = true;\n        }\n    }\n\n    private onFieldDeselected(fieldName: string): void {\n        if (this.selectedMandatoryFields.length > 0 && this.selectedMandatoryFields.indexOf(fieldName) !== -1) {\n            this.selectedMandatoryFields.splice(this.selectedMandatoryFields.indexOf(fieldName), 1);\n        }\n\n        if (\n            this.settings.autoplayRestrictions.mandatory.length !== this.selectedMandatoryFields.length &&\n            this.settings.autoplayRestrictions.mandatory.length > 0\n        ) {\n            this.rootStore.uiStore.allRestrictionsApplied = false;\n        }\n    }\n}\n","import Core from '@egt/core';\nimport { FeatureController, InitialSettings, RootStore } from '@egt/slot';\nimport {\n    Button,\n    ITitledWindowConfig,\n    MoneyText,\n    SteppedSlider,\n    Text,\n    TextAlign,\n    TextConfig,\n    TitledWindow,\n    ValueButton,\n    ViewContainer,\n} from '@egt/ui-lib';\nimport { Graphics, Sprite, TextStyle } from 'pixi.js';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { ISettingsPopupComponentConfiguration } from '../../interfaces/SettingsInterfaces';\nimport SpinSettingsView from './SpinSettingsView';\n\n@injectable()\nexport default class SpinSettingsViewDesktop extends SpinSettingsView {\n    protected spinsButtons: ValueButton[];\n    protected buttonsOffset: number;\n    private filedsBorders: Graphics[];\n    private noLimitLabels: Text[];\n    private noLimitsConfig: TextConfig;\n    private noLimitsStyle: TextStyle;\n    private breakingLine: Sprite;\n    private infinitySprite: Sprite;\n    private menuBody: TitledWindow;\n    private config: any;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('FeatureController') protected feature: FeatureController,\n        @inject('SettingsPopupComponentConfiguration')\n        protected componentConfiguration: ISettingsPopupComponentConfiguration,\n    ) {\n        super(rootStore, settings, feature, componentConfiguration);\n    }\n\n    public init(): void {\n        super.init();\n        this.interactive = true;\n        this.rootStore.subjects.CLOSE_SETTINGS_POPUP.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            this.VISIBLE.next(false);\n        });\n    }\n\n    public get panelDimensions(): any {\n        return { width: 898, height: 646, topOffset: 6 };\n    }\n\n    protected setOrientation(): void {\n        const buttonsTopOffset: number = 30;\n        const slidersLeftOffset: number = (this.sliderContainerWidth - this.sliderContainerWidth) / 2;\n        const slidersTopOffset: number = (this.sliderContainerHeight - this.sliderHeight) / 2;\n\n        //\n        this.balanceDecreaseText.x = (this.panelDimensions.width - this.balanceDecreaseText.textBounds.width) / 2;\n        this.balanceDecreaseText.y = 78;\n\n        this.lossSliderContainer.x = (this.panelDimensions.width - this.sliderContainerWidth) / 2;\n        this.lossSliderContainer.y = 110;\n\n        this.lossSlider.x = slidersLeftOffset;\n        this.lossSlider.y = slidersTopOffset;\n\n        this.balanceDecreaseValue.x =\n            this.lossSliderContainer.x + this.lossSliderContainer.width - this.balanceDecreaseValue.textBounds.width;\n        this.balanceDecreaseValue.y = 148;\n        this.balanceIncreaseText.x = (this.panelDimensions.width - this.balanceIncreaseText.textBounds.width) / 2;\n        this.balanceIncreaseText.y = this.lossSliderContainer.y + this.lossSliderContainer.height + this.textTopOffset;\n\n        this.winsSliderContainer.x = (this.panelDimensions.width - this.sliderContainerWidth) / 2;\n        this.winsSliderContainer.y = 230;\n\n        this.winsSlider.x = slidersLeftOffset;\n        this.winsSlider.y = slidersTopOffset;\n\n        this.balanceIncreaseValue.x =\n            this.winsSliderContainer.x + this.winsSliderContainer.width - this.balanceIncreaseValue.textBounds.width;\n        this.balanceIncreaseValue.y = 268;\n        this.singleWinLimitText.x = (this.panelDimensions.width - this.singleWinLimitText.textBounds.width) / 2;\n        this.singleWinLimitText.y = this.winsSliderContainer.y + this.winsSliderContainer.height + this.textTopOffset;\n\n        this.singleWinLimitValue.x =\n            this.winsSliderContainer.x + this.winsSliderContainer.width - this.singleWinLimitValue.textBounds.width;\n        this.singleWinLimitValue.y = this.noLimitLabels[this.noLimitLabels.length - 1].y;\n\n        this.singleWinSliderContainer.x = (this.panelDimensions.width - this.sliderContainerWidth) / 2;\n        this.singleWinSliderContainer.y = 350;\n\n        this.singleWinSlider.x = slidersLeftOffset;\n        this.singleWinSlider.y = slidersTopOffset;\n\n        // //\n        this.numberOfSpinsText.x = (this.panelDimensions.width - this.numberOfSpinsText.textBounds.width) / 2;\n        this.numberOfSpinsText.y =\n            this.singleWinSliderContainer.y + this.singleWinSliderContainer.height + this.textTopOffset;\n\n        this.spinsButtons.forEach((spinBtn: ValueButton, index: number): void => {\n            spinBtn.x = this.getButtonsLeftOffset(this.spinsButtons) + index * (spinBtn.width + this.buttonsOffset);\n            spinBtn.y = this.numberOfSpinsText.y + this.numberOfSpinsText.style.lineHeight + buttonsTopOffset;\n        });\n\n        this.breakingLine.x = (this.panelDimensions.width - this.breakingLine.width) / 2;\n        this.breakingLine.y = this.panelDimensions.height - this.startAutoplayButton.height - 50;\n\n        // //\n        this.startAutoplayButton.x = (this.panelDimensions.width - this.startAutoplayButton.width) / 2;\n        this.startAutoplayButton.y = this.panelDimensions.height - this.startAutoplayButton.height - 32;\n\n        this.startButtonText.textBounds = { width: this.startAutoplayButton.width - 20, height: 26 };\n        this.startButtonText.pivot.set(\n            this.startButtonText.textBounds.width / 2,\n            this.startButtonText.textBounds.height / 2,\n        );\n        this.startButtonText.x = this.startAutoplayButton.width / 2;\n        this.startButtonText.y = this.startAutoplayButton.height / 2;\n        // this.startButtonText.y = (this.startAutoplayButton.height - this.startButtonText.height) / 2;\n\n        // this.singleWinZeroValue.x = this.singleWinLimitValue.x;\n        // this.singleWinZeroValue.y = this.singleWinLimitValue.y;\n\n        this.decreaseMandatorySign.x = (this.panelDimensions.width + this.balanceDecreaseText.textWidth) / 2;\n        this.decreaseMandatorySign.y = this.balanceDecreaseText.y;\n\n        this.increaseMandatorySign.x = (this.panelDimensions.width + this.balanceIncreaseText.textWidth) / 2;\n        this.increaseMandatorySign.y = this.balanceIncreaseText.y;\n\n        this.winMandatorySign.x = (this.panelDimensions.width + this.singleWinLimitText.textWidth) / 2;\n        this.winMandatorySign.y = this.singleWinLimitText.y;\n    }\n\n    protected createTextProps(): void {\n        // this.singleWinStyle.fill =\n        // this.increaseStyle.fill =\n        // this.decreaseStyle.fill = this.spinsStyle.fill = '#FFFFFF';\n        // this.singleWinStyle.fontFamily =\n        // this.increaseStyle.fontFamily =\n        // this.decreaseStyle.fontFamily =\n        // this.spinsStyle.fontFamily = 'FutunaPT-Book';\n        // this.singleWinStyle.fontWeight =\n        // this.increaseStyle.fontWeight =\n        // this.decreaseStyle.fontWeight =\n        // this.spinsStyle.fontWeight = 'bold';\n        // this.singleWinStyle.fontSize =\n        // this.increaseStyle.fontSize =\n        // this.decreaseStyle.fontSize =\n        // this.spinsStyle.fontSize = 11;\n        // this.singleWinStyle.padding =\n        // this.increaseStyle.padding =\n        // this.decreaseStyle.padding =\n        // this.spinsStyle.padding = 5;\n        // this.singleWinStyle = this.componentConfiguration.autoplayViewProps.singleWinStyle;\n        // this.increaseStyle = this.componentConfiguration.autoplayViewProps.increaseStyle;\n        // this.decreaseStyle = this.componentConfiguration.autoplayViewProps.decreaseStyle;\n        // this.spinsStyle = this.componentConfiguration.autoplayViewProps.spinsStyle;\n        // this.startButtonTextStyle = this.componentConfiguration.autoplayViewProps.startButtonTextStyle;\n\n        // this.decreaseValueStyle.fill = this.increaseValueStyle.fill = this.zeroValueStyle.fill = '#595959';\n        // this.singleWinValueStyle.fill = this.colorValues;\n        // this.decreaseValueStyle.fontFamily =\n        //     this.increaseValueStyle.fontFamily =\n        //     this.singleWinValueStyle.fontFamily =\n        //     this.zeroValueStyle.fontFamily =\n        //         'Arial';\n        // this.decreaseValueStyle.fontSize =\n        //     this.increaseValueStyle.fontSize =\n        //     this.singleWinValueStyle.fontSize =\n        //     this.zeroValueStyle.fontSize =\n        //         16;\n\n        this.singleWinConfig.bounds.width =\n            this.increaseConfig.bounds.width =\n            this.decreaseConfig.bounds.width =\n            this.spinsConfig.bounds.width =\n                540;\n        this.singleWinConfig.bounds.height =\n            this.increaseConfig.bounds.height =\n            this.decreaseConfig.bounds.height =\n            this.spinsConfig.bounds.height =\n                21;\n        this.singleWinConfig.minFontSize =\n            this.increaseConfig.minFontSize =\n            this.decreaseConfig.minFontSize =\n            this.spinsConfig.minFontSize =\n                16;\n        this.singleWinConfig.shouldFitInBounds =\n            this.increaseConfig.shouldFitInBounds =\n            this.decreaseConfig.shouldFitInBounds =\n            this.spinsConfig.shouldFitInBounds =\n                true;\n        this.singleWinConfig.align =\n            this.increaseConfig.align =\n            this.decreaseConfig.align =\n            this.spinsConfig.align =\n                TextAlign.CENTER;\n\n        this.startButtonTextConfig.bounds.width = 100;\n        this.startButtonTextConfig.bounds.height = 25;\n        this.startButtonTextConfig.minFontSize = 16;\n        this.startButtonTextConfig.shouldFitInBounds = true;\n        this.startButtonTextConfig.align = TextAlign.CENTER;\n\n        this.limitsValuesConfig.bounds.width = 80;\n        this.limitsValuesConfig.bounds.height = 20;\n        this.limitsValuesConfig.shouldFitInBounds = true;\n        this.limitsValuesConfig.align = TextAlign.CENTER;\n        this.limitsValuesConfig.shouldHideWhenMoneyValueIsZero = true;\n        this.limitsValuesConfig.showRoundedValue = false;\n        this.limitsValuesConfig.useMoneyMode = true;\n\n        this.limitsValuesConfig.moneyFontSize = 16;\n        this.limitsValuesConfig.centsFontSize = 16;\n        this.limitsValuesConfig.currencyFontSize = 10;\n\n        this.limitsValuesConfig.currency = this.rootStore.uiStore.currency;\n\n        // this.mandatorySignStyle.fill = '#FF0000';\n        // this.mandatorySignStyle.fontFamily = 'Arial';\n        // this.mandatorySignStyle.fontWeight = 'bold';\n        // this.mandatorySignStyle.fontSize = 20;\n\n        this.mandatorySignConfig.bounds.width = 20;\n        this.mandatorySignConfig.bounds.height = 20;\n        this.mandatorySignConfig.shouldFitInBounds = true;\n        this.mandatorySignConfig.align = TextAlign.CENTER;\n\n        this.noLimitsConfig = new TextConfig();\n        this.noLimitsConfig.debug = false;\n        this.noLimitsConfig.align = TextAlign.CENTER;\n        this.noLimitsConfig.bounds.width = 100;\n        this.noLimitsConfig.bounds.height = 20;\n        this.noLimitsConfig.shouldFitInBounds = true;\n\n        // this.noLimitsStyle = new TextStyle();\n        // this.noLimitsStyle.fill = '#767676';\n        // this.noLimitsStyle.fontFamily = 'FuturaPT';\n        // this.noLimitsStyle.fontSize = 16;\n        // this.noLimitsStyle.padding = 5;\n    }\n\n    protected initialRender(): void {\n        this.createTextProps();\n\n        this.config = {} as ITitledWindowConfig;\n\n        this.config.width = this.panelDimensions.width;\n        this.config.height = this.panelDimensions.height;\n        this.config.borderLeftUpTexture = Core.assets.getTextureFromSpriteSheet('miscellaneous', 'windowCornerLu.png');\n        this.config.title = Core.translator.translate('AUTOPLAY SETTINGS');\n        this.config.titleStyle = this.componentConfiguration.tabNameProps.textStyle;\n        this.menuBody = new TitledWindow(this.config);\n        this.menuBody.x = 0;\n        this.menuBody.y = 0;\n        this.menuBody.interactive = true;\n        this.addChild(this.menuBody);\n\n        this.buttonsOffset = 22;\n        this.textTopOffset = this.componentConfiguration.autoplayViewProps.textTopOffset;\n        this.sliderContainerWidth = this.panelDimensions.width - 296;\n        this.sliderContainerHeight = 30;\n        this.sliderTopOffset = 10;\n        this.sliderHeight = 4;\n\n        this.filedsBorders = [];\n        this.noLimitLabels = [];\n        this.infinitySprite = new Sprite();\n\n        for (let i = 0; i < 3; i++) {\n            const fieldBoard = new Graphics();\n            fieldBoard.lineStyle(1, 0x595959, undefined, undefined, true);\n            fieldBoard.beginFill(0x121212);\n            fieldBoard.drawRect((this.panelDimensions.width - 693) / 2, 75 + i * 120, 693, 102);\n            fieldBoard.endFill();\n            this.filedsBorders.push(fieldBoard);\n            this.addChild(fieldBoard);\n\n            const noLimitText = new Text(\n                this.noLimitsConfig,\n                Core.translator.translate('NO LIMIT'),\n                this.componentConfiguration.autoplayViewProps.zeroValueStyle,\n            );\n            noLimitText.x = 110;\n            noLimitText.y = 75 + i * 120 + 74;\n            this.noLimitLabels.push(noLimitText);\n            this.addChild(noLimitText);\n        }\n\n        this.decreaseMandatorySign = new Text(\n            this.mandatorySignConfig,\n            '*',\n            this.componentConfiguration.autoplayViewProps.mandatorySignStyle,\n        );\n        this.increaseMandatorySign = new Text(\n            this.mandatorySignConfig,\n            '*',\n            this.componentConfiguration.autoplayViewProps.mandatorySignStyle,\n        );\n        this.winMandatorySign = new Text(\n            this.mandatorySignConfig,\n            '*',\n            this.componentConfiguration.autoplayViewProps.mandatorySignStyle,\n        );\n\n        this.numberOfSpinsText = new Text(\n            this.spinsConfig,\n            Core.translator.translate('NUMBER OF SPINS').toUpperCase(),\n            this.spinsStyle,\n        );\n\n        this.addChild(this.numberOfSpinsText);\n\n        const stopOnText = Core.translator.translate('STOP ON').toUpperCase();\n        this.balanceDecreaseText = new Text(\n            this.decreaseConfig,\n            stopOnText + ' ' + Core.translator.translate('LOSS LIMIT').toUpperCase(),\n            this.decreaseStyle,\n        );\n        this.addChild(this.decreaseMandatorySign);\n        if (this.settings.autoplayRestrictions.mandatory.indexOf('lossLimits') === -1) {\n            this.decreaseMandatorySign.visible = false;\n        }\n\n        this.addChild(this.balanceDecreaseText);\n\n        this.balanceIncreaseText = new Text(\n            this.increaseConfig,\n            stopOnText + ' ' + Core.translator.translate('WINS LIMIT').toUpperCase(),\n            this.increaseStyle,\n        );\n\n        this.addChild(this.increaseMandatorySign);\n        if (this.settings.autoplayRestrictions.mandatory.indexOf('winLimits') === -1) {\n            this.increaseMandatorySign.visible = false;\n        }\n\n        this.addChild(this.balanceIncreaseText);\n\n        this.limitsValuesConfig.shouldFitInBounds = false;\n        this.limitsValuesConfig.align = TextAlign.RIGHT;\n\n        this.balanceIncreaseValue = new MoneyText(this.limitsValuesConfig, 0, this.increaseValueStyle);\n        this.addChild(this.balanceIncreaseValue);\n        this.values.push(this.balanceIncreaseValue);\n\n        this.singleWinLimitText = new Text(\n            this.singleWinConfig,\n            stopOnText + ' ' + Core.translator.translate('STOP ON WIN').toUpperCase(),\n            this.singleWinStyle,\n        );\n\n        this.addChild(this.winMandatorySign);\n        if (this.settings.autoplayRestrictions.mandatory.indexOf('singleWinLimit') === -1) {\n            this.winMandatorySign.visible = false;\n        }\n\n        this.addChild(this.singleWinLimitText);\n\n        this.singleWinLimitValue = new MoneyText(this.limitsValuesConfig, 0, this.singleWinValueStyle);\n        this.addChild(this.singleWinLimitValue);\n        this.values.push(this.singleWinLimitValue);\n\n        // this.singleWinZeroValue = new Text(this.limitsValuesConfig, '-', this.zeroValueStyle);\n        // this.values.push(this.singleWinZeroValue);\n        // this.addChild(this.singleWinZeroValue);\n\n        this.startAutoplayButton = new Button([\n            Core.assets.getAsset('svgStartButton').texture,\n            Core.assets.getAsset('svgStartButton').texture,\n            Core.assets.getAsset('svgStartButtonHover').texture,\n            Core.assets.getAsset('svgStartButtonInactive').texture,\n        ]);\n        this.startAutoplayButton.interactive = false;\n        this.startAutoplayButton.CLICK.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            const numberOfFreeSpins = Number(this.spinsButtons.find((button) => button.selected)?.buttonValue);\n            this.startAutoplayFromMenu(numberOfFreeSpins);\n        });\n\n        this.startButtonText = new Text(\n            this.startButtonTextConfig,\n            Core.translator.translate('START AUTOPLAY'),\n            this.startButtonTextStyle,\n        );\n        // this.startButtonText.pivot.x = 2;\n\n        this.startAutoplayButton.addChild(this.startButtonText);\n\n        this.addChild(this.startAutoplayButton);\n\n        let inactiveDotTexture;\n        let activeDotTexture;\n        if (this.componentConfiguration.autoplayViewProps.useTexturesForDots) {\n            inactiveDotTexture = Core.assets.getAsset(\n                this.componentConfiguration.autoplayViewProps.inactiveDotTexture,\n            ).texture;\n            activeDotTexture = Core.assets.getAsset(\n                this.componentConfiguration.autoplayViewProps.activeDotTexture,\n            ).texture;\n        }\n\n        this.lossSliderContainer = new ViewContainer();\n        const minBalanceValue = (this.getCurrentBalance() * this.balanceDecreaseValues) / 100;\n        this.lossSlider = new SteppedSlider({\n            sliderWidth: this.sliderContainerWidth,\n            sliderHeight: this.sliderHeight,\n            minValue: 0,\n            inactiveHandleTexture:\n                this.settings.autoplayRestrictions.mandatory.indexOf('lossLimits') !== -1\n                    ? Core.assets.getAsset('svgRedAuto').texture\n                    : Core.assets.getAsset('svgGreyAuto').texture,\n            activeHandleTexture: Core.assets.getAsset('svgGreenAuto').texture,\n            steps: [0, minBalanceValue],\n            stepsRadius: 6,\n            useSteps: false,\n            inactiveDotTexture,\n            activeDotTexture,\n            notSelectedFill: this.componentConfiguration.autoplayViewProps.slidersNotSelectedColor,\n            selectedFill: this.componentConfiguration.autoplayViewProps.slidersSelectedColor,\n        });\n        this.lossSliderContainer.addChild(this.lossSlider);\n        this.lossSlider.init();\n        this.balanceDecreaseValue = new MoneyText(this.limitsValuesConfig, 0, this.decreaseValueStyle);\n        this.addChild(this.balanceDecreaseValue);\n        this.lossSlider.CHANGE.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            if (this.lossSlider.CHANGE.value > 0) {\n                this.balanceDecreaseValue.textColor = this.colorValues;\n                this.balanceDecreaseValue.money = this.lossSlider.CHANGE.value;\n            } else {\n                this.balanceDecreaseValue.money = 0;\n            }\n            this.makeDecreaseSelection(this.balanceDecreaseValue.money);\n        });\n\n        this.winsSliderContainer = new ViewContainer();\n        const maxBalanceValue =\n            (this.getCurrentBalance() * this.balanceIncreaseValues) / 100 - this.getCurrentBalance();\n        this.winsSlider = new SteppedSlider({\n            sliderWidth: this.sliderContainerWidth,\n            sliderHeight: this.sliderHeight,\n            minValue: this.balanceIncreaseValues,\n            inactiveHandleTexture:\n                this.settings.autoplayRestrictions.mandatory.indexOf('winLimits') !== -1\n                    ? Core.assets.getAsset('svgRedAuto').texture\n                    : Core.assets.getAsset('svgGreyAuto').texture,\n            activeHandleTexture: Core.assets.getAsset('svgGreenAuto').texture,\n            steps: [0, maxBalanceValue],\n            stepsRadius: 6,\n            useSteps: false,\n            inactiveDotTexture,\n            activeDotTexture,\n            notSelectedFill: this.componentConfiguration.autoplayViewProps.slidersNotSelectedColor,\n            selectedFill: this.componentConfiguration.autoplayViewProps.slidersSelectedColor,\n        });\n\n        this.winsSliderContainer.addChild(this.winsSlider);\n        this.winsSlider.init();\n        this.balanceIncreaseValue = new MoneyText(this.limitsValuesConfig, 0, this.decreaseValueStyle);\n        this.addChild(this.balanceIncreaseValue);\n        this.winsSlider.CHANGE.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            // this.clearTextStyles(this.winValues);\n            if (this.winsSlider.CHANGE.value > 0) {\n                this.balanceIncreaseValue.textColor = this.colorValues;\n                this.balanceIncreaseValue.money = this.getCurrentBalance() + this.winsSlider.CHANGE.value;\n            } else {\n                this.balanceIncreaseValue.money = 0;\n            }\n            this.makeIncreaseSelection(this.balanceIncreaseValue.money);\n        });\n\n        this.singleWinSliderContainer = new ViewContainer();\n\n        this.singleWinSlider = new SteppedSlider({\n            sliderWidth: this.sliderContainerWidth,\n            sliderHeight: this.sliderHeight,\n            minValue: 0,\n            inactiveHandleTexture:\n                this.settings.autoplayRestrictions.mandatory.indexOf('singleWinLimit') !== -1\n                    ? Core.assets.getAsset('svgRedAuto').texture\n                    : Core.assets.getAsset('svgGreyAuto').texture,\n            activeHandleTexture: Core.assets.getAsset('svgGreenAuto').texture,\n            steps: [0, this.singleWinLimitValues],\n            useSteps: false,\n            stepsRadius: 6,\n            inactiveDotTexture,\n            activeDotTexture,\n            notSelectedFill: this.componentConfiguration.autoplayViewProps.slidersNotSelectedColor,\n            selectedFill: this.componentConfiguration.autoplayViewProps.slidersSelectedColor,\n        });\n        this.singleWinSliderContainer.addChild(this.singleWinSlider);\n        this.singleWinSlider.init();\n\n        this.singleWinSlider.CHANGE.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            if (this.singleWinSlider.CHANGE.value === 0) {\n                // this.singleWinZeroValue.visible = true;\n                this.singleWinLimitValue.money = 0;\n            } else {\n                this.singleWinLimitValue.textColor = this.colorValues;\n                this.singleWinLimitValue.money = this.singleWinSlider.CHANGE.value;\n            }\n            this.makeWinLimitSelection(this.singleWinLimitValue.money);\n        });\n\n        this.addChild(this.lossSliderContainer);\n        this.addChild(this.winsSliderContainer);\n        this.addChild(this.singleWinSliderContainer);\n\n        this.breakingLine = new Sprite();\n        this.breakingLine.texture = Core.assets.getTextureFromSpriteSheet('miscellaneous', 'greyLine.png');\n        this.addChild(this.breakingLine);\n\n        this.spinsButtons = [];\n        this.numberOfSpinsValues.forEach((value) => {\n            if (value !== 0) {\n                const spinValueBtn: ValueButton = this.createValueButton(value, false);\n                this.spinsButtons.push(spinValueBtn);\n\n                if (value === -1) {\n                    spinValueBtn.hideValue();\n\n                    this.infinitySprite.texture = Core.assets.getAsset(\n                        this.componentConfiguration.autoplayViewProps.infinityValueTexture,\n                    ).texture;\n                    this.infinitySprite.scale.set(0.7);\n                    this.infinitySprite.x = (spinValueBtn.width - this.infinitySprite.width) / 2 + 1;\n                    this.infinitySprite.y = (spinValueBtn.height - this.infinitySprite.height) / 2 + 1;\n                    spinValueBtn.addChild(this.infinitySprite);\n                }\n                this.addChild(spinValueBtn);\n\n                spinValueBtn.CLICK.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n                    spinValueBtn.selected = !spinValueBtn.selected;\n                    this.makeNumOfSpinsSelection(value, spinValueBtn);\n                });\n            }\n        });\n\n        this.makeNumOfSpinsSelection(this.numberOfSpinsValues[0], this.spinsButtons[0]);\n        this.setOrientation();\n    }\n\n    protected makeNumOfSpinsSelection(value: number, btn: ValueButton): void {\n        this.clearSelections(this.spinsButtons);\n        // if (btn.buttonValue !== '-1') {\n        //     btn.style.fill = '0xffffff';\n        // } else {\n        //     this.infinitySprite.tint = 0xffffff;\n        // }\n        btn.selected = true;\n        this.autoSpinsSelected = value;\n        this.setAutoplayState();\n    }\n\n    protected resetAutoPlayRestrictions(): void {\n        this.clearSelections(this.spinsButtons);\n        this.spinsButtons[0].selected = true;\n        this.spinsButtons[0].style.fill = '0xffffff';\n        this.rootStore.uiStore.AUTOPLAY_BET_COUNTER.next(0);\n        this.rootStore.uiStore.autoPlayFromSettings = false;\n        this.lossSlider.resetSlider();\n        this.winsSlider.resetSlider();\n        this.singleWinSlider.resetSlider();\n    }\n\n    private createValueButton(value: number, _showAsMoney: boolean): ValueButton {\n        const valueButtonTextures = [\n            Core.assets.getAsset('svgSpinsButtonOff').texture,\n            Core.assets.getAsset('svgSpinsButtonOn').texture,\n            Core.assets.getAsset('svgSpinsButtonOn').texture,\n            Core.assets.getAsset('svgSpinsButtonOff').texture,\n        ];\n        const valueButtonSelectedTextures = [\n            Core.assets.getAsset('svgSpinsButtonGreen').texture,\n            Core.assets.getAsset('svgSpinsButtonGreen').texture,\n            Core.assets.getAsset('svgSpinsButtonGreen').texture,\n            Core.assets.getAsset('svgSpinsButtonGreen').texture,\n        ];\n\n        // const textStyle = new TextStyle({\n        //     fontFamily: 'FuturaPTCond-Bold',\n        //     fontSize: 20,\n        //     fontWeight: 'bold',\n        //     fill: '#FFFFFF',\n        // });\n\n        const valueBtn: ValueButton = new ValueButton(\n            'spins' + value,\n            value.toString(),\n            this.componentConfiguration.autoplayViewProps.valueButtonsTextStyle,\n            70,\n            48,\n            valueButtonTextures,\n            valueButtonSelectedTextures,\n            false,\n        );\n\n        return valueBtn;\n    }\n\n    private getButtonsLeftOffset(buttonsSet: ValueButton[]): number {\n        return (\n            (this.panelDimensions.width -\n                (buttonsSet.length * buttonsSet[0].width + (buttonsSet.length - 1) * this.buttonsOffset)) /\n            2\n        );\n    }\n\n    private clearSelections(buttonsGroup: ValueButton[]): void {\n        buttonsGroup.forEach((btn) => {\n            btn.selected = false;\n            // if (btn.buttonValue !== '-1') {\n            //     btn.style.fill = '0x747474';\n            // } else {\n            //     this.infinitySprite.tint = 0x747474;\n            // }\n        });\n        this.autoSpinsSelected = this.numberOfSpinsValues[0];\n    }\n\n    // private clearTextStyles(textGroup: MoneyText[]): void {\n    //     textGroup.forEach(txt => {\n    //         txt.textColor = '0x595959';\n    //     });\n    // }\n}\n","import { Subject } from 'rxjs';\nimport { injectable } from 'tsyringe';\n\n@injectable()\nexport default class SettingsPopupSubjects {\n    public readonly BEFORE_CLOSE: Subject<void> = new Subject();\n    public readonly BEFORE_OPEN: Subject<void> = new Subject();\n    public readonly AFTER_OPEN: Subject<void> = new Subject();\n    public readonly AFTER_CLOSE: Subject<void> = new Subject();\n}\n","import Core, { IOrientation } from '@egt/core';\nimport { InitialSettings, RootStore } from '@egt/slot';\nimport { Button, Text, TextConfig, ToggleButton, ViewContainer } from '@egt/ui-lib';\nimport { gsap } from 'gsap';\nimport { Container, Graphics, Text as PixiText, Point, Sprite } from 'pixi.js';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport SettingsTab from '../enums/SettingsTab';\nimport { ISettingsPopupComponentConfiguration } from '../interfaces/SettingsInterfaces';\nimport BetSettingsView from '../settings-views/bet/BetSettingsView';\nimport GeneralSettingsView from '../settings-views/general/GeneralSettingsView';\nimport HelpView from '../settings-views/help/HelpView';\nimport PaytableHTMLView from '../settings-views/paytableHTML/PaytableHTMLView';\nimport SpinSettingsView from '../settings-views/spin/SpinSettingsView';\nimport SettingsPopupSubjects from '../subjects/SettingsPopupSubjects';\n\n@injectable()\nexport default class SettingsPopup extends ViewContainer {\n    public betButton: ToggleButton;\n    public generalButton: ToggleButton;\n    public spinButton: ToggleButton;\n    public infoButton: ToggleButton;\n    public helpButton: ToggleButton;\n\n    protected headers: any[] = [];\n    protected headerBackground: Container;\n    protected headerTopLine: Graphics;\n    protected headerBottomLine: Graphics;\n    protected betSettingsHeader: Text | PixiText;\n    protected generalSettingsHeader: Text | PixiText;\n    protected spinSettingsHeader: Text | PixiText;\n    protected helpSettingsHeader: Text | PixiText;\n    protected infoSettingsHeader: Text | PixiText;\n    protected settingsBackgroundSprite: Sprite;\n    protected betButtonsBlocker: Graphics;\n    protected settingsBar: ViewContainer;\n\n    protected backgroundOverlay: Sprite;\n\n    protected tabs: any[] = [];\n    protected initialized: boolean = false;\n    protected paytableAssetsLoaded: boolean = false;\n    protected background: Graphics;\n    protected headerBounds: any;\n    protected animationTween: any;\n    private _isOpened: boolean = false;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('PaytableHTMLView') protected infoSettings: PaytableHTMLView,\n        @inject('SpinSettingsView') protected spinSettings: SpinSettingsView,\n        @inject('GeneralSettingsView') protected generalSettings: GeneralSettingsView,\n        @inject('HelpView') protected helpSettings: HelpView,\n        @inject('BetSettingsView') protected betSettings: BetSettingsView,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('SettingsPopupSubjects') protected subjects: SettingsPopupSubjects,\n        @inject('SettingsPopupComponentConfiguration')\n        protected componentConfiguration: ISettingsPopupComponentConfiguration,\n    ) {\n        super();\n    }\n\n    public init(): void {\n        this.visible = false;\n        this.interactive = this.componentConfiguration.popupProps.isInteractive;\n        this.sortableChildren = true;\n    }\n\n    public initComplete(): void {\n        this.rootStore.uiStore.SHOW_SETTINGS.pipe(takeUntil(this.DESTROY)).subscribe(this.renderPopup.bind(this));\n    }\n\n    public get isOpened(): boolean {\n        return this._isOpened;\n    }\n\n    public set isOpened(value: boolean) {\n        this._isOpened = value;\n    }\n\n    public open(animation: boolean): void {\n        this.subjects.BEFORE_OPEN.next();\n        this.killAllAnimations();\n\n        this.visible = true;\n\n        if (animation) {\n            this.y = -Core.ORIENTATION.value.height;\n            this.animationTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/slot-components/settings-popup/src/egt/views/SettingsPopup.ts:89:35\",null]), gsap.to(this, {\n                duration: 0.3,\n                y: this.componentConfiguration.popupProps.topOffset,\n                ease: 'power2.in',\n                onComplete: () => {\n                    this.subjects.AFTER_OPEN.next();\n                },\n            }));\n            this.isOpened = true;\n        } else {\n            this.y = this.componentConfiguration.popupProps.topOffset;\n            this.isOpened = true;\n            this.subjects.AFTER_OPEN.next();\n        }\n    }\n\n    public close(animation: boolean): void {\n        if (!this.isOpened) {\n            return;\n        }\n        this.isOpened = false;\n        this.subjects.BEFORE_CLOSE.next();\n        this.killAllAnimations();\n\n        if (animation) {\n            this.animationTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/slot-components/settings-popup/src/egt/views/SettingsPopup.ts:114:35\",null]), gsap.to(this, {\n                duration: 0.3,\n                y: -Core.ORIENTATION.value.height,\n                ease: 'power2.in',\n                onComplete: () => {\n                    this.visible = false;\n                    this.subjects.AFTER_CLOSE.next();\n                },\n            }));\n        } else {\n            this.visible = false;\n            this.y = -Core.ORIENTATION.value.height;\n            this.subjects.AFTER_CLOSE.next();\n        }\n        // this.hideSettingsViews();\n    }\n\n    public destroy(): void {\n        this.killAllAnimations();\n        this.subjects.BEFORE_CLOSE.complete();\n        this.subjects.BEFORE_OPEN.complete();\n        this.subjects.AFTER_OPEN.complete();\n        this.subjects.AFTER_CLOSE.complete();\n        // @ts-ignore\n        this.BEFORE_CLOSE = null;\n        // @ts-ignore\n        this.BEFORE_OPEN = null;\n        // @ts-ignore\n        this.AFTER_OPEN = null;\n        // @ts-ignore\n        this.AFTER_CLOSE = null;\n        this.removeChildren();\n        if (this.background) {\n            this.background.destroy();\n            // @ts-ignore\n            this.background = null;\n        }\n        if (this.headerBackground) {\n            this.headerBackground.destroy();\n            // @ts-ignore\n            this.headerBackground = null;\n        }\n        if (this.backgroundOverlay) {\n            this.backgroundOverlay.destroy();\n            // @ts-ignore\n            this.backgroundOverlay = null;\n        }\n        // If the views are not added as children, destroy them manually.\n        // if (!this.initialized) {\n        this.spinSettings.destroy({ children: true, texture: true, baseTexture: true });\n        this.generalSettings.destroy({ children: true, texture: true, baseTexture: true });\n        this.helpSettings.destroy({ children: true, texture: true, baseTexture: true });\n        this.betSettings.destroy();\n        this.infoSettings.destroy({ children: true, texture: true, baseTexture: true });\n\n        super.destroy({ children: true, texture: true, baseTexture: true });\n    }\n\n    public clearTabSelection(): void {\n        if (this.betButton) {\n            this.betButton.selected = false;\n            this.betButton.enabled = true;\n        }\n\n        if (this.spinButton) {\n            this.spinButton.selected = false;\n            this.spinButton.enabled = true;\n        }\n\n        if (this.generalButton) {\n            this.generalButton.selected = false;\n            this.generalButton.enabled = true;\n        }\n\n        if (this.infoButton) {\n            this.infoButton.selected = false;\n            this.infoButton.enabled = true;\n        }\n\n        if (this.helpButton) {\n            this.helpButton.selected = false;\n            this.helpButton.enabled = true;\n        }\n\n        this.hideSettingsViews();\n    }\n\n    protected renderPopup(): void {\n        if (this.rootStore.uiStore.SHOW_SETTINGS.value && !this.initialized) {\n            this.initialized = true;\n            this.initialRender();\n\n            Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n            this.rootStore.uiStore.SELECTED_SETTINGS_TAB.pipe(takeUntil(this.DESTROY)).subscribe(\n                this.selectTab.bind(this),\n            );\n        } else if (this.rootStore.uiStore.SHOW_SETTINGS.value && this.initialized) {\n            this.selectTab(this.rootStore.uiStore.SELECTED_SETTINGS_TAB.value);\n        }\n    }\n\n    protected setOrientation(orientation: IOrientation): void {\n        if (this.initialized) {\n            // this.width = orientation.width;\n            // this.height = orientation.height;\n            this.background.width = orientation.width + 2;\n            this.background.height = orientation.height - this.componentConfiguration.popupProps.bottomOffset;\n            this.background.y = this.componentConfiguration.backgroundProps.y;\n            this.scale = new Point(1, 1);\n\n            if (this.headerBackground instanceof Sprite) {\n                this.headerBackground.texture = Core.assets.getTextureFromSpriteSheet(\n                    this.componentConfiguration.popupProps.assetId,\n                    this.componentConfiguration.headerBackgroundProps.backgroundTexture,\n                );\n            } else {\n                this.headerBackground.width = orientation.width;\n                this.headerBackground.height = this.componentConfiguration.headerBackgroundProps.headerHeight;\n            }\n            this.headerBackground.y = -this.componentConfiguration.popupProps.topOffset;\n\n            if (this.componentConfiguration.popupProps.backgroundOverlay.enabled && this.backgroundOverlay) {\n                this.backgroundOverlay.texture = Core.assets.getTextureFromSpriteSheet(\n                    this.componentConfiguration.popupProps.assetId,\n                    this.componentConfiguration.popupProps.backgroundOverlay.texture,\n                );\n                this.backgroundOverlay.x = this.componentConfiguration.popupProps.backgroundOverlay.x;\n                this.backgroundOverlay.y = this.componentConfiguration.popupProps.backgroundOverlay.y;\n                this.backgroundOverlay.visible = this.componentConfiguration.popupProps.backgroundOverlay.visible;\n            }\n\n            this.headerTopLine.width = orientation.width;\n            this.headerTopLine.height = this.componentConfiguration.headerTopLineProps.height;\n            this.headerTopLine.y = -this.componentConfiguration.popupProps.topOffset + this.headerBackground.height;\n\n            this.headerBottomLine.width = orientation.width;\n            this.headerBottomLine.height = this.componentConfiguration.headerBottomLineProps.height;\n            this.headerBottomLine.y =\n                -this.componentConfiguration.popupProps.topOffset +\n                this.componentConfiguration.headerBackgroundProps.headerHeight +\n                this.componentConfiguration.headerTopLineProps.height;\n\n            this.settingsBackgroundSprite.texture = Core.assets.getTextureFromSpriteSheet(\n                this.componentConfiguration.popupProps.assetId,\n                this.componentConfiguration.settingsBarProps.settingsBackgroundTexture,\n            );\n            this.settingsBackgroundSprite.y =\n                orientation.height -\n                this.componentConfiguration.popupProps.menuTopOffset -\n                this.componentConfiguration.settingsBarProps.settingsSpriteYOffset;\n            this.settingsBackgroundSprite.interactive =\n                this.componentConfiguration.settingsBarProps.settingsBackgroundInteractive;\n\n            this.betButtonsBlocker.x =\n                this.settingsBackgroundSprite.x + this.componentConfiguration.blockerProps.blockerOffset;\n            this.betButtonsBlocker.y = this.settingsBackgroundSprite.y;\n            this.betButtonsBlocker.width =\n                Core.display.stage.width - this.componentConfiguration.blockerProps.blockerOffset * 2;\n            this.betButtonsBlocker.height = this.settingsBackgroundSprite.height;\n\n            this.betButtonsBlocker.visible = orientation.isLandscape ? true : false;\n\n            this.settingsBar.y =\n                orientation.height -\n                this.componentConfiguration.popupProps.menuTopOffset +\n                (this.settingsBackgroundSprite.height - this.settingsBar.height) / 2 -\n                this.componentConfiguration.settingsBarProps.yOffset;\n            this.settingsBar.x = (orientation.width - this.settingsBar.width) / 2;\n\n            this.headers.forEach((header) => {\n                header.style = this.componentConfiguration.tabNameProps.textStyle;\n                header.textBounds = this.headerBounds;\n                header.pivot.x = header.width / 2;\n                header.x = orientation.width / 2;\n                header.y = this.headerBackground.y + this.headerBackground.height / 2;\n            });\n\n            if (this.isOpened) {\n                this.close(false);\n                this.open(false);\n            }\n        }\n    }\n\n    protected initialRender(): void {\n        this.background = new Graphics();\n        this.background.beginFill(\n            this.componentConfiguration.backgroundProps.backgroundColor,\n            this.componentConfiguration.backgroundProps.backgroundAlpha,\n        );\n        this.background.drawRect(0, 0, 1, 1);\n        this.background.endFill();\n        this.background.interactive = true;\n\n        this.addChild(this.background);\n\n        if (this.componentConfiguration.popupProps.backgroundOverlay.enabled) {\n            this.backgroundOverlay = new Sprite();\n            this.backgroundOverlay.interactive = true;\n            this.addChild(this.backgroundOverlay);\n        }\n\n        this.headerTopLine = new Graphics();\n        this.headerBottomLine = new Graphics();\n        const isLandscape: boolean = Core.ORIENTATION.value.isLandscape;\n\n        let headerBoundWidth: number = isLandscape ? Core.ORIENTATION.value.width / 2 : Core.ORIENTATION.value.width;\n        headerBoundWidth -= this.componentConfiguration.headerBackgroundProps.headerBoundsWidthOffset;\n        const headerBoundsHeight: number =\n            this.componentConfiguration.headerBackgroundProps.headerHeight -\n            this.componentConfiguration.headerBackgroundProps.headerBoundsHeightOffset;\n        this.headerBounds = { width: headerBoundWidth, height: headerBoundsHeight };\n        // if we have texture for background - create and use Sprite\n        // else draw and use Graphics\n        if (this.componentConfiguration.headerBackgroundProps.useTexture) {\n            this.headerBackground = new Sprite();\n            this.addChild(this.headerBackground);\n        } else {\n            this.headerTopLine.beginFill(this.componentConfiguration.headerTopLineProps.color);\n            this.headerTopLine.drawRect(0, 0, 1, 1);\n            this.headerTopLine.endFill();\n\n            this.headerBottomLine.beginFill(this.componentConfiguration.headerBottomLineProps.color);\n            this.headerBottomLine.drawRect(0, 0, 1, 1);\n            this.headerBottomLine.endFill();\n\n            this.headerBackground = new Graphics();\n            (this.headerBackground as Graphics).beginFill(\n                this.componentConfiguration.headerBackgroundProps.headerColor,\n            );\n            (this.headerBackground as Graphics).drawRect(0, 0, 1, 1);\n            (this.headerBackground as Graphics).endFill();\n\n            this.addChild(this.headerBackground);\n            this.addChild(this.headerTopLine);\n            this.addChild(this.headerBottomLine);\n        }\n        this.headerBackground.name = 'headerBackground';\n\n        this.settingsBackgroundSprite = new Sprite();\n        this.settingsBackgroundSprite.name = 'footerBackground';\n        this.addChild(this.settingsBackgroundSprite);\n\n        this.betButtonsBlocker = this.creatBetButtonsBlocker();\n        this.betButtonsBlocker.interactive = true;\n        this.addChild(this.betButtonsBlocker);\n\n        this.settingsBar = this.createSettingsBar();\n        this.addChild(this.settingsBar);\n\n        this.betSettingsHeader = this.createTabName(Core.translator.translate('BET SETTINGS'));\n        this.addChild(this.betSettingsHeader);\n        this.headers.push(this.betSettingsHeader);\n\n        this.generalSettingsHeader = this.createTabName(Core.translator.translate('GENERAL SETTINGS'));\n        this.addChild(this.generalSettingsHeader);\n        this.headers.push(this.generalSettingsHeader);\n\n        this.spinSettingsHeader = this.createTabName(Core.translator.translate('AUTOPLAY SETTINGS'));\n        this.addChild(this.spinSettingsHeader);\n        this.headers.push(this.spinSettingsHeader);\n\n        this.helpSettingsHeader = this.createTabName(Core.translator.translate('HELP'));\n        this.addChild(this.helpSettingsHeader);\n        this.headers.push(this.helpSettingsHeader);\n\n        this.infoSettingsHeader = this.createTabName(Core.translator.translate('PAYTABLE'));\n        this.addChild(this.infoSettingsHeader);\n        this.headers.push(this.infoSettingsHeader);\n\n        this.tabs.push(this.betSettings, this.generalSettings, this.spinSettings, this.infoSettings, this.helpSettings);\n        this.addChild(this.betSettings);\n        this.addChild(this.generalSettings);\n        this.addChild(this.spinSettings);\n        this.addChild(this.helpSettings);\n        this.addChild(this.infoSettings);\n    }\n\n    protected createTabName(viewName: string): any {\n        const tabHeaderConfig: TextConfig = new TextConfig();\n        // if (this.componentConfiguration.tabNameProps.useTextConfig) {\n        tabHeaderConfig.bounds.width = this.headerBounds.width;\n        tabHeaderConfig.bounds.height = this.headerBounds.height;\n        tabHeaderConfig.minFontSize = this.componentConfiguration.tabNameProps.minFontSize;\n        tabHeaderConfig.shouldFitInBounds = true;\n        const text = new Text(tabHeaderConfig, viewName, this.componentConfiguration.tabNameProps.textStyle);\n        text.pivot.x = text.width / 2;\n        text.pivot.y = tabHeaderConfig.bounds.height / 2;\n        // } else {\n        //     text = new PixiText(viewName, this.componentConfiguration.tabNameProps.textStyle);\n        //     text.pivot.x = text.width / 2;\n        //     text.pivot.y = text.height / 2;\n        // }\n\n        text.x = Core.display.stage.width / 2;\n        return text;\n    }\n\n    protected createHelpSettings(): ViewContainer {\n        // TODO: Implement\n        const container = new ViewContainer();\n        container.addChild(this.createTabName('History Settings'));\n        return container;\n    }\n\n    protected selectTab(tab: SettingsTab): void {\n        this.clearTabSelection();\n        this[tab.toLowerCase() + 'Settings'].show = true;\n        this.find(tab.toLowerCase() + 'Button').selected = true;\n        this.find(tab.toLowerCase() + 'Button').enabled = false;\n        this.headers.forEach((header) => {\n            header.visible = false;\n        });\n        this[tab.toLowerCase() + 'SettingsHeader'].visible = true;\n\n        // If we have different size of scrollbars for different pages. Now we have scroll only in info page\n        switch (tab) {\n            case SettingsTab.INFO:\n                this.rootStore.subjects.OPEN_HELP_POPUP.next(false);\n                this.rootStore.subjects.OPEN_INFO_POPUP.next(true);\n                break;\n            case SettingsTab.HELP:\n                this.rootStore.subjects.OPEN_HELP_POPUP.next(true);\n                this.rootStore.subjects.OPEN_INFO_POPUP.next(false);\n                break;\n            default:\n                this.rootStore.subjects.OPEN_HELP_POPUP.next(false);\n                this.rootStore.subjects.OPEN_INFO_POPUP.next(false);\n        }\n    }\n\n    protected hideSettingsViews(): void {\n        this.betSettings.show = false;\n        this.generalSettings.show = false;\n        this.spinSettings.show = false;\n        this.infoSettings.show = false;\n        this.helpSettings.show = false;\n        this.headers.forEach((header) => {\n            header.visible = false;\n        });\n    }\n\n    protected creatBetButtonsBlocker(): Graphics {\n        return new Graphics()\n            .beginFill(\n                this.componentConfiguration.blockerProps.backgroundColor,\n                this.componentConfiguration.blockerProps.backgroundAlpha,\n            )\n            .drawRect(0, 0, 1, 1)\n            .endFill();\n    }\n\n    protected createSettingsBar(): ViewContainer {\n        const container: ViewContainer = new ViewContainer();\n        const settingButtons: ToggleButton[] = [];\n\n        if (this.componentConfiguration.settingsBarProps.haveBetButton) {\n            this.betButton = this.createSvgTabButton(\n                'betButton',\n                this.componentConfiguration.settingsBarProps.betButtonTextures.onTexture,\n                this.componentConfiguration.settingsBarProps.betButtonTextures.offTexture,\n            );\n            container.addChild(this.betButton);\n            settingButtons.push(this.betButton);\n        }\n\n        if (this.componentConfiguration.settingsBarProps.haveGeneralButton) {\n            this.generalButton = this.createSvgTabButton(\n                'generalButton',\n                this.componentConfiguration.settingsBarProps.generalButtonTextures.onTexture,\n                this.componentConfiguration.settingsBarProps.generalButtonTextures.offTexture,\n            );\n            container.addChild(this.generalButton);\n            settingButtons.push(this.generalButton);\n        }\n\n        if (this.settings.autoplay === true && this.componentConfiguration.settingsBarProps.haveSpinButton) {\n            this.spinButton = this.createSvgTabButton(\n                'spinButton',\n                this.componentConfiguration.settingsBarProps.spinButtonTextures.onTexture,\n                this.componentConfiguration.settingsBarProps.spinButtonTextures.offTexture,\n            );\n            container.addChild(this.spinButton);\n            settingButtons.push(this.spinButton);\n        }\n\n        if (this.componentConfiguration.settingsBarProps.haveInfoButton) {\n            this.infoButton = this.createSvgTabButton(\n                'infoButton',\n                this.componentConfiguration.settingsBarProps.infoButtonTextures.onTexture,\n                this.componentConfiguration.settingsBarProps.infoButtonTextures.offTexture,\n            );\n            container.addChild(this.infoButton);\n            settingButtons.push(this.infoButton);\n        }\n\n        if (this.componentConfiguration.settingsBarProps.haveHelpButton) {\n            this.helpButton = this.createSvgTabButton(\n                'helpButton',\n                this.componentConfiguration.settingsBarProps.helpButtonTextures.onTexture,\n                this.componentConfiguration.settingsBarProps.helpButtonTextures.offTexture,\n            );\n            container.addChild(this.helpButton);\n            settingButtons.push(this.helpButton);\n        }\n\n        for (let i: number = 0; i < settingButtons.length; i++) {\n            if (settingButtons[i]) {\n                settingButtons[i].x = this.componentConfiguration.settingsBarProps.buttonsSpacing * i;\n            }\n        }\n\n        return container;\n    }\n\n    protected createSvgTabButton(name: string, onTextureName: string, offTextureName: string): ToggleButton {\n        const button: ToggleButton = new ToggleButton(\n            new Button([Core.assets.getAsset(onTextureName).texture], [Core.assets.getAsset('svgTabOn').texture]),\n            new Button([Core.assets.getAsset(offTextureName).texture], [Core.assets.getAsset('svgTabOff').texture]),\n        );\n        button.name = name;\n\n        return button;\n    }\n\n    protected killAllAnimations(): void {\n        if (this.animationTween) {\n            this.animationTween.kill();\n            this.animationTween = null;\n        }\n    }\n}\n","import Core from '@egt/core';\nimport { InitialSettings, RootStore } from '@egt/slot';\nimport { Button } from '@egt/ui-lib';\nimport { gsap } from 'gsap';\nimport { Graphics } from 'pixi.js';\nimport { inject, injectable } from 'tsyringe';\nimport SettingsTab from '../enums/SettingsTab';\nimport { ISettingsPopupComponentConfiguration } from '../interfaces/SettingsInterfaces';\nimport BetSettingsViewDesktop from '../settings-views/bet/BetSettingsViewDesktop';\nimport GeneralSettingsViewDesktop from '../settings-views/general/GeneralSettingsViewDesktop';\nimport HelpView from '../settings-views/help/HelpView';\nimport PaytableHTMLView from '../settings-views/paytableHTML/PaytableHTMLView';\nimport SpinSettingsViewDesktop from '../settings-views/spin/SpinSettingsViewDesktop';\nimport SettingsPopupSubjects from '../subjects/SettingsPopupSubjects';\nimport SettingsPopup from './SettingsPopup';\n\n@injectable()\nexport default class SettingsPopupDesktop extends SettingsPopup {\n    public closeBtn: Button;\n    private darkLayer: Graphics;\n\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('PaytableHTMLView') protected infoSettings: PaytableHTMLView,\n        @inject('SpinSettingsView') protected spinSettings: SpinSettingsViewDesktop,\n        @inject('GeneralSettingsView') protected generalSettings: GeneralSettingsViewDesktop,\n        @inject('BetSettingsView') protected betSettings: BetSettingsViewDesktop,\n        @inject('HelpView') protected helpSettings: HelpView,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('SettingsPopupSubjects') protected subjects: SettingsPopupSubjects,\n        @inject('SettingsPopupComponentConfiguration')\n        protected componentConfiguration: ISettingsPopupComponentConfiguration,\n    ) {\n        super(\n            rootStore,\n            infoSettings,\n            spinSettings,\n            generalSettings,\n            helpSettings,\n            betSettings,\n            settings,\n            subjects,\n            componentConfiguration,\n        );\n    }\n\n    public destroy(): void {\n        super.destroy.apply(this, arguments);\n    }\n\n    public setDimensions(selectedTab: string): void {\n        let panelWidth: number = 0;\n        let _panelHeight: number = 0;\n        switch (selectedTab) {\n            case 'SPIN':\n                panelWidth = this.spinSettings.panelDimensions.width;\n                _panelHeight = this.spinSettings.panelDimensions.height;\n                this.y = this.spinSettings.panelDimensions.topOffset;\n                break;\n            case 'GENERAL':\n                panelWidth = this.generalSettings.panelDimensions.width;\n                _panelHeight = this.generalSettings.panelDimensions.height;\n                this.y = this.generalSettings.panelDimensions.topOffset;\n                break;\n            case 'BET':\n                panelWidth = this.componentConfiguration.betViewProps.widthBounds;\n                _panelHeight = this.componentConfiguration.betViewProps.heightBounds;\n                this.y = this.componentConfiguration.betViewProps.viewTopOffset;\n                break;\n            case 'INFO':\n                panelWidth = this.componentConfiguration.paytableViewProps.widthBounds;\n                _panelHeight = this.componentConfiguration.paytableViewProps.heightBounds;\n                this.y = this.componentConfiguration.paytableViewProps.viewTopOffset;\n                break;\n            case 'HELP':\n                panelWidth = this.componentConfiguration.helpViewProps.widthBounds;\n                _panelHeight = this.componentConfiguration.helpViewProps.heightBounds;\n                this.y = this.componentConfiguration.helpViewProps.viewTopOffset;\n                break;\n        }\n\n        this.x = (Core.display.stage.width - panelWidth) / 2;\n        // this.maskYOffset = 0;\n        // this.headerHeight = 48;\n\n        this.darkLayer.width = Core.display.stage.width;\n        this.darkLayer.height = Core.display.stage.height;\n        this.darkLayer.x = -(Core.display.stage.width - panelWidth) / 2;\n        this.darkLayer.y = -this.y;\n\n        this.closeBtn.scale.set(0.6, 0.6);\n        this.closeBtn.x = panelWidth - this.closeBtn.width - 14;\n        this.closeBtn.y = (this.componentConfiguration.headerBackgroundProps.headerHeight - this.closeBtn.height) / 2;\n    }\n\n    public clearTabSelection(): void {\n        this.hideSettingsViews();\n        // this.rootStore.uiStore.SHOW_SETTINGS.next(false);\n    }\n\n    public open(): void {\n        this.subjects.BEFORE_OPEN.next();\n        this.rootStore.subjects.TAB_OPENED.next(true);\n        this.killAllAnimations();\n        this.visible = true;\n        this.isOpened = true;\n        this.animationTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/slot-components/settings-popup/src/egt/views/SettingsPopupDesktop.ts:107:31\",null]), gsap.to(this, {\n            duration: 0.3,\n            alpha: 1,\n            onComplete: () => {\n                this.subjects.AFTER_OPEN.next();\n            },\n        }));\n    }\n\n    /**\n     * @override\n     */\n    public close(): void {\n        this.isOpened = false;\n        this.subjects.BEFORE_CLOSE.next();\n        this.killAllAnimations();\n\n        this.animationTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/slot-components/settings-popup/src/egt/views/SettingsPopupDesktop.ts:124:31\",null]), gsap.to(this, {\n            duration: 0.3,\n            alpha: 0,\n            onComplete: () => {\n                this.visible = false;\n                this.rootStore.subjects.TAB_OPENED.next(false);\n                this.subjects.AFTER_CLOSE.next();\n            },\n        }));\n    }\n\n    protected setOrientation(): void {\n        return;\n    }\n\n    protected initialRender(): void {\n        this.darkLayer = new Graphics();\n        this.darkLayer.name = 'dark_layer';\n        this.darkLayer.interactive = true;\n        this.darkLayer.beginFill(0x000000, 0.8);\n        this.darkLayer.drawRect(0, 0, 1, 1);\n        this.darkLayer.endFill();\n\n        this.addChild(this.darkLayer);\n        this.closeBtn = new Button([Core.assets.getAsset('svgSettingsClose').texture]);\n        this.closeBtn.enabled = true;\n        this.closeBtn.name = 'close_button';\n\n        this.tabs.push(this.betSettings, this.generalSettings, this.spinSettings, this.infoSettings, this.helpSettings);\n        this.addChild(this.betSettings);\n        this.addChild(this.generalSettings);\n        this.addChild(this.spinSettings);\n        this.addChild(this.infoSettings);\n        this.addChild(this.helpSettings);\n        this.addChild(this.closeBtn);\n    }\n\n    protected selectTab(tab: SettingsTab): void {\n        this.clearTabSelection();\n        this[tab.toLowerCase() + 'Settings'].show = true;\n        this.headers.forEach((header) => {\n            header.visible = false;\n        });\n        this.darkLayer.visible = true;\n\n        switch (tab) {\n            case SettingsTab.INFO:\n                this.rootStore.subjects.OPEN_HELP_POPUP.next(false);\n                this.rootStore.subjects.OPEN_INFO_POPUP.next(true);\n                this.infoSettings.visible = true;\n                break;\n            case SettingsTab.HELP:\n                this.rootStore.subjects.OPEN_INFO_POPUP.next(false);\n                this.rootStore.subjects.OPEN_HELP_POPUP.next(true);\n                this.helpSettings.visible = true;\n                break;\n            default:\n                this.rootStore.subjects.OPEN_INFO_POPUP.next(false);\n            // this.scrollBarWidth = this.infoSettings.scrollBarOptions.backWidth;\n        }\n    }\n}\n","import Core, { AssetPriority, BaseFeature } from '@egt/core';\nimport { ReelsOverlayZOrders } from '@egt/reels-overlay';\nimport { Features, RootView } from '@egt/slot';\nimport { ViewContainer } from '@egt/ui-lib';\nimport { DependencyContainer, Lifecycle } from 'tsyringe';\nimport { characterAnimationConfigFactory } from './configurations/CharacterAnimationFeatureConfiguration';\nimport { ICharacterAnimationFeatureConfiguration } from './configurations/ICharacterAnimationFeatureConfiguration';\nimport CharacterAnimationsController from './controllers/CharacterAnimationsController';\nimport CharacterAnimationsView from './views/CharacterAnimationsView';\n\nexport default class CharacterAnimationsFeature extends BaseFeature {\n    public view: CharacterAnimationsView;\n    public controller: CharacterAnimationsController;\n    public reelsOverlayView: ViewContainer;\n\n    public featureType: Features = Features.CHARACTER_ANIMATIONS;\n    public configurationName = 'CharacterAnimationsFeature';\n    protected mainAssetID = 'characterAnimations';\n    protected showLoadingScreen: boolean = false;\n    private featureConfiguration: ICharacterAnimationFeatureConfiguration;\n\n    private settings: any;\n\n    constructor(private config: any) {\n        super();\n    }\n\n    public destroy(): void {\n        if (this.controller) {\n            this.controller.destroy();\n            // @ts-ignore\n            this.controller = null;\n        }\n\n        // @ts-ignore\n        this.reelsOverlayView = null;\n        this.settings = null;\n    }\n\n    public onGameSettings(settings: any): void {\n        this.settings = settings;\n    }\n\n    public onRegisterDependencies(container: DependencyContainer): void {\n        super.onRegisterDependencies(container);\n        if (this.config) {\n            this.dependencyContainer.register(\n                'CharacterAnimationFeatureConfiguration',\n                this.config(characterAnimationConfigFactory()),\n            );\n        } else {\n            this.dependencyContainer.register(\n                'CharacterAnimationFeatureConfiguration',\n                characterAnimationConfigFactory(),\n            );\n        }\n        if (!this.dependencyContainer.isRegistered('CharacterAnimationsView')) {\n            this.dependencyContainer.register(\n                'CharacterAnimationsView',\n                { useClass: CharacterAnimationsView },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n        if (!this.dependencyContainer.isRegistered('CharacterAnimationsController')) {\n            this.dependencyContainer.register(\n                'CharacterAnimationsController',\n                { useClass: CharacterAnimationsController },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n        this.featureConfiguration = container.resolve('CharacterAnimationFeatureConfiguration');\n        this.mainAssetID = this.featureConfiguration.showAfterAssetIsLoaded;\n    }\n\n    public onGameStarted(): void {\n        this.controller.onGameStarted(this.settings);\n    }\n\n    public onResolveDependencies(container: DependencyContainer): void {\n        this.view = container.resolve('CharacterAnimationsView');\n        this.view.name = 'CharacterAnimationsView';\n\n        this.controller = container.resolve('CharacterAnimationsController');\n        this.controller.ready = this.ready.bind(this);\n\n        // if (!this.configuration.positionOverSlices) {\n        //     this.backgroundAnimationView.zIndex = ZOrders.REELS_LEVEL - 2;\n        //     this.rootView.addChild(this.backgroundAnimationView);\n        // } else {\n        if (this.dependencyContainer.isRegistered('ReelsOverlay')) {\n            this.reelsOverlayView = this.dependencyContainer.resolve('ReelsOverlay');\n        }\n    }\n\n    public onInitialRender(rootView: RootView): void {\n        if (this.reelsOverlayView) {\n            this.view.zIndex = ReelsOverlayZOrders.BACKGROUND_ANIMATIONS + 1;\n            this.reelsOverlayView.addChild(this.view);\n        } else {\n            this.view.zIndex = this.featureConfiguration.viewZIndex;\n            rootView.addChild(this.view);\n        }\n        // this.view.onGameStarted();\n    }\n\n    public onPrepareResources(_container: any): void {\n        const game = this.settings.game;\n        let priority: AssetPriority = this.featureConfiguration.mainAssetPriority;\n\n        if (game && game.state && game.state.rounds) {\n            const rounds = this.settings.game.state.rounds;\n            if (rounds && rounds.length && rounds[0].type === 'RESPIN') {\n                priority = AssetPriority.HIGHEST;\n            }\n        }\n\n        Core.assets.addAssets([\n            {\n                id: 'characterAnimations',\n                url: '../assets/' + Core.configuration.gameKey + '/spine/characterAnimation.json',\n                priority: priority,\n                type: 'spineAnimation',\n            },\n        ]);\n    }\n\n    /*  public onIndividualAssetLoaded(asset: any): void {\n        super.onIndividualAssetLoaded.apply(this, arguments);\n        if (asset.asset.id === this.featureConfiguration.showAfterAssetIsLoaded) {\n            this.view.onComponentReady();\n        }\n    } */\n}\n","import { AssetPriority, BaseComponentConfiguration } from '@egt/core';\nimport { ZOrders } from '@egt/slot';\nimport { ICharacterAnimationFeatureConfiguration } from './ICharacterAnimationFeatureConfiguration';\n\nexport default class CharacterAnimationFeatureConfiguration extends BaseComponentConfiguration {}\n\nexport function characterAnimationConfigFactory(): any {\n    class CharacterAnimationFeatureConfigurationInternalClass\n        extends CharacterAnimationFeatureConfiguration\n        implements ICharacterAnimationFeatureConfiguration\n    {\n        /** Apperance duration of the background animation in seconds, after it is loaded */\n        public fadeInDuration: number = 1;\n\n        /** Default looping animation to start playing */\n        public idleAnimationName: string = 'Idle';\n\n        public mainAssetPriority: AssetPriority = AssetPriority.LOW;\n\n        // if override this assets to be different from feature main assets should guarantee \"characterAnimations\" assets is loaded before your asset\n        public showAfterAssetIsLoaded: string = 'characterAnimations';\n        public viewZIndex: number = ZOrders.REELS_LEVEL - 1;\n\n        // public triggerCharacterAnimCascade: number = 4;\n        // public triggerCharacterAnimWinFactor: number = 5;\n        public triggerCharacterAnimWinMultiplierValueFs: number = 8;\n        public triggerCharacterAnimWinMultiplierValueSFs: number = 32;\n        public characterWinAnimIndex: number = 1;\n        public hasFreeSpinsWinAnimation: boolean = false;\n    }\n    return CharacterAnimationFeatureConfigurationInternalClass;\n}\n","import Core, { BaseController, IOrientation } from '@egt/core';\nimport { take, takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport CharacterAnimationsView from '../views/CharacterAnimationsView';\n\n@injectable()\nexport default class CharacterAnimationsController extends BaseController {\n    public ready: () => Promise<void>;\n\n    constructor(@inject('CharacterAnimationsView') protected view: CharacterAnimationsView) {\n        super(view);\n    }\n\n    public destroy(): void {\n        // Do something\n        super.destroy();\n    }\n\n    public async onGameStarted(_settings: any): Promise<void> {\n        Core.ORIENTATION.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n        await this.ready();\n\n        this.view.onGameStarted();\n    }\n\n    /**\n     * Prepare next animation to be played after the current one is finished. Using changeAnimation method internally.\n     * @param {string} type - The animation type to change to\n     * @param {number} mixingDuration - The mixing duration of the animation change.\n     * @param {boolean} loop - Wether the animation should loop or not.\n     */\n    protected prepareNextAnimation(type: string, mixingDuration: number = 0.2, loop: boolean = false): void {\n        this.view.ON_ANIMATION_COMPLETE.pipe(take(1), takeUntil(this.DESTROY)).subscribe(() => {\n            this.view.changeAnimation(type, mixingDuration, loop);\n        });\n    }\n\n    protected setOrientation(orientation: IOrientation): void {\n        this.view.setOrientation(orientation);\n    }\n}\n","export enum SPINES {\n    BASE = 'characterAnimations',\n    FREESPINS = 'characterAnimationsFreespins',\n    SECOND_CHARACTER_FREESPINS = 'secondCharacterAnimationsFreespins',\n}\n\nexport default SPINES;\n","import Core, { IOrientation, Timers } from '@egt/core';\nimport { ViewContainer } from '@egt/ui-lib';\nimport gsap from 'gsap';\nimport { Sprite } from 'pixi.js';\nimport { BehaviorSubject, Subject } from 'rxjs';\nimport { skip, takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { ICharacterAnimationFeatureConfiguration } from '../configurations/ICharacterAnimationFeatureConfiguration';\nimport { SPINES } from '../enums/AnimationTypes';\nimport { RootStore } from '@egt/slot';\n\n@injectable()\nexport default class CharacterAnimationsView extends ViewContainer {\n    public animation: any;\n    public onCompleteIdle2Anim: any;\n    public ON_ANIMATION_STARTED: BehaviorSubject<{ type: string }> = new BehaviorSubject({ type: '' });\n    public ON_ANIMATION_COMPLETE: Subject<void> = new Subject<void>();\n    public ON_ANIMATION_FADED_IN: Subject<void> = new Subject<void>();\n    public currentAnimation: string;\n    protected staticBackgroundSprite: Sprite;\n    protected animationEventListener: any;\n    protected fadeTween: any;\n\n    ///////////////// Track Index /////////////////\n    //MAIN TRACK INDEX FOR CHARACTER ANIMATIONS\n    protected DEFAULT_TRACK_INDEX: number = 0;\n\n    ///////////////// End Track Index /////////////////\n\n    constructor(\n        @inject('CharacterAnimationFeatureConfiguration')\n        protected featureConfiguration: ICharacterAnimationFeatureConfiguration,\n        @inject('RootStore') protected rootStore: RootStore,\n    ) {\n        super();\n\n        this.currentAnimation = this.featureConfiguration.idleAnimationName;\n\n        this.animationEventListener = {\n            event: (_entry, _event) => {\n                // switch (event.data.name) {\n                //     case '':\n                //         break;\n                //     default:\n                //         break;\n                // }\n            },\n            start: (trackEntry: any) => {\n                this.ON_ANIMATION_STARTED.next({ type: trackEntry.animation.name });\n            },\n            complete: (_trackEntry: any) => {\n                // Timers.setTimeout(() => {}, 0);\n                this.ON_ANIMATION_COMPLETE.next();\n            },\n        };\n\n        this.rootStore.subjects.SET_CHARACTER_SPINE.pipe(takeUntil(this.DESTROY), skip(1)).subscribe(\n            ({ spine, alpha, visible }) => {\n                this.setAnimation(spine, ((window as any).__SLN=(alpha), ((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"spine:packages/slot-features/character-animations/src/egt/character-animations/views/CharacterAnimationsView.ts:59:17\",(window as any).__SLN]), (window as any).__SLN), visible);\n            },\n        );\n    }\n    public destroy(): void {\n        // Do something\n        this.destroyCharacterAnim();\n\n        if (this.staticBackgroundSprite) {\n            this.removeChild(this.staticBackgroundSprite);\n            this.staticBackgroundSprite.destroy();\n            // @ts-ignore\n            this.staticBackgroundSprite = null;\n        }\n\n        this.killFadeTween();\n        super.destroy();\n    }\n    public onGameStarted(): void {\n        Core.LEFT_HAND_MODE.pipe(takeUntil(this.DESTROY)).subscribe(this.setOrientation.bind(this));\n        this.initialRender();\n    }\n    public destroyCharacterAnim(): void {\n        if (this.animation) {\n            this.animation.destroy();\n            this.removeChild(this.animation);\n            // @ts-ignore\n            this.animation = null;\n        }\n    }\n\n    public setAnimation(spineName: SPINES = SPINES.BASE, alpha: number = 0, visible: boolean = true): void {\n        this.destroyCharacterAnim();\n        this.animation = Core.spineAnimations.createSpineAnimations(spineName);\n        this.animation.x = Core.display.stage.width / 2;\n        this.animation.y = Core.display.stage.height / 2;\n        this.animation.visible = false;\n        this.animation.alpha = alpha;\n        this.addChild(this.animation);\n        if (!this.animation.state.hasAnimation(this.getAnimationName())) {\n            this.currentAnimation = this.featureConfiguration.idleAnimationName;\n        }\n        this.animation.state.addListener(this.animationEventListener);\n        if (this.animation.state.hasAnimation(this.getAnimationName())) {\n            this.animation.state.setAnimation(this.DEFAULT_TRACK_INDEX, ((window as any).__SLN=(this.getAnimationName()), ((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"spine:packages/slot-features/character-animations/src/egt/character-animations/views/CharacterAnimationsView.ts:103:13\",(window as any).__SLN]), (window as any).__SLN), true);\n            this.animation.visible = visible;\n        }\n        Timers.setTimeout(() => {\n            this.setStaticTextures();\n        }, 0);\n    }\n    public characterAnimationType(): any {\n        // implement logic here\n    }\n    public setStaticTextures(): void {\n        // remove current if any\n        if (this.staticBackgroundSprite && !this.fadeTween) {\n            this.removeChild(this.staticBackgroundSprite);\n            this.staticBackgroundSprite.destroy();\n            // @ts-ignore\n            this.staticBackgroundSprite = null;\n        }\n        // if animation is loaded - do not create static sprite\n        if (this.animation) {\n            return;\n        }\n        const textureId = `characterAnimationStatic${Core.ORIENTATION.value.orientation}.png`;\n        const asset = Core.assets.getAsset('mainResources');\n        let texture = null;\n\n        if (Array.isArray(asset)) {\n            const filteredAssets = asset.filter((spritesheet) => spritesheet.textures[textureId] !== undefined);\n            if (filteredAssets.length) {\n                texture = filteredAssets[0].textures[textureId];\n            }\n        } else if (asset.spritesheet.textures[textureId]) {\n            texture = asset.spritesheet.textures[textureId];\n        }\n\n        if (texture) {\n            this.staticBackgroundSprite = new Sprite(texture);\n            this.addChild(this.staticBackgroundSprite);\n        }\n    }\n\n    /**\n     * Change the animation of the character, with or without using mixing duration.\n     * If the mixing duration is 0, the animation will change instantly without using the Spine mixing process.\n     * @param {string} type - The animation type to change to\n     * @param {number} mixingDuration - The mixing duration of the animation change.\n     * @param {boolean} loop - Wether the animation should loop or not.\n     */\n    public changeAnimation(type: string, mixingDuration: number = 0.2, loop: boolean = false): void {\n        if (!this.animation) {\n            this.currentAnimation = type;\n            return;\n        }\n        if (!this.animation.state.hasAnimation(this.getAnimationName())) {\n            this.currentAnimation = type;\n            return;\n        }\n\n        if (mixingDuration > 0) {\n            // this.animation.state.clearListeners();\n            this.animation.stateData.setMix(this.getAnimationName(), this.getAnimationName(type), mixingDuration);\n        }\n        this.currentAnimation = type;\n        this.animation.state.setAnimation(this.DEFAULT_TRACK_INDEX, ((window as any).__SLN=(this.getAnimationName(type)), ((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"spine:packages/slot-features/character-animations/src/egt/character-animations/views/CharacterAnimationsView.ts:166:9\",(window as any).__SLN]), (window as any).__SLN), loop);\n    }\n\n    /**\n     * Get the current animation type of the character.\n     * @returns {String} Returns the value of the currently playing animation.\n     */\n    public animationType(): string {\n        return this.currentAnimation;\n    }\n\n    public getAnimationName(type?: string): string {\n        return 'character' + (type || this.animationType()) + this.orientation;\n    }\n\n    /**\n     * Get the current orientation with capital first letter.\n     * @returns {String} Returns 'Portrait' or 'Landscape'.\n     */\n    public get orientation(): string {\n        return Core.ORIENTATION.value.orientation;\n    }\n\n    public initialRender(): void {\n        this.setAnimation();\n        this.playTween();\n    }\n\n    public playTween(): void {\n        this.fadeTween = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/slot-features/character-animations/src/egt/character-animations/views/CharacterAnimationsView.ts:195:26\",null]), gsap.timeline({\n            onComplete: () => {\n                this.killFadeTween();\n                this.ON_ANIMATION_FADED_IN.next();\n            },\n        }));\n        this.fadeTween.to(this.animation, {\n            duration: this.featureConfiguration.fadeInDuration,\n            alpha: 1,\n        });\n        this.fadeTween.play();\n    }\n\n    public onComponentReady(): void {\n        this.initialRender();\n    }\n\n    public setOrientation(_orientation: IOrientation): void {\n        this.setStaticTextures();\n\n        //to be deleted when we have character\n        // if (this.staticBackgroundSprite && Core.ORIENTATION.value.isPortrait) {\n        //     this.staticBackgroundSprite.y = 57;\n        // }\n\n        if (!this.animation) {\n            return;\n        }\n        if (this.animation.state.hasAnimation(this.getAnimationName())) {\n            let trackTime: number = 0;\n            // loop is preserved from the currently playing track instead of being hardcoded to true:\n            // forcing true here restarted one-shot animations (e.g. BigWin/SmallWin, started with\n            // loop=false) as looping on orientation change, so their spine 'complete' event never\n            // fired, leaving listeners attached and the animation stuck looping forever.\n            let loop: boolean = true;\n            const currentTrack = this.animation.state.getCurrent(this.DEFAULT_TRACK_INDEX);\n            if (currentTrack) {\n                trackTime = currentTrack.trackTime;\n                loop = currentTrack.loop;\n            }\n            this.animation.x = Core.display.stage.width / 2;\n            this.animation.y = Core.display.stage.height / 2;\n            this.animation.visible = true;\n            this.animation.state.setAnimation(this.DEFAULT_TRACK_INDEX, ((window as any).__SLN=(this.getAnimationName()), ((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"spine:packages/slot-features/character-animations/src/egt/character-animations/views/CharacterAnimationsView.ts:238:13\",(window as any).__SLN]), (window as any).__SLN), loop);\n            this.animation.state.getCurrent(this.DEFAULT_TRACK_INDEX).setAnimationLast(trackTime);\n            this.animation.state.getCurrent(this.DEFAULT_TRACK_INDEX).trackTime = trackTime;\n        } else {\n            this.animation.visible = false;\n        }\n        this.animation.alpha = 1;\n    }\n\n    protected killFadeTween(): void {\n        if (this.fadeTween) {\n            this.fadeTween.kill();\n            this.fadeTween = null;\n            this.setStaticTextures();\n        }\n    }\n}\n","import { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { ICharacterAnimationFeatureConfiguration } from '../configurations/ICharacterAnimationFeatureConfiguration';\nimport { RootStore } from '@egt/slot';\nimport { CascadeSubjects } from '@egt/cascade-slot';\nimport CharacterAnimationsView from './CharacterAnimationsView';\nimport Core, { Timers } from '@egt/core';\n\n@injectable()\nexport default class ClusterCascadeCharacterAnimationsView extends CharacterAnimationsView {\n    protected winAnimationCompleteListener: any;\n    private smallWinSoundIndex = 1;\n    private bigWinSoundIndex = 1;\n\n    constructor(\n        @inject('CharacterAnimationFeatureConfiguration')\n        protected featureConfiguration: ICharacterAnimationFeatureConfiguration,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('CascadeSubjects') protected cascadeSubjects: CascadeSubjects,\n    ) {\n        super(featureConfiguration, rootStore);\n        this.cascadeSubjects = cascadeSubjects;\n    }\n\n    public onGameStarted(): void {\n        super.onGameStarted();\n        this.cascadeSubjects.CHARACTER_ANIM_ON_COEFFICIENT_WIN.pipe(takeUntil(this.DESTROY)).subscribe(\n            (coefficient: string) => {\n                this.playCharacterWinAnimation(coefficient);\n            },\n        );\n    }\n\n    public destroyCharacterAnim(): void {\n        if (this.animation) {\n            if (this.winAnimationCompleteListener) {\n                this.animation.state.removeListener(this.winAnimationCompleteListener);\n                this.winAnimationCompleteListener = null;\n            }\n            this.animation.destroy();\n            this.removeChild(this.animation);\n            // @ts-ignore\n            this.animation = null;\n        }\n    }\n\n    public playCharacterWinAnimation(coefficient: string): void {\n        if (!this.animation) {\n            return;\n        }\n        let featureSuffix = '';\n        const freespinRound = this.rootStore.domainStore.betResponse?.rounds?.filter(\n            (round) => round.type === 'FREESPIN',\n        )[0];\n        const inFreeSpins = freespinRound?.remain >= 0 && freespinRound.count !== freespinRound.remain;\n        if (this.featureConfiguration.hasFreeSpinsWinAnimation && inFreeSpins) {\n            featureSuffix = 'FreeSpins';\n        }\n\n        const bigWinFullName = this.getAnimationName(featureSuffix + coefficient);\n        if (!this.animation.state.hasAnimation(bigWinFullName) || this.winAnimationCompleteListener) {\n            return;\n        }\n        let soundSuffix = '';\n        if (coefficient === 'SmallWin') {\n            soundSuffix = String(this.smallWinSoundIndex);\n            this.smallWinSoundIndex = (this.smallWinSoundIndex % 4) + 1;\n        }\n        if (coefficient === 'BigWin') {\n            soundSuffix = String(this.bigWinSoundIndex);\n            this.bigWinSoundIndex = (this.bigWinSoundIndex % 4) + 1;\n        }\n        Core.sounds.play('character' + coefficient + soundSuffix);\n        const mixDuration = 0.2;\n        let winCompleteEventFired = false;\n        this.winAnimationCompleteListener = {\n            complete: (trackEntry: any) => {\n                // Compare against the current orientation-aware name, not the one captured at the\n                // start: if orientation changed mid-animation, setOrientation() swapped the track to\n                // a new TrackEntry whose animation.name reflects the new orientation, so trackEntry\n                // would never match a stale captured name and the listener would never be cleaned up.\n                if (trackEntry?.animation?.name !== this.getAnimationName(featureSuffix + coefficient)) {\n                    return;\n                }\n                Timers.setTimeout(() => {\n                    if (this.animation && this.winAnimationCompleteListener) {\n                        this.animation.state.removeListener(this.winAnimationCompleteListener);\n                    }\n                    this.winAnimationCompleteListener = null;\n                    this.changeAnimation(this.featureConfiguration.idleAnimationName, 0, true);\n                }, 0);\n            },\n            event: (trackEntry: any, event: any) => {\n                if (\n                    trackEntry?.animation?.name !== this.getAnimationName(featureSuffix + coefficient) ||\n                    winCompleteEventFired\n                ) {\n                    return;\n                }\n                if (event.data.name === 'showBigWin') {\n                    winCompleteEventFired = true;\n                    this.cascadeSubjects.CHARACTER_ANIM_WIN_COMPLETE.next();\n                }\n            },\n        };\n        this.animation.state.addListener(this.winAnimationCompleteListener);\n        this.changeAnimation(featureSuffix + coefficient, mixDuration, false);\n        if (Core.sounds.isPlaying('sumPearls') && coefficient !== 'SmallWin') {\n            Core.sounds.stop('sumPearls');\n        }\n    }\n}\n","import CharacterAnimationsFeature from './character-animations/CharacterAnimationsFeature';\nimport CharacterAnimationFeatureConfiguration from './character-animations/configurations/CharacterAnimationFeatureConfiguration';\nimport { ICharacterAnimationFeatureConfiguration } from './character-animations/configurations/ICharacterAnimationFeatureConfiguration';\nimport CharacterAnimationsController from './character-animations/controllers/CharacterAnimationsController';\nimport SPINES from './character-animations/enums/AnimationTypes';\nimport CharacterAnimationsView from './character-animations/views/CharacterAnimationsView';\nimport ClusterCascadeCharacterAnimationsView from './character-animations/views/ClusterCascadeCharacterAnimationsView';\n\nexport {\n    CharacterAnimationsController,\n    CharacterAnimationsView,\n    CharacterAnimationsFeature,\n    ICharacterAnimationFeatureConfiguration,\n    CharacterAnimationFeatureConfiguration,\n    SPINES,\n    ClusterCascadeCharacterAnimationsView,\n};\nexport default CharacterAnimationsFeature;\n","import { Sprite, Texture } from 'pixi.js';\nimport { Subject } from 'rxjs';\nimport ViewContainer from './ViewContainer';\n\nexport default class Icon extends ViewContainer {\n    public readonly SWITCH = new Subject();\n    public readonly SWITCH_ON = new Subject();\n    public readonly SWITCH_OFF = new Subject();\n\n    protected iconSelected: Sprite;\n    protected iconDeselected: Sprite;\n\n    protected _selected: boolean = true;\n    protected _enabled: boolean = true;\n\n    constructor(textureSelected: Texture, textureDeselected: Texture) {\n        super();\n\n        // Create the Sprites for both selected and deselected states\n        this.iconSelected = new Sprite(textureSelected);\n        this.iconDeselected = new Sprite(textureDeselected);\n\n        // Center the icons\n        this.iconSelected.anchor.set(0);\n        this.iconDeselected.anchor.set(0);\n\n        // Add both icons to the container\n        this.addChild(this.iconSelected);\n        this.addChild(this.iconDeselected);\n\n        // Set initial selection state\n        this.selected = false;\n\n        // Make the icons interactive\n        this.interactive = true;\n        this.iconSelected.interactive = true;\n        this.iconDeselected.interactive = true;\n\n        // Set up click event listeners\n        // fromEvent(this.iconSelected, 'pointertap')\n        //     .pipe(takeUntil(this.DESTROY))\n        //     .subscribe(this.onSelectedClicked.bind(this));\n\n        // fromEvent(this.iconDeselected, 'pointertap')\n        //     .pipe(takeUntil(this.DESTROY))\n        //     .subscribe(this.onDeselectedClicked.bind(this));\n    }\n\n    public destroy(): void {\n        this.iconSelected.destroy({ children: true });\n        this.iconDeselected.destroy({ children: true });\n\n        this.SWITCH.complete();\n        this.SWITCH_ON.complete();\n        this.SWITCH_OFF.complete();\n\n        super.destroy({ children: true, texture: true });\n    }\n\n    set enabled(value: boolean) {\n        this._enabled = value;\n        this.interactive = value;\n        this.iconSelected.interactive = value;\n        this.iconDeselected.interactive = value;\n    }\n\n    get selected(): boolean {\n        return this._selected;\n    }\n\n    set selected(value: boolean) {\n        this.setSelection(value, false);\n    }\n\n    set interactiveMode(value: boolean) {\n        this.interactive = value;\n        this.iconSelected.interactive = value;\n        this.iconDeselected.interactive = value;\n    }\n\n    protected onSelectedClicked(): void {\n        if (!this._enabled) {\n            return;\n        }\n        this.setSelection(false, true);\n    }\n\n    protected onDeselectedClicked(): void {\n        if (!this._enabled) {\n            return;\n        }\n        this.setSelection(true, true);\n    }\n\n    protected setSelection(selected: boolean, triggerEvents: boolean): void {\n        if (this._selected !== selected) {\n            this._selected = selected;\n\n            // Toggle visibility based on selection\n            this.iconSelected.visible = selected;\n            this.iconDeselected.visible = !selected;\n\n            if (triggerEvents) {\n                this.SWITCH.next(selected);\n                if (selected) {\n                    this.SWITCH_ON.next(selected);\n                } else {\n                    this.SWITCH_OFF.next(selected);\n                }\n            }\n        }\n    }\n}\n","import { JackpotLevelStats, JackpotStatsResponse, StatsIntervalTracker } from '@egt/core';\nimport { Observable } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { injectable } from 'tsyringe';\nimport ViewContainer from './ViewContainer';\nimport BangUpText from './texts/BangUpText';\nimport JackpotBangUpBitMapText from './texts/JackpotBangUpBitMapText';\n\n/**\n * The counter API this base needs - every feature's bang-up text provides it.\n * `gsapSync` is optional because the non-bitmap counters tick on a timer.\n */\ntype IJackpotCounter = BangUpText & {\n    setValue(value: number): void;\n    start(bangUpTo: number, startFrom: number, bangUpTime: number, gsapSync?: boolean): void;\n};\n\n/** The part of a bet response the counters need: the jackpot levels the player won on it */\nexport interface IJackpotWinningBet {\n    jpw?: IJackpotWin[];\n}\n\nexport interface IJackpotWin {\n    amount?: number;\n    jackpotName?: string;\n    levelId?: number;\n    levelName?: string;\n    type?: string;\n    winId?: number;\n}\n\nexport enum JackpotLevel {\n    GRAND = 0,\n    MAJOR = 1,\n    MINOR = 2,\n    MINI = 3,\n}\n\n/**\n * Shared behaviour of the jackpot counters views: the counters and their last\n * known values indexed by level id - 1, and the bang-up on a stats push.\n *\n * @typeParam TCounter the bang-up text the feature uses for its counters\n */\n@injectable()\nexport default class JackpotCounterBase<\n    TCounter extends IJackpotCounter = JackpotBangUpBitMapText,\n> extends ViewContainer {\n    protected jackpotBangupTextsArray: TCounter[] = [];\n    protected jackpotValuesArray: number[] = [0, 0, 0, 0];\n\n    /**\n     * Bang-up duration is derived from the measured interval between stats pushes,\n     * so a bang-up finishes just as the next one arrives - a longer duration\n     * leaves the counter permanently trailing the real value.\n     */\n    protected statsInterval: StatsIntervalTracker = new StatsIntervalTracker();\n\n    /**\n     * Level ids a stats push may bang up, or null for every level in the response.\n     * Views whose lower levels are derived locally - from the denomination or the\n     * selected bet - restrict this so a pushed value cannot fight the local one.\n     */\n    protected statsDrivenLevelIds: number[] | null = null;\n\n    /**\n     * Wins of the current bet (win key -> level id) whose splash has not been seen yet. A stats push\n     * does not touch their levels, so the reset value does not show up before the player has seen the\n     * won splash - see holdWonLevelsUntilSplash.\n     */\n    private heldWins: Map<string, number> = new Map();\n\n    /**\n     * Keys of wins whose splash was already seen. A multi-spin result emits BET once per spin with the\n     * same jpw (DomainStore.bet), and some features re-emit a response - such a replay must not hold a\n     * level again, as no second splash would release it.\n     */\n    private releasedWinKeys: Set<string> = new Set();\n\n    /** the last stats push, replayed into the held counters when they are released */\n    protected lastStatsResponse: JackpotStatsResponse | null = null;\n\n    /** level names in level id order, used to map a won jackpot to its counter */\n    protected wonLevelNames: string[] = ['grand', 'major', 'minor', 'mini'];\n\n    public destroy(): void {\n        this.jackpotBangupTextsArray.forEach((element) => {\n            element.destroy();\n        });\n        this.jackpotBangupTextsArray.length = 0;\n        super.destroy({ children: true, texture: true });\n    }\n    public presetCounters(jackpotStatsResponse: JackpotStatsResponse): void {\n        if (jackpotStatsResponse.levelStats) {\n            jackpotStatsResponse.levelStats?.forEach((levelStats) => {\n                if (this.statsDrivenLevelIds && !this.statsDrivenLevelIds.includes(levelStats.levelId)) {\n                    return;\n                }\n                const jackpotStats: JackpotLevelStats = this.getJackpotStatsById(\n                    levelStats.levelId,\n                    jackpotStatsResponse.levelStats,\n                );\n                const counter: TCounter = this.jackpotBangupTextsArray[levelStats.levelId - 1];\n                this.jackpotValuesArray[levelStats.levelId - 1] = jackpotStats?.currentValue;\n                // Presetting is a jump, not a bang-up - keep currentValue in step with\n                // the display so the next bang-up starts from what is on screen.\n                if (counter) {\n                    counter.currentValue = jackpotStats?.currentValue;\n                    counter.setValue(jackpotStats?.currentValue);\n                }\n            });\n        }\n    }\n    public updateJackpot(jackpotStatsResponse: JackpotStatsResponse): void {\n        if (!jackpotStatsResponse.levelStats) {\n            return;\n        }\n        this.lastStatsResponse = jackpotStatsResponse;\n\n        const bangUpTime: number = this.statsInterval.nextBangUpTime();\n\n        jackpotStatsResponse.levelStats.forEach((levelStats) => {\n            if (this.statsDrivenLevelIds && !this.statsDrivenLevelIds.includes(levelStats.levelId)) {\n                return;\n            }\n            if (this.isLevelHeld(levelStats.levelId)) {\n                return;\n            }\n            const jackpotStats: JackpotLevelStats = this.getJackpotStatsById(\n                levelStats.levelId,\n                jackpotStatsResponse.levelStats,\n            );\n            const counter: TCounter = this.jackpotBangupTextsArray[levelStats.levelId - 1];\n            if (\n                jackpotStats &&\n                counter &&\n                this.jackpotValuesArray[levelStats.levelId - 1] !== jackpotStats.currentValue\n            ) {\n                // Bang up from the value that is actually on screen, not from the\n                // previous server value. The previous bang-up is normally still\n                // running when the next stats arrive, so its target was never\n                // reached - starting from it snaps the counter forward and the\n                // bang-up reads as a jump instead of a climb. `current` is the\n                // displayed value on every bang-up text, `currentValue` only on\n                // the gsap driven ones.\n                counter.start(jackpotStats.currentValue, counter.current, bangUpTime, true);\n                this.jackpotValuesArray[levelStats.levelId - 1] = jackpotStats.currentValue;\n            }\n        });\n    }\n\n    /**\n     * Keeps the counters of the levels the player wins on a bet at their value until `splashVisible`\n     * emits, then shows the latest pushed value. Wins by other players are not affected.\n     * Call once when the counters are set up.\n     *\n     * @param bets every bet response (`rootStore.domainStore.BET`)\n     * @param splashVisible emits once the jackpot won splash covers the counters\n     */\n    protected holdWonLevelsUntilSplash(bets: Observable<IJackpotWinningBet>, splashVisible: Observable<unknown>): void {\n        bets.pipe(takeUntil(this.DESTROY)).subscribe((bet) => this.onWinningBet(bet));\n        splashVisible.pipe(takeUntil(this.DESTROY)).subscribe(() => this.releaseHeldLevels());\n    }\n\n    protected isLevelHeld(levelId: number): boolean {\n        return Array.from(this.heldWins.values()).includes(levelId);\n    }\n\n    /** shows the latest pushed value in the held counters - override to refresh what depends on them */\n    protected releaseHeldLevels(): void {\n        const heldWins = this.heldWins;\n        this.heldWins = new Map();\n        heldWins.forEach((levelId, winKey) => {\n            this.releasedWinKeys.add(winKey);\n            this.setLevelFromLastStats(levelId);\n        });\n    }\n\n    private onWinningBet(bet: IJackpotWinningBet): void {\n        const wins = (bet?.jpw ?? []).filter((jackpotWin) => this.isOwnWin(jackpotWin));\n        const winKeys = wins.map((jackpotWin) => this.getWinKey(jackpotWin));\n\n        // A replay of the same result keeps its hold. Any other bet means the held splash will not come\n        // any more - release, so a counter cannot stay frozen.\n        const isReplay =\n            this.heldWins.size > 0 && Array.from(this.heldWins.keys()).every((key) => winKeys.includes(key));\n        if (isReplay) {\n            return;\n        }\n        this.releaseHeldLevels();\n        // only wins this bet can still replay need remembering\n        this.releasedWinKeys = new Set(winKeys.filter((key) => this.releasedWinKeys.has(key)));\n\n        wins.forEach((jackpotWin, index) => {\n            const levelId = this.getWonLevelId(jackpotWin);\n            const isStatsDriven = !this.statsDrivenLevelIds || this.statsDrivenLevelIds.includes(levelId);\n            if (levelId > 0 && isStatsDriven && !this.releasedWinKeys.has(winKeys[index])) {\n                this.heldWins.set(winKeys[index], levelId);\n            }\n        });\n    }\n\n    /**\n     * Whether a jpw entry is a win this feature plays a splash for. Only those hold a counter - one that\n     * gets no splash would stay frozen until the next bet. Override where one bet can win jackpots of\n     * different features (Premium Link + single progressive), mirroring the check that plays the win.\n     */\n    protected isOwnWin(_jackpotWin: IJackpotWin): boolean {\n        return true;\n    }\n\n    /** identifies a win across the replays of one result - the server winId, else what describes it */\n    private getWinKey(jackpotWin: IJackpotWin): string {\n        if (jackpotWin.winId !== undefined && jackpotWin.winId !== null) {\n            return `id:${jackpotWin.winId}`;\n        }\n        return `${jackpotWin.jackpotName}|${jackpotWin.levelId ?? jackpotWin.levelName}|${jackpotWin.amount}`;\n    }\n\n    /** jumps a counter to the last pushed value, the way presetCounters() does */\n    protected setLevelFromLastStats(levelId: number): void {\n        const jackpotStats = this.lastStatsResponse\n            ? this.getJackpotStatsById(levelId, this.lastStatsResponse.levelStats)\n            : undefined;\n        const counter: TCounter = this.jackpotBangupTextsArray[levelId - 1];\n        if (!jackpotStats || !counter) {\n            return;\n        }\n        this.jackpotValuesArray[levelId - 1] = jackpotStats.currentValue;\n        counter.currentValue = jackpotStats.currentValue;\n        counter.setValue(jackpotStats.currentValue);\n    }\n\n    /** level id of a won jackpot - by name where it is one of wonLevelNames, else the server id */\n    protected getWonLevelId(jackpotWin: IJackpotWin): number {\n        const byName = this.wonLevelNames.indexOf(jackpotWin.levelName?.toLowerCase() ?? '') + 1;\n        return byName || jackpotWin.levelId || 0;\n    }\n\n    protected getJackpotStatsById(levelID: number, levelStats: JackpotLevelStats[]): JackpotLevelStats {\n        let jackpotStats: any;\n        if (levelStats) {\n            for (const stats of levelStats) {\n                if (stats.levelId === levelID) {\n                    jackpotStats = stats;\n                }\n            }\n        }\n\n        return jackpotStats;\n    }\n}\n","import { Sprite, Text, TextStyle, Texture } from 'pixi.js';\nimport { Subject, fromEvent } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport ViewContainer from './ViewContainer';\n\nexport default class Slider extends ViewContainer {\n    public readonly CHANGE: Subject<number> = new Subject<number>();\n\n    protected minValue: number;\n    protected maxValue: number;\n    protected sliderWidth: number;\n    protected sliderHeight: number;\n    protected minSpinsText: Text;\n    protected maxSpinsText: Text;\n    protected valuesXOffset: number;\n    protected stepsSelectedTexture: Texture;\n    protected stepsNotSelectedTexture: Texture;\n    protected stepsSelected: Sprite;\n    protected stepsNotSelected: Sprite;\n    protected handleTexture: Texture;\n    protected handle: Sprite;\n    protected textStyle: TextStyle;\n    protected dragging: boolean = false;\n    protected data: any;\n    protected delta: any;\n    protected initialSliderPosition: number;\n    protected tooltip: Text;\n    protected tooltipYOffset: number;\n\n    constructor(options: any) {\n        super();\n\n        this.minValue = options.minValue || 0;\n        this.maxValue = options.maxValue || 100;\n        this.handleTexture = options.handleTexture || Texture.EMPTY;\n        this.sliderWidth = options.sliderWidth || 100;\n        this.sliderHeight = options.sliderHeight || 10;\n        this.valuesXOffset = options.valuesXOffset || 10;\n        this.stepsSelectedTexture = options.stepsSelected || Texture.EMPTY;\n        this.stepsNotSelectedTexture = options.stepsNotSelected || Texture.EMPTY;\n        this.tooltipYOffset = options.tooltipYOffset || -30;\n        this.textStyle =\n            options.textStyle ||\n            new TextStyle({\n                fill: '#FFFFFF',\n                fontFamily: 'Arial',\n                fontSize: 20,\n            });\n    }\n\n    public init(): void {\n        this.initialRender();\n    }\n\n    public setSliderValue = (x: number): void => {\n        this.handle.x =\n            (x * (this.sliderWidth - this.handle.width + this.valuesXOffset)) / 100 + this.initialSliderPosition;\n        this.tooltip.x = this.handle.x + (this.handle.width - this.tooltip.width) / 2;\n        this.tooltip.text = this.getSliderValue().toString();\n        this.stepsSelected.width = (this.sliderWidth * this.getSliderValue()) / 100;\n    };\n\n    public getSliderValue = (): number => {\n        return Math.ceil(\n            ((this.handle.x - this.initialSliderPosition) /\n                (this.sliderWidth - this.handle.width + this.valuesXOffset)) *\n                this.maxValue,\n        );\n    };\n\n    protected initialRender(): void {\n        this.minSpinsText = new Text(this.minValue.toString(), this.textStyle);\n        this.minSpinsText.x = 0;\n        this.minSpinsText.y = 0;\n        this.addChild(this.minSpinsText);\n\n        this.maxSpinsText = new Text(this.maxValue.toString(), this.textStyle);\n        this.maxSpinsText.x = this.minSpinsText.x + this.minSpinsText.width + this.sliderWidth + this.valuesXOffset * 2;\n        this.maxSpinsText.y = 0;\n        this.addChild(this.maxSpinsText);\n\n        this.stepsNotSelected = new Sprite(this.stepsNotSelectedTexture);\n        this.stepsNotSelected.x = this.minSpinsText.x + this.minSpinsText.width + this.valuesXOffset;\n        this.stepsNotSelected.y = (this.minSpinsText.height - this.sliderHeight) / 2;\n        this.stepsNotSelected.width = this.sliderWidth;\n        this.stepsNotSelected.height = this.sliderHeight;\n        this.addChild(this.stepsNotSelected);\n\n        this.stepsSelected = new Sprite(this.stepsSelectedTexture);\n        this.stepsSelected.x = this.stepsNotSelected.x;\n        this.stepsSelected.y = this.stepsNotSelected.y;\n        this.stepsSelected.width = 0;\n        this.stepsSelected.height = this.sliderHeight;\n        this.addChild(this.stepsSelected);\n\n        this.initialSliderPosition = this.stepsNotSelected.x - this.valuesXOffset / 2;\n        this.handle = new Sprite(this.handleTexture);\n        this.handle.x = this.initialSliderPosition;\n        this.handle.y = (this.minSpinsText.height - this.handle.height) / 2;\n        this.handle.interactive = true;\n        this.handle.buttonMode = true;\n        this.addChild(this.handle);\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/slot-features/ui-lib/src/egt/ui/Slider.ts:104:9\",(this.handle),\"pointerdown\"]), fromEvent(this.handle, 'pointerdown'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe((e: any) => {\n                this.data = e;\n                this.delta = e.data.getLocalPosition(this.handle).x;\n                this.dragging = true;\n            });\n\n        fromEvent(this.handle, 'pointermove')\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe((_e: any) => {\n                if (this.dragging) {\n                    const move = this.data.data.getLocalPosition(this.handle.parent);\n                    if (move.y >= this.handle.y && move.y <= this.handle.y + this.handle.height) {\n                        const value = this.pixelToValue(move.x - this.delta);\n                        this.handle.x = this.valueToPixel(value);\n                        this.tooltip.x = this.handle.x + (this.handle.width - this.tooltip.width) / 2;\n                        this.tooltip.text = this.getSliderValue().toString();\n                        this.stepsSelected.width = (this.sliderWidth * this.getSliderValue()) / 100;\n                        this.CHANGE.next(this.getSliderValue());\n                    }\n                }\n            });\n\n        this.tooltip = new Text('0', this.textStyle);\n        this.tooltip.x = this.handle.x + (this.handle.width - this.tooltip.width) / 2;\n        this.tooltip.y = this.handle.y + this.tooltipYOffset;\n        this.addChild(this.tooltip);\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/slot-features/ui-lib/src/egt/ui/Slider.ts:133:9\",(document.body),\"touchend\"]), fromEvent(document.body, 'touchend')).pipe(takeUntil(this.DESTROY)).subscribe(this.endDrag.bind(this));\n\n        fromEvent(document.body, 'mouseup').pipe(takeUntil(this.DESTROY)).subscribe(this.endDrag.bind(this));\n    }\n\n    protected endDrag(): void {\n        this.data = null;\n        this.dragging = false;\n    }\n\n    protected valueToPixel(value: number): number {\n        if (value < this.minValue) {\n            value = this.minValue;\n        } else if (value > this.maxValue) {\n            value = this.maxValue;\n        }\n        return (\n            this.initialSliderPosition + (this.sliderWidth * (value - this.minValue)) / (this.maxValue - this.minValue)\n        );\n    }\n\n    protected pixelToValue(pixel: number): number {\n        if (pixel < 0) {\n            pixel = 0;\n        } else if (pixel > this.sliderWidth) {\n            pixel = this.sliderWidth;\n        }\n        return (\n            this.minValue +\n            ((this.maxValue - this.minValue) * (pixel - this.handle.width + this.valuesXOffset)) / this.sliderWidth\n        );\n    }\n}\n","import Core from '@egt/core';\nimport { Container, Graphics, Rectangle, Sprite, Texture } from 'pixi.js';\nimport { BehaviorSubject, fromEvent } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport ViewContainer from './ViewContainer';\n\nexport default class SteppedSlider extends ViewContainer {\n    public readonly CHANGE: BehaviorSubject<number> = new BehaviorSubject<number>(0);\n    public readonly VALUE_REACHED: BehaviorSubject<number> = new BehaviorSubject<number>(-1);\n    public inactiveHandleTexture: Texture;\n    public activeHandleTexture: Texture;\n    public hoverHandleTexture: Texture;\n    public disabledHandleTexture: Texture;\n    public pressedHandleTexture: Texture;\n    public inactiveDotTexture: Texture;\n    public activeDotTexture: Texture;\n    public steps: number[];\n\n    protected _state: SteppedSliderStates = SteppedSliderStates.Inactive;\n\n    protected minValue: number;\n    // protected maxValue: number;\n    protected sliderWidth: number;\n    protected sliderHeight: number;\n\n    protected stepsSelected: Container;\n    protected stepsNotSelected: Container;\n    protected stepsSelectedTexture: Texture;\n    protected stepsNotSelectedTexture: Texture;\n    protected useSteps: boolean;\n    protected handle: Sprite;\n    protected handleDimensions: Record<string, number> | null;\n    protected dragging: boolean = false;\n    protected data: any;\n    protected delta: any;\n    protected notSelectedFill: any;\n    protected selectedFill: any;\n    protected activeOffset: number;\n    protected stepsSectors: number[] = [];\n    protected selectedStep: number;\n    protected currentStep: number;\n    protected stepsOffset: number;\n    protected stepsRadius: number;\n    protected slideStepsTolerance: number;\n    protected touchStepsTolerance: number;\n    protected useDotSteps: boolean = true;\n\n    private stepsActiveArr: Container[] = [];\n    private stepsInactiveArr: Container[] = [];\n\n    constructor(options: any) {\n        super();\n        this.interactive = true;\n\n        this.minValue = options.minValue || 0;\n        // this.maxValue = options.maxValue || 100;\n        this.stepsNotSelectedTexture = options.stepsNotSelectedTexture;\n        this.inactiveHandleTexture = options.inactiveHandleTexture || Texture.EMPTY;\n        this.inactiveDotTexture = options.inactiveDotTexture;\n        this.stepsSelectedTexture = options.stepsSelectedTexture;\n        this.activeHandleTexture = options.activeHandleTexture || Texture.EMPTY;\n        this.hoverHandleTexture = options.hoverHandleTexture;\n        this.disabledHandleTexture = options.disabledHandleTexture || options.activeHandleTexture;\n        this.pressedHandleTexture = options.pressedHandleTexture || options.activeHandleTexture;\n        this.activeDotTexture = options.activeDotTexture;\n        this.sliderWidth = options.sliderWidth || 100;\n        this.sliderHeight = options.sliderHeight || 10;\n        this.notSelectedFill = options.notSelectedFill;\n        this.selectedFill = options.selectedFill;\n        this.steps = options.steps || null;\n        this.useSteps = options.useSteps !== false;\n        this.stepsRadius = options.stepsRadius || 10;\n        this.handleDimensions = options.handleDimensions || null;\n        if (options.hasOwnProperty('useStepsDots')) {\n            this.useDotSteps = options.useStepsDots;\n        }\n    }\n\n    public init(): void {\n        this.initialRender();\n    }\n\n    private attachEventListeners() {\n        fromEvent(this.handle, 'pointerover').pipe(takeUntil(this.DESTROY)).subscribe(this.onHandleHover.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/slot-features/ui-lib/src/egt/ui/SteppedSlider.ts:86:9\",(this.handle),\"pointerup\"]), fromEvent(this.handle, 'pointerup')).pipe(takeUntil(this.DESTROY)).subscribe(this.onHandleReleased.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/slot-features/ui-lib/src/egt/ui/SteppedSlider.ts:88:9\",(this.handle),\"pointerupoutside\"]), fromEvent(this.handle, 'pointerupoutside'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onHandleReleased.bind(this));\n\n        fromEvent(this.handle, 'pointerout').pipe(takeUntil(this.DESTROY)).subscribe(this.onHandleReleased.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/slot-features/ui-lib/src/egt/ui/SteppedSlider.ts:94:9\",(this.handle.parent),\"pointerdown\"]), fromEvent(this.handle.parent, 'pointerdown'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe((e: any) => {\n                this.data = e;\n                this.delta = e.data.getLocalPosition(this.handle).x;\n                this.dragging = true;\n                const pressing = this.handle.containsPoint({\n                    x: e.data.global.x,\n                    y: e.data.global.y,\n                });\n                if (pressing) {\n                    this.state = SteppedSliderStates.Pressed;\n                } else {\n                    this.forceDragSlider(e);\n                }\n            });\n\n        fromEvent(this.handle.parent, 'pointermove')\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe((_e: any) => {\n                if (this.dragging) {\n                    const move = this.data.data.getLocalPosition(this.handle.parent);\n                    const value = this.pixelToValue(move.x);\n                    if (this.useSteps) {\n                        this.currentStep = Math.floor(value);\n                        this.handle.x = this.valueToPixel(value);\n                        this.stepsSelected.width = this.handle.x;\n                        // in some cases this goes negative and progress is drawn to back ?!?\n                        this.stepsSelected.scale.x = Math.abs(this.stepsSelected.scale.x);\n\n                        this.stepsActiveArr.forEach((step: any, _index) => {\n                            let x: number;\n                            if (step instanceof Sprite) {\n                                x = step.x;\n                            } else {\n                                x = step.getLocalBounds().x;\n                            }\n                            if (x < this.handle.x) {\n                                step.visible = true;\n                            } else {\n                                step.visible = false;\n                            }\n                        });\n                    } else {\n                        this.currentStep = Math.ceil(value);\n                        this.handle.x = this.valueToPixel(value);\n                        const roundedValue = (this.steps[this.steps.length - 1] / 100) * this.currentStep;\n                        this.setSliderValue(roundedValue);\n                        if (roundedValue > 0) {\n                            this.stepsSelected.width = Math.min(move.x, this.sliderWidth);\n                            if (this.stepsActiveArr[this.stepsActiveArr.length - 1]) {\n                                this.stepsActiveArr[this.stepsActiveArr.length - 1].visible = true;\n                            }\n                            if (this.stepsInactiveArr[this.stepsInactiveArr.length - 1]) {\n                                this.stepsInactiveArr[this.stepsInactiveArr.length - 1].visible = false;\n                            }\n                        } else {\n                            this.stepsSelected.width = 0;\n                        }\n                        this.state = SteppedSliderStates.Pressed;\n                    }\n                }\n            });\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/slot-features/ui-lib/src/egt/ui/SteppedSlider.ts:158:9\",(this.handle.parent),\"pointerupoutside\"]), fromEvent(this.handle.parent, 'pointerupoutside'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe((e: any) => {\n                if (this.dragging) {\n                    this.forceDragSlider(e);\n                    this.data = null;\n                    this.dragging = false;\n                }\n            });\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/slot-features/ui-lib/src/egt/ui/SteppedSlider.ts:168:9\",(this.handle.parent),\"pointerup\"]), fromEvent(this.handle.parent, 'pointerup'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe((e: any) => {\n                if (this.dragging) {\n                    const hover = this.handle.containsPoint({\n                        x: e.data.global.x,\n                        y: e.data.global.y,\n                    });\n\n                    if (hover && !this.useSteps) {\n                        if (Core.isDesktopMode && this.hoverHandleTexture) {\n                            this.state = SteppedSliderStates.Over;\n                        }\n                    } else {\n                        this.forceDragSlider(e);\n                    }\n                    this.data = null;\n                    this.dragging = false;\n                }\n            });\n    }\n\n    public setSliderValue(value: number): void {\n        this.CHANGE.next(value);\n    }\n\n    public getSliderValue = (): number => {\n        return this.CHANGE.value;\n    };\n\n    public resetSlider(): void {\n        this.stepsActiveArr.forEach((stepSprite) => {\n            if (stepSprite) {\n                stepSprite.visible = false;\n            }\n        });\n        this.currentStep = 0;\n        this.setSliderValue(this.steps[0]);\n        this.stepsSelected.width = 0;\n        this.handle.x = this.valueToPixel(0);\n        this.state = this.steps[0] === 0 ? SteppedSliderStates.Inactive : SteppedSliderStates.Active;\n    }\n\n    protected initialRender(): void {\n        // add active / inactive lines from texture or draw them\n        if (this.stepsNotSelectedTexture) {\n            this.stepsNotSelected = new Sprite(this.stepsNotSelectedTexture);\n        } else {\n            this.stepsNotSelected = new Graphics();\n            (this.stepsNotSelected as Graphics).beginFill(this.notSelectedFill);\n            (this.stepsNotSelected as Graphics).drawRect(this.x, this.y, this.sliderWidth, this.sliderHeight);\n            (this.stepsNotSelected as Graphics).endFill();\n        }\n        this.addChild(this.stepsNotSelected);\n        this.stepsNotSelected.name = 'stepsNotSelectedLine';\n        this.stepsNotSelected.width = this.sliderWidth;\n        this.stepsNotSelected.height = this.sliderHeight;\n\n        if (this.stepsSelectedTexture) {\n            this.stepsSelected = new Sprite(this.stepsSelectedTexture);\n        } else {\n            this.stepsSelected = new Graphics();\n            (this.stepsSelected as Graphics).beginFill(this.selectedFill);\n            (this.stepsSelected as Graphics).drawRect(\n                this.stepsNotSelected.x,\n                this.stepsNotSelected.y,\n                0.1,\n                this.sliderHeight,\n            );\n            (this.stepsSelected as Graphics).endFill();\n        }\n        this.addChild(this.stepsSelected);\n        this.stepsSelected.name = 'stepsSelectedLine';\n        this.stepsSelected.width = 0.1;\n        this.stepsSelected.height = this.sliderHeight;\n\n        // add step points\n        if (this.steps && this.useDotSteps) {\n            this.selectedStep = this.steps[0];\n            this.CHANGE.next(this.selectedStep);\n            this.stepsOffset = 100 / (this.steps.length - 1);\n            this.activeOffset = parseFloat((this.stepsOffset / 2).toFixed(1));\n            this.slideStepsTolerance = Math.floor(this.activeOffset / 4);\n            this.touchStepsTolerance = Math.floor(this.activeOffset);\n            for (let i = 0; i < this.steps.length; i++) {\n                this.stepsSectors.push(this.activeOffset + this.activeOffset * i * 2);\n\n                let stepInactiveDot: Container;\n                if (this.inactiveDotTexture) {\n                    stepInactiveDot = new Sprite(this.inactiveDotTexture);\n                    stepInactiveDot.pivot.x = stepInactiveDot.width / 2;\n                    stepInactiveDot.pivot.y = stepInactiveDot.height / 2;\n                    stepInactiveDot.x = this.sliderWidth - i * (this.sliderWidth / (this.steps.length - 1));\n                    stepInactiveDot.y = this.sliderHeight / 2;\n                } else {\n                    stepInactiveDot = new Graphics();\n                    (stepInactiveDot as Graphics).beginFill(0x585858, 1);\n                    (stepInactiveDot as Graphics).drawCircle(\n                        this.sliderWidth - i * (this.sliderWidth / (this.steps.length - 1)),\n                        this.sliderHeight / 2,\n                        this.stepsRadius,\n                    );\n                    (stepInactiveDot as Graphics).endFill();\n                }\n                this.addChild(stepInactiveDot);\n                stepInactiveDot.name = 'stepInactive' + i;\n                this.stepsInactiveArr.push(stepInactiveDot);\n\n                let stepActiveDot;\n                if (this.activeDotTexture) {\n                    stepActiveDot = new Sprite(this.activeDotTexture);\n                    stepActiveDot.pivot.x = stepActiveDot.width / 2;\n                    stepActiveDot.pivot.y = stepActiveDot.height / 2;\n                    stepActiveDot.x = this.sliderWidth - i * (this.sliderWidth / (this.steps.length - 1));\n                    stepActiveDot.y = this.sliderHeight / 2;\n                } else {\n                    stepActiveDot = new Graphics();\n                    (stepActiveDot as Graphics).beginFill(this.selectedFill, 1);\n                    (stepActiveDot as Graphics).drawCircle(\n                        this.sliderWidth - i * (this.sliderWidth / (this.steps.length - 1)),\n                        this.sliderHeight / 2,\n                        this.stepsRadius,\n                    );\n                    (stepActiveDot as Graphics).endFill();\n                }\n                this.addChild(stepActiveDot);\n                stepActiveDot.name = 'stepActive' + i;\n                stepActiveDot.visible = false;\n                this.stepsActiveArr.push(stepActiveDot);\n            }\n        }\n\n        // add handle\n        this.handle = new Sprite(this.steps[0] === 0 ? this.inactiveHandleTexture : this.activeHandleTexture);\n        this.handle.anchor.set(0, 0.5);\n        this.handle.x = this.stepsNotSelected.x - this.handle.width / 2;\n        this.handle.y = this.stepsNotSelected.y + this.sliderHeight / 2;\n        if (this.handleDimensions) {\n            this.handle.width = this.handleDimensions.width;\n            this.handle.height = this.handleDimensions.height;\n        }\n        this.handle.name = 'handler';\n        this.handle.interactive = true;\n        this.handle.buttonMode = true;\n        this.addChild(this.handle);\n\n        if (!Core.isDesktopMode) {\n            this.hitArea = new Rectangle(\n                -this.handle.width / 2,\n                -this.handle.height,\n                this.sliderWidth + this.handle.width,\n                this.handle.height * 2,\n            );\n        }\n        this.attachEventListeners();\n    }\n\n    protected endDrag(e): void {\n        if (e && this.dragging) {\n            this.forceDragSlider(e);\n        }\n        this.data = null;\n        this.dragging = false;\n    }\n\n    protected valueToPixel(value: number): number {\n        if (value < 0) {\n            value = 0;\n        }\n        if (value > 100) {\n            value = 100;\n        }\n        return (this.sliderWidth * value) / 100 - this.handle.width / 2;\n    }\n\n    protected pixelToValue(pixel: number): number {\n        if (pixel < 0) {\n            pixel = 0;\n        } else if (pixel > this.sliderWidth) {\n            pixel = this.sliderWidth;\n        }\n        return (100 * pixel) / this.sliderWidth;\n    }\n\n    protected onHandleHover(): void {\n        if (!this.hoverHandleTexture) {\n            return;\n        }\n        this.state = SteppedSliderStates.Over;\n    }\n\n    protected onHandleReleased(): void {\n        if (this.useSteps) {\n            for (let i = 0; i < this.stepsSectors.length; i++) {\n                if (this.currentStep >= this.stepsSectors[i] && this.currentStep < this.stepsSectors[i + 1]) {\n                    this.state = SteppedSliderStates.Active;\n                    break;\n                }\n            }\n        } else {\n            const roundedValue = Math.round((this.steps[this.steps.length - 1] / 100) * this.currentStep);\n            this.state = roundedValue ? SteppedSliderStates.Active : SteppedSliderStates.Inactive;\n        }\n        // this.state = SteppedSliderStates.Inactive;\n    }\n\n    // private setHandleTexture(texture: Texture): void {\n    //     this.handle.texture = texture;\n    // }\n\n    private forceDragSlider(data: any): void {\n        this.data = data;\n        const move = this.data.data.getLocalPosition(this.handle.parent);\n        const value = this.pixelToValue(move.x);\n        this.currentStep = Math.floor(value);\n        if (this.useSteps) {\n            if (this.currentStep <= this.touchStepsTolerance) {\n                this.resetSlider();\n            } else {\n                for (let i = 0; i < this.stepsSectors.length; i++) {\n                    if (this.currentStep >= this.stepsSectors[i] && this.currentStep < this.stepsSectors[i + 1]) {\n                        this.setSliderValue(this.steps[i + 1]);\n                        this.handle.x = this.valueToPixel(\n                            this.stepsSectors[this.stepsSectors.indexOf(this.stepsSectors[i]) + 1] - this.activeOffset,\n                        );\n                        for (let j = this.stepsActiveArr.length - 1; j >= this.stepsActiveArr.length - 1 - i; j--) {\n                            if (this.stepsActiveArr[j]) {\n                                this.stepsActiveArr[j].visible = true;\n                            }\n                            if (this.stepsInactiveArr[j]) {\n                                this.stepsInactiveArr[j].visible = true;\n                            }\n                        }\n                        for (let j = 0; j <= this.stepsActiveArr.length - 2 - i; j++) {\n                            if (this.stepsActiveArr[j]) {\n                                this.stepsActiveArr[j].visible = false;\n                            }\n                            if (this.stepsInactiveArr[j]) {\n                                this.stepsInactiveArr[j].visible = true;\n                            }\n                        }\n                        this.state = SteppedSliderStates.Active;\n                        // this.setHandleTexture(this.activeHandleTexture);\n                        break;\n                    }\n                }\n                this.stepsSelected.width = this.handle.x + this.handle.width / 2 - this.stepsSelected.x;\n            }\n        } else {\n            this.handle.x = this.valueToPixel(value);\n            const roundedValue = Math.round((this.steps[this.steps.length - 1] / 100) * this.currentStep);\n            this.setSliderValue(roundedValue);\n            if (roundedValue > 0) {\n                this.stepsSelected.width = Math.min(move.x, this.sliderWidth);\n                if (this.stepsActiveArr[this.stepsActiveArr.length - 1]) {\n                    this.stepsActiveArr[this.stepsActiveArr.length - 1].visible = true;\n                }\n                if (this.stepsInactiveArr[this.stepsInactiveArr.length - 1]) {\n                    this.stepsInactiveArr[this.stepsInactiveArr.length - 1].visible = false;\n                }\n            } else {\n                this.stepsSelected.width = 0;\n                for (let j = 0; j <= this.stepsActiveArr.length - 1; j++) {\n                    if (this.stepsActiveArr[j]) {\n                        this.stepsActiveArr[j].visible = false;\n                    }\n                    if (this.stepsInactiveArr[j]) {\n                        this.stepsInactiveArr[j].visible = true;\n                    }\n                }\n            }\n            this.state = roundedValue ? SteppedSliderStates.Active : SteppedSliderStates.Inactive;\n            // this.setHandleTexture(roundedValue ? this.activeHandleTexture : this.inactiveHandleTexture);\n        }\n    }\n\n    set state(state: SteppedSliderStates) {\n        this._state = state;\n        this.cursor = 'normal';\n\n        switch (state) {\n            case SteppedSliderStates.Inactive:\n                this.handle.texture = this.inactiveHandleTexture;\n                break;\n            case SteppedSliderStates.Over:\n                this.cursor = 'pointer';\n                this.handle.texture = this.hoverHandleTexture;\n                break;\n            case SteppedSliderStates.Active:\n                this.handle.texture = this.activeHandleTexture;\n                break;\n            case SteppedSliderStates.Disabled:\n                this.handle.texture = this.disabledHandleTexture;\n                break;\n            case SteppedSliderStates.Pressed:\n                this.handle.texture = this.pressedHandleTexture;\n                break;\n        }\n    }\n}\n\nexport enum SteppedSliderStates {\n    Inactive,\n    Over,\n    Active,\n    Disabled,\n    Pressed,\n}\n","import { Container, Graphics, Sprite } from 'pixi.js';\nimport ViewContainer from './ViewContainer';\nimport { ITitledWindowConfig } from './interfaces/ITitledWindowConfig';\nimport Text from './texts/Text';\nimport TextAlign from './texts/TextAlign';\nimport TextConfig from './texts/TextConfig';\nimport VerticalTextAlign from './texts/VerticalTextAlign';\n// import IBorderedWindowConfig from \"./interfaces/IBorderedWindowConfig\";\n\nexport default class TitledWindow extends ViewContainer {\n    private titleText: Text;\n    private container: Container;\n    private shadow: Sprite;\n    private containerWidth: number;\n\n    constructor(private config: ITitledWindowConfig) {\n        super();\n        config.width = config.width || 440;\n        config.height = config.height || 674;\n        config.backgroundColor = config.backgroundColor || 0x0;\n        config.backgroundAlpha = config.backgroundAlpha || 1;\n\n        config.headerHeight = config.headerHeight || 45;\n        config.headerColor = config.headerColor || 0x141414;\n        config.headerBorderSize = config.headerBorderSize || 2;\n        config.headerBorderColor = config.headerBorderColor || 0x787878;\n\n        config.title = config.title || '';\n        if (!config.titleStyle) {\n            config.titleStyle = {};\n        }\n        config.titleStyle.fontFamily = config.titleStyle.fontFamily || 'FuturaPT';\n        config.titleStyle.fontSize = config.titleStyle.fontSize || 24;\n        config.titleStyle.lineHeight = config.titleStyle.lineHeight || config.headerHeight;\n        config.titleStyle.fontWeight = config.titleStyle.fontWeight || '';\n        config.titleStyle.fill = config.titleStyle.fill || '#CFCFCF';\n        config.titleStyle.padding = config.titleStyle.padding || 0;\n        config.titleStyle.letterSpacing = config.titleStyle.letterSpacing || 1.2;\n\n        config.borderSize = config.borderSize || 2;\n        config.borderColor = config.borderColor || 0xf1f1f1;\n        config.borderRadius = config.borderRadius || 10;\n\n        config.shadowLeftWidth = 0;\n        config.shadowRightWidth = 0;\n        config.shadowTopHeight = 0;\n        config.shadowBottomHeight = 0;\n\n        if (config.useArcs === undefined) {\n            config.useArcs = true;\n        }\n\n        this.container = new Container();\n        this.container.visible = false;\n        this.container.x = 0;\n        this.container.y = 0;\n        // shadow\n        if (config.shadow && config.textureShadow) {\n            // left shadow\n            this.shadow = new Sprite(config.textureShadow);\n            this.redrawShadows();\n            this.container.addChild(this.shadow);\n        }\n\n        const win: Graphics = new Graphics();\n        this.container.addChild(win);\n\n        // its look better with arc nd lines than RoundedRect !\n        if (config.useArcs) {\n            win.lineStyle(config.borderSize, config.borderColor, 1)\n                .arc(\n                    config.borderRadius + 1,\n                    config.borderRadius + 1,\n                    config.borderRadius,\n                    this.radians(180),\n                    this.radians(270),\n                )\n                .moveTo(config.width - config.borderRadius, 1)\n                .arc(\n                    config.width - config.borderRadius - 1,\n                    config.borderRadius + 1,\n                    config.borderRadius,\n                    this.radians(270),\n                    this.radians(360),\n                )\n                .moveTo(config.width - 1, config.height - config.borderRadius - 1)\n                .arc(\n                    config.width - config.borderRadius - 1,\n                    config.height - config.borderRadius - 1,\n                    config.borderRadius,\n                    this.radians(0),\n                    this.radians(90),\n                )\n                .moveTo(config.borderRadius, config.height - 1)\n                .arc(\n                    config.borderRadius + 1,\n                    config.height - config.borderRadius - 1,\n                    config.borderRadius,\n                    this.radians(90),\n                    this.radians(180),\n                )\n                .lineStyle(config.borderSize, config.borderColor, 1)\n                // left border\n                .moveTo(1, config.borderRadius)\n                .lineTo(1, config.height - config.borderRadius)\n                // upper border\n                .moveTo(config.borderRadius, 1)\n                .lineTo(config.width - config.borderRadius, 1)\n                // right border\n                .moveTo(config.width - 1, config.borderRadius)\n                .lineTo(config.width - 1, config.height - config.borderRadius)\n                // down border\n                .moveTo(config.borderRadius, config.height - 1)\n                .lineTo(config.width - config.borderRadius + 1, config.height - 1)\n                .lineStyle(undefined);\n        } else {\n            win.beginFill(config.borderColor, 1)\n                .drawRoundedRect(0, 0, config.width, config.height, config.borderRadius)\n                .endFill();\n        }\n\n        // if there is texture for border corners - use it for smooty corners\n        if (config.borderLeftUpTexture) {\n            const corner_lu = new Sprite(config.borderLeftUpTexture);\n            corner_lu.x = 0;\n            corner_lu.y = 0;\n            this.container.addChild(corner_lu);\n\n            const corner_ru = new Sprite(config.borderLeftUpTexture);\n            corner_ru.scale.x = -1;\n            corner_ru.x = config.width;\n            corner_ru.y = 0;\n            this.container.addChild(corner_ru);\n\n            const corner_ld = new Sprite(config.borderLeftUpTexture);\n            corner_ld.scale.y = -1;\n            corner_ld.x = 0;\n            corner_ld.y = config.height;\n            this.container.addChild(corner_ld);\n\n            const corner_rd = new Sprite(config.borderLeftUpTexture);\n            corner_rd.scale.x = -1;\n            corner_rd.scale.y = -1;\n            corner_rd.x = config.width;\n            corner_rd.y = config.height;\n            this.container.addChild(corner_rd);\n        }\n        win.x = 0;\n        win.y = 0;\n        win.beginFill(config.backgroundColor, config.backgroundAlpha)\n            .drawRoundedRect(\n                config.borderSize,\n                config.borderSize,\n                config.width - 2 * config.borderSize,\n                config.height - 2 * config.borderSize,\n                config.borderRadius,\n            )\n            .endFill()\n            .beginFill(config.headerColor, 1)\n            .drawRoundedRect(\n                config.borderSize,\n                config.borderSize,\n                config.width - 2 * config.borderSize,\n                config.headerHeight - config.borderSize,\n                config.borderRadius,\n            )\n            .endFill()\n            .beginFill(config.headerColor, 1)\n            .drawRect(\n                config.borderSize,\n                config.borderSize + config.borderRadius,\n                config.width - 2 * config.borderSize,\n                config.headerHeight - config.borderSize - config.borderRadius,\n            )\n            .endFill()\n            .beginFill(config.headerBorderColor, 1)\n            .drawRect(\n                config.borderSize,\n                config.headerHeight,\n                config.width - 2 * config.borderSize,\n                config.headerBorderSize,\n            )\n            .endFill();\n\n        // win.cacheAsBitmap = true;\n        // this.container.cacheAsBitmap = true;\n        this.container.interactive = false;\n        this.interactive = false;\n        this.addChild(this.container);\n\n        if (config.title !== '') {\n            this.title = config.title;\n        }\n\n        this.containerWidth = this.width;\n        this.container.visible = true;\n        // this.cacheAsBitmap = true;\n    }\n\n    public set title(value: string) {\n        if (!this.titleText) {\n            this.config.title = value;\n            this.config.titleStyle.lineHeight = this.config.titleStyle.fontSize;\n            const textConfig: TextConfig = new TextConfig();\n            textConfig.bounds.width = this.config.width - 2 * (this.config.borderSize + this.config.borderRadius);\n            textConfig.bounds.height = this.config.headerHeight - (this.config.borderSize + this.config.borderRadius);\n            textConfig.align = TextAlign.CENTER;\n            textConfig.verticalAlign = VerticalTextAlign.CENTER;\n            // textConfig.debug = true;\n            textConfig.shouldFitInBounds = true;\n\n            this.titleText = new Text(textConfig, value, this.config.titleStyle);\n            // this.titleText = new Text(value, this.config.titleStyle);\n            this.addChild(this.titleText);\n            this.titleText.x = this.config.borderRadius + this.config.borderSize;\n            this.titleText.y = Math.floor(this.config.borderRadius / 2) + this.config.borderSize;\n        }\n        this.titleText.text = value;\n    }\n\n    public redrawShadows(): void {\n        if (!this.shadow) {\n            return;\n        }\n        const leftShadow = this.config.shadow === 'left';\n        if (leftShadow) {\n            this.shadow.x = -this.config.borderRadius * 4;\n            this.shadow.width = this.config.width + 8 * this.config.borderRadius;\n            this.shadow.y = -4 * this.config.borderRadius;\n            this.shadow.height = this.config.height + 10 * this.config.borderRadius;\n        } else {\n            this.shadow.x = -4 * this.config.borderRadius;\n            this.shadow.width = this.config.width + 8 * this.config.borderRadius;\n            this.shadow.y = -4 * this.config.borderRadius;\n            this.shadow.height = this.config.height + 10 * this.config.borderRadius;\n        }\n\n        // set sizes of shadows in config\n        this.config.shadowLeftWidth = leftShadow ? Math.abs(this.shadow.x) : 0;\n        this.config.shadowRightWidth = leftShadow ? 0 : Math.abs(this.shadow.x);\n        this.config.shadowTopHeight = Math.abs(this.shadow.y);\n        this.config.shadowBottomHeight = Math.abs(\n            this.shadow.height - this.config.shadowTopHeight - this.config.height,\n        );\n\n        // this.width = this.containerWidth;\n    }\n\n    public destroy(_options?: { children?: boolean; texture?: boolean; baseTexture?: boolean }): void {\n        this.removeChildren();\n\n        this.titleText.destroy();\n        // @ts-ignore\n        this.titleText = null;\n\n        this.container.destroy({ children: true, texture: true, baseTexture: true });\n        // @ts-ignore\n        this.container = null;\n\n        // @ts-ignore\n        this.shadow = null;\n\n        super.destroy({ children: true, texture: true, baseTexture: true });\n    }\n\n    private radians(degrees: number): number {\n        const pi = Math.PI;\n        return degrees * (pi / 180);\n    }\n}\n","import Core from '@egt/core';\nimport { Graphics } from 'pixi.js';\nimport { injectable } from 'tsyringe';\nimport ViewContainer from './ViewContainer';\n\n@injectable()\nexport default class UIBlocker extends ViewContainer {\n    public blockerOverlay: Graphics;\n\n    constructor() {\n        super();\n        this.blockerOverlay = new Graphics();\n        this.blockerOverlay.beginFill(0xffffff);\n        this.blockerOverlay.drawRect(0, 0, Core.ORIENTATION.value.width, Core.ORIENTATION.value.height);\n        this.blockerOverlay.endFill();\n        this.alpha = 0;\n        this.visible = false;\n        this.addChild(this.blockerOverlay);\n    }\n\n    public enable(): void {\n        this.visible = true;\n        this.interactive = true;\n        this.blockerOverlay.width = Core.ORIENTATION.value.width;\n        this.blockerOverlay.height = Core.ORIENTATION.value.height;\n    }\n\n    public resize(): void {\n        this.blockerOverlay.width = Core.ORIENTATION.value.width;\n        this.blockerOverlay.height = Core.ORIENTATION.value.height;\n    }\n\n    public disable(): void {\n        this.interactive = false;\n        this.visible = false;\n    }\n}\n","import { Container, DisplayObject } from 'pixi.js';\nimport { Subject } from 'rxjs';\nimport { Logger, minusEmoji, plusEmoji } from 'unicorn.console-logger';\nimport Core from '@egt/core';\n\n// @injectable()\nexport default class ViewContainer extends Container {\n    public name: string;\n    public readonly DESTROY: Subject<void> = new Subject<void>();\n\n    constructor() {\n        super();\n\n        if (Core.configuration.devTools) {\n            const className = this.constructor.name;\n\n            Logger.logViewMessage([`constructor()`], className);\n\n            this.on('added', () => {\n                const parentsChainNames = this.getParentChainNames(this);\n                const name = this.name ? `('${this.name}')` : '';\n                let message = `Added ${plusEmoji}`;\n                if (this.isOnStage(this)) {\n                    // we add the eye icon to indicate that at this moment in time the view container should be visible on the stage\n                    message = message + ` 👁️`;\n                }\n                Logger.logViewMessage([`${message}`], `${parentsChainNames}${className}${name}`);\n            });\n\n            this.on('removed', (parentContainer) => {\n                const parentsChainNames = this.getParentChainNames(parentContainer);\n                const name = this.name ? `('${this.name}')` : '';\n                Logger.logViewMessage(`Removed ${minusEmoji}`, `${parentsChainNames}${className}${name}`);\n            });\n        }\n    }\n\n    public find(name: string): any {\n        return this._find(name, this);\n    }\n\n    public destroy(_options?: { children?: boolean; texture?: boolean; baseTexture?: boolean }): void {\n        Logger.logViewMessage([`destroy(...) ${minusEmoji}`, _options], this.constructor.name);\n        if (this.DESTROY) {\n            this.DESTROY.next();\n            this.DESTROY.complete();\n            // @ts-ignore\n            this.DESTROY = null;\n        }\n        super.destroy.apply(this, arguments);\n\n        Object.keys(this).forEach((key: string) => {\n            if (this[key]) {\n                this[key] = null;\n            }\n        });\n    }\n\n    private _find(name: string, element: any): any {\n        if (element.name === name) {\n            return element;\n        }\n\n        if (element.children) {\n            for (const child of element.children) {\n                const found = this._find(name, child);\n                if (found) {\n                    return found;\n                }\n            }\n        }\n    }\n\n    protected getParentChainNames(object: DisplayObject): string {\n        const parents: Container[] = this.getParentChain(object).filter((parent) => {\n            return parent instanceof ViewContainer || parent === Core.stage.gameContainer;\n        });\n\n        const parentsNames: string[] = parents.map((parent) => {\n            if (parent === Core.stage.gameContainer) {\n                return 'Stage';\n            }\n            return parent.constructor.name;\n        });\n\n        return parentsNames.length > 0 ? parentsNames.join('.') + '.' : '';\n    }\n\n    protected getParentChain(object: DisplayObject): Container[] {\n        const parents: Container[] = [];\n        let currentParent: Container | null = object.parent;\n        const stageContainer = Core.stage.gameContainer;\n        while (currentParent) {\n            if (currentParent instanceof ViewContainer || currentParent === stageContainer) {\n                parents.unshift(currentParent);\n            }\n            currentParent = currentParent.parent;\n        }\n\n        return parents;\n    }\n\n    protected isOnStage(object: DisplayObject): boolean {\n        const parents = this.getParentChain(object);\n        return parents.includes(Core.stage.gameContainer);\n    }\n}\n","import Core from '@egt/core';\nimport { BehaviorSubject } from 'rxjs';\nimport { filter, takeUntil } from 'rxjs/operators';\nimport ViewContainer from './ViewContainer';\nimport { IViewVisibilityContainer } from './interfaces/IViewVisiilityContainer';\n\nexport default class ViewVisibilityContainer extends ViewContainer implements IViewVisibilityContainer {\n    public readonly VISIBLE: BehaviorSubject<boolean>;\n\n    constructor() {\n        super();\n        this.VISIBLE = new BehaviorSubject<boolean>(false);\n        this.VISIBLE.pipe(takeUntil(this.DESTROY)).subscribe(this.onVisibilityChanged.bind(this));\n        Core.ORIENTATION.pipe(\n            takeUntil(this.DESTROY),\n            filter((_x) => this.VISIBLE.value),\n        ).subscribe(this.redrawView.bind(this));\n    }\n\n    public set show(value: boolean) {\n        // Log.debug(\"** View Visibility change\", this.constructor.name, value);\n        this.VISIBLE.next(value);\n        this.visible = value;\n    }\n    public destroy(_options?: { children?: boolean; texture?: boolean; baseTexture?: boolean }): void {\n        if (this.VISIBLE) {\n            this.VISIBLE.complete();\n            // @ts-ignore\n            this.VISIBLE = null;\n        }\n\n        super.destroy.apply(this, arguments);\n    }\n\n    /* @ts-ignore */\n    public redrawView(): void {\n        // overwtitten in every view. called when view stay visible.\n        // probably orientation chaned will be executed\n    }\n\n    protected onVisibilityChanged(): void {\n        if (this.VISIBLE.value) {\n            this.redrawView();\n        }\n    }\n}\n","import Core, { Money } from '@egt/core';\nimport { Sprite, TextStyle, Texture } from 'pixi.js';\nimport { takeUntil } from 'rxjs/operators';\nimport {\n    AutoAlign,\n    IBetButtonConfig,\n    IBetButtonsConfig,\n    IInnerStampConfig,\n    IInnerTextConfig,\n} from '../interfaces/Interfaces';\nimport Text from '../texts/Text';\nimport TextAlign from '../texts/TextAlign';\nimport TextConfig from '../texts/TextConfig';\nimport VerticalTextAlign from '../texts/VerticalTextAlign';\nimport Button from './Button';\nimport ButtonStates from './ButtonStates';\n\nexport default class BetButton extends Button {\n    public betPerLine: number;\n\n    protected textTopOffset: number = 3;\n    protected currencyTextOffset: number;\n    protected amountTextOffset: number;\n    protected textLeftOffset: number;\n    protected credits: number = 0;\n\n    protected amount: Money;\n\n    protected labelText: Text;\n    protected currencyText: Text;\n    protected amountText: Text;\n\n    protected currencyStyle: TextStyle;\n    protected amountStyle: TextStyle;\n    protected labelStyle: TextStyle;\n\n    protected stamp: Sprite;\n\n    protected _denomination: number;\n    protected _selected: boolean;\n    protected _selectedTextures: Texture[];\n    protected _disabled: boolean;\n\n    protected _dynamicConfig: IBetButtonsConfig;\n\n    private _factor: number;\n    private _text: string;\n\n    private _maxBet: number | undefined;\n    private _maxBetBuyBonus: number | undefined;\n    private _buyBonusActivated: boolean | undefined;\n    private fakeMask: Sprite;\n    private _fakeMaskTexture: Texture | undefined;\n\n    constructor(config: IBetButtonConfig) {\n        super(config.textures);\n\n        this.name = config.name;\n        this.betPerLine = config.betPerLine;\n        this._denomination = config.denomination;\n        this._factor = config.factor;\n        this._width = config.width;\n        this._height = config.height;\n        this._text = config.text;\n        this._selectedTextures = config.selectedTextures || [];\n        this._fakeMaskTexture = config.fakeMaskTexture;\n        this._selected = config.selected || false;\n        this._maxBet = config.maxBet;\n        this._maxBetBuyBonus = config.maxBetBuyBonus;\n\n        this._dynamicConfig = config.dynamicConfig || {\n            currency: {\n                visible: true,\n                defaultStyle: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 17,\n                    fontWeight: 'bold',\n                    fill: '#C6C5C5',\n                }),\n                selectedStyle: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 17,\n                    fontWeight: 'bold',\n                    fill: '#FFD200',\n                }),\n                x: AutoAlign.CENTER,\n                y: 8,\n                bounds: { width: 99, height: 30 },\n                textAlign: TextAlign.CENTER,\n                debug: false,\n                shouldFitInBounds: true,\n            },\n            amount: {\n                visible: true,\n                defaultStyle: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontWeight: 'bold',\n                    fontSize: 36,\n                    fill: '#C6C5C5', // '#FFFFFF'\n                }),\n                selectedStyle: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontWeight: 'bold',\n                    fontSize: 36,\n                    fill: '#FFFFFF',\n                }),\n                x: AutoAlign.CENTER,\n                y: 28,\n                bounds: { width: 99, height: 34 },\n                textAlign: TextAlign.CENTER,\n                debug: false,\n                shouldFitInBounds: true,\n            },\n            label: {\n                visible: true,\n                defaultStyle: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 21,\n                    fontWeight: 'bold',\n                    fill: '#FFD200',\n                    padding: 5,\n                }),\n                selectedStyle: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 21,\n                    fontWeight: 'bold',\n                    fill: '#FFD200',\n                    padding: 5,\n                }),\n                x: AutoAlign.CENTER,\n                y: 66,\n                bounds: { width: 99, height: 30 },\n                textAlign: TextAlign.CENTER,\n                debug: false,\n                shouldFitInBounds: true,\n            },\n            stamp: {\n                hasStamp: false,\n                x: 0,\n                y: 0,\n                width: 0,\n                height: 0,\n                alpha: 0,\n                texture: { source: '', name: '' },\n            },\n            textures: ['svgBet', 'svgBetPressed', 'svgBet', 'svgBet'],\n            selectedTextures: ['svgActiveBet', 'svgActiveBetPressed', 'svgActiveBet', 'svgActiveBet'],\n            fakeMaskTexture: 'maxBet',\n            width: 113,\n            height: 90,\n        };\n        this.creatButton();\n    }\n\n    public setSelectedTextures(newTextures: Texture[]): void {\n        if (newTextures && newTextures.length === 1) {\n            newTextures.push(newTextures[0].clone());\n            newTextures.push(newTextures[0].clone());\n            newTextures.push(newTextures[0].clone());\n        }\n\n        this._selectedTextures = newTextures;\n\n        if (this._selected && this._selectedTextures) {\n            this.button.texture = this._selectedTextures[ButtonStates.Normal];\n        }\n    }\n\n    set buyBonusActivated(value: boolean | undefined) {\n        this._buyBonusActivated = value;\n        this.maxBetCheck();\n    }\n\n    get buyBonusActivated(): boolean | undefined {\n        return this._buyBonusActivated;\n    }\n\n    public set fontSize(value) {\n        // if (this.amountStyle.fontSize !== value) {\n        this.amountStyle.fontSize = value;\n        // this.amountStyle.lineHeight = Number(value);\n        // @ts-ignore\n        if (this._dynamicConfig) {\n            this._dynamicConfig.amount.selectedStyle.fontSize = value;\n            this._dynamicConfig.amount.defaultStyle.fontSize = value;\n        }\n        this.amountText.style = this.amountStyle;\n        this.updateConfig();\n        // }\n    }\n\n    public get fontSize(): string | number {\n        return this.amountText.style.fontSize;\n    }\n\n    public set labelSize(value) {\n        if (this.labelStyle.fontSize !== value) {\n            this.labelStyle.fontSize = value;\n            this.labelStyle.lineHeight = Number(value);\n            this.labelText.style = this.labelStyle;\n        }\n    }\n\n    public get labelSize(): string | number {\n        return this.labelStyle.fontSize;\n    }\n\n    public set currencySize(value) {\n        if (this.currencyStyle.fontSize !== value) {\n            this.currencyStyle.fontSize = value;\n            this.currencyStyle.lineHeight = Number(value);\n            this.currencyText.style = this.currencyStyle;\n        }\n    }\n\n    public get currencySize(): string | number {\n        return this.currencyStyle.fontSize;\n    }\n\n    get text(): string {\n        return this._text;\n    }\n\n    set text(value: string) {\n        this._text = value;\n        this.labelText.text = value;\n    }\n\n    set selected(value: boolean) {\n        if (this._selected === value) {\n            return;\n        }\n\n        this._selected = value;\n        let texture: Texture;\n\n        if (this._selected && this._selectedTextures) {\n            texture = this._selectedTextures[ButtonStates.Normal];\n        } else {\n            texture = this.textures[ButtonStates.Normal];\n        }\n\n        this.button.texture = texture;\n\n        // this.setStyles();\n        this.updateConfig();\n        this.maxBetCheck();\n    }\n\n    get selected(): boolean {\n        return this._selected;\n    }\n\n    get enabled(): boolean {\n        return this._enabled;\n    }\n\n    set lines(_lines: number) {\n        if (this._factor) {\n            this.credits = this.betPerLine * this._factor;\n        } else {\n            this.credits = this.betPerLine * this.lines;\n        }\n        this.setCorrectTextValues();\n    }\n\n    set factor(factor: number) {\n        this._factor = factor;\n        this.credits = this.betPerLine * this._factor;\n        this.setCorrectTextValues();\n    }\n\n    get factor(): number {\n        return this._factor;\n    }\n\n    public destroy(): void {\n        if (this.stamp) {\n            this.stamp.destroy();\n            // @ts-ignore\n            this.stamp = null;\n        }\n\n        if (this.amount) {\n            // @ts-ignore\n            this.amount = null;\n        }\n\n        if (this.labelText) {\n            this.labelText.destroy();\n            // @ts-ignore\n            this.labelText = null;\n        }\n\n        if (this.currencyText) {\n            this.currencyText.destroy();\n            // @ts-ignore\n            this.currencyText = null;\n        }\n\n        if (this.amountText) {\n            this.amountText.destroy();\n            // @ts-ignore\n            this.amountText = null;\n        }\n\n        if (this.currencyStyle) {\n            // @ts-ignore\n            this.currencyStyle = null;\n        }\n\n        if (this.amountStyle) {\n            // @ts-ignore\n            this.amountStyle = null;\n        }\n\n        if (this.labelStyle) {\n            // @ts-ignore\n            this.labelStyle = null;\n        }\n        if (this._dynamicConfig) {\n            // @ts-ignore\n            this._dynamicConfig = null;\n        }\n        if (this._selectedTextures && this._selectedTextures.length > 0) {\n            this._selectedTextures.forEach((texture) => texture.destroy());\n            // @ts-ignore\n            this._selectedTextures = null;\n        }\n        if (this.fakeMask) {\n            this.fakeMask.destroy();\n            // @ts-ignore\n            this.fakeMask = null;\n        }\n        if (this._fakeMaskTexture) {\n            this._fakeMaskTexture.destroy();\n            // @ts-ignore\n            this._fakeMaskTexture = null;\n        }\n        super.destroy();\n    }\n\n    public updateConfig(): void {\n        this.setStyles();\n        this.amountText.style = this.amountStyle;\n        this.currencyText.style = this.currencyStyle;\n        this.labelText.style = this.labelStyle;\n    }\n\n    public set enabled(value: boolean) {\n        const { isOverMaxBet, isOverMaxBetBuyBonus } = this.getMaxBet();\n        if (isOverMaxBet || isOverMaxBetBuyBonus) {\n            this._enabled = false;\n            this.interactive = false;\n        } else {\n            this._enabled = value;\n            this.interactive = value;\n            if (this.textures) {\n                // POSSIBLE PROBLEMS\n                this.button.texture = this.getTexture(this._state)!;\n            }\n        }\n    }\n\n    protected setOffsets(): void {\n        // this.currencyTextOffset = 11;\n        // this.amountTextOffset = 11;\n        // this.textLeftOffset = 11;\n    }\n\n    protected creatButton(): void {\n        if (this._selected && this._selectedTextures) {\n            this.button.texture = this._selectedTextures[ButtonStates.Normal];\n        }\n        if (this._factor) {\n            this.credits = this.betPerLine * this._factor;\n        } else {\n            this.credits = this.betPerLine * this.lines;\n        }\n\n        this.button.width = this._width;\n        this.button.height = this._height;\n        this.setStyles();\n        // this.initializeTextConfigs();\n        this.createTextElements();\n        if (this._dynamicConfig?.stamp.hasStamp) {\n            this.createButtonStamp(this._dynamicConfig?.stamp);\n        }\n        this.createFakeMask();\n        this.maxBetCheck();\n        Core.MONEY_MODE_IN_CREDITS.pipe(takeUntil(Core.ON_GAME_UNLOADED)).subscribe(this.onMoneyModeChanged.bind(this));\n        Core.SELECTED_DENOMINATION.pipe(takeUntil(Core.ON_GAME_UNLOADED)).subscribe(\n            this.onDenominationChanged.bind(this),\n        );\n    }\n\n    protected setStyles(): void {\n        // @ts-ignore\n        this.currencyStyle = this._selected\n            ? this._dynamicConfig?.currency.selectedStyle\n            : this._dynamicConfig?.currency.defaultStyle;\n        // @ts-ignore\n        this.amountStyle = this._selected\n            ? this._dynamicConfig?.amount.selectedStyle\n            : this._dynamicConfig?.amount.defaultStyle;\n        // @ts-ignore\n        this.labelStyle = this._selected\n            ? this._dynamicConfig?.label.selectedStyle\n            : this._dynamicConfig?.label.defaultStyle;\n\n        this.currencyStyle = JSON.parse(JSON.stringify(this.currencyStyle));\n        this.amountStyle = JSON.parse(JSON.stringify(this.amountStyle));\n        this.labelStyle = JSON.parse(JSON.stringify(this.labelStyle));\n    }\n\n    /**\n     * @override\n     */\n    protected getTexture(state: ButtonStates): Texture | null {\n        let texture: Texture;\n        if (this._selected && this._selectedTextures && !this._disabled) {\n            texture = this._selectedTextures[state];\n        } else {\n            texture = this.textures[state];\n        }\n        return texture || null;\n    }\n\n    /**\n     *\n     */\n    protected updateVerticalPosition(): void {\n        // const creditsText: Text = this.find(this.name + 'Amount');\n        // creditsText.y = (this._height - creditsText.height) / 2 + this.textTopOffset + 4;\n        // creditsText.y = (this._height - creditsText.config.bounds.height) / 2 + this.textTopOffset;\n        // this.setCorrectTextValues();\n    }\n\n    /**\n     *\n     */\n    protected create(): void {\n        // this.currencyText = new Text(this.currencyConfig, '', this.currencyStyle);\n        // this.currencyText.x = this.currencyTextOffset;\n        // this.currencyText.y = this.textTopOffset;\n        // this.currencyText.name = this.name + 'Currency';\n        // this.amount = new Money(this.credits * Core.SELECTED_DENOMINATION.value);\n        // this.amountText = new Text(\n        //     this.amountConfig,\n        //     Core.MONEY_MODE_IN_CREDITS.value ? this.amount.stringCredits : this.amount.stringMoney,\n        //     this.amountStyle,\n        // );\n        // this.amountText.name = this.name + 'Amount';\n        // this.amountText.x = this.amountTextOffset;\n        // this.amountText.y = (this._height - this.amountText.height) / 2 + this.textTopOffset;\n        // this.labelText = new Text(this.labelConfig, this._text, this.labelStyle);\n        // this.labelText.name = this.name + 'Label';\n        // this.labelText.x = this.textLeftOffset;\n        // this.labelText.y = this.textTopOffset + this._height - this._height / 3;\n        // // this.currencyText.visible = !Core.MONEY_MODE_IN_CREDITS.value;\n        // // this.amountMoneyText.visible = Core.MONEY_MODE_IN_CREDITS.value;\n        // this.addChild(this.currencyText);\n        // // this.addChild(this.amountMoneyText);\n        // this.addChild(this.amountText);\n        // this.addChild(this.labelText);\n    }\n\n    protected setCorrectTextValues(): void {\n        this.amount.amountMoney = this.credits * Core.SELECTED_DENOMINATION.value;\n        if (Core.MONEY_MODE_IN_CREDITS.value) {\n            // this.find(this.name + 'Money').moneyValues.amountMoney = this.credits * Core.SELECTED_DENOMINATION.value;\n            this.find(this.name + 'Amount').text = this.credits;\n        } else {\n            // this.find(this.name + 'Money').moneyValues.amountMoney = this.credits * Core.SELECTED_DENOMINATION.value;\n            this.amount.amountMoney = this.credits * Core.SELECTED_DENOMINATION.value;\n            if (this.amount.amountMoney >= 100 && Number.isInteger(this.amount.amountMoney)) {\n                this.find(this.name + 'Amount').text = this.amount.stringMoneyWithoutCents;\n            } else {\n                this.find(this.name + 'Amount').text = this.amount.stringMoney;\n            }\n        }\n        // this.updateHorizontalPosition(this.amountText, this._dynamicConfig.amount);\n        this.updateVerticalPosition();\n\n        this.maxBetCheck();\n    }\n\n    protected maxBetCheck() {\n        const { isOverMaxBet, isOverMaxBetBuyBonus } = this.getMaxBet();\n\n        if (isOverMaxBet || isOverMaxBetBuyBonus) {\n            if (isOverMaxBet) {\n                this.enableButton(false);\n            } else {\n                this.enableButton(true);\n            }\n            if (isOverMaxBetBuyBonus) {\n                this.tintButton();\n                this.buttonMode = false;\n                // this._disabled = true;\n                this.enabled = false;\n                // this.interactive = false;\n                // this.cursor = 'normal';\n                // this.interactive = false;\n                this.selected = false;\n            }\n        } else {\n            this.untintButton();\n            // this.enableButton(true);\n            this.buttonMode = true;\n            // this._disabled = false;\n            this.enabled = true;\n            this.enableButton(true);\n        }\n    }\n\n    private getMaxBet() {\n        const isOverMaxBet = this._maxBet && this.amount.amountMoney > this._maxBet;\n        const isOverMaxBetBuyBonus =\n            this.buyBonusActivated && this._maxBetBuyBonus && this.amount.amountMoney > this._maxBetBuyBonus;\n        return { isOverMaxBet, isOverMaxBetBuyBonus };\n    }\n\n    private tintButton(): void {\n        this.button.tint = 0x797979;\n        this.labelText.tintText(0x797979);\n        this.currencyText.tintText(0x797979);\n        this.amountText.tintText(0x797979);\n    }\n\n    private untintButton(): void {\n        this.button.tint = 0xffffff;\n        this.labelText.tintText(0xffffff);\n        this.currencyText.tintText(0xffffff);\n        this.amountText.tintText(0xffffff);\n    }\n\n    private enableButton(enable: boolean) {\n        this.buttonMode = enable;\n        this._disabled = !enable;\n        this.currencyText.visible = enable;\n        this.amountText.visible = enable;\n        this.labelText.visible = enable;\n        this.fakeMask.visible = !enable;\n        this.enabled = enable;\n    }\n\n    protected onDenominationChanged(): void {\n        this.setCorrectTextValues();\n    }\n\n    protected onMoneyModeChanged(): void {\n        if (Core.MONEY_MODE_IN_CREDITS.value) {\n            this.currencyText.text = Core.translator.translate('CREDITS');\n        } else {\n            this.currencyText.text = Core.PLAYER_BALANCE.value.currency;\n        }\n        this.setCorrectTextValues();\n    }\n\n    protected updateHorizontalPosition(el: Text, conf: IInnerTextConfig): void {\n        if (conf.x === AutoAlign.CENTER) {\n            el.x = Math.round(this.button.width - conf.bounds.width) / 2;\n        } else {\n            el.x = conf.x;\n        }\n    }\n\n    private createTextElements(): void {\n        this.amount = new Money(this.credits * Core.SELECTED_DENOMINATION.value);\n        this.currencyText = this.createTextElement(this._dynamicConfig.currency, '', this.currencyStyle, 'Currency');\n        this.amountText = this.createTextElement(\n            this._dynamicConfig.amount,\n            this.getFormattedAmount(),\n            this.amountStyle,\n            'Amount',\n        );\n\n        this.labelText = this.createTextElement(this._dynamicConfig.label, this._text, this.labelStyle, 'Label');\n        this.addChild(this.currencyText, this.amountText, this.labelText);\n    }\n\n    private createFakeMask(): void {\n        this.fakeMask = new Sprite(this._fakeMaskTexture);\n        this.fakeMask.visible = false;\n        this.fakeMask.width = this._width;\n        this.fakeMask.height = this._height;\n        this.addChild(this.fakeMask);\n    }\n\n    private createButtonStamp(stampConfig: IInnerStampConfig): void {\n        this.stamp = new Sprite(\n            Core.assets.getTextureFromSpriteSheet(stampConfig.texture.source, stampConfig.texture.name),\n        );\n        this.stamp.y = stampConfig.y;\n        this.stamp.x = stampConfig.x;\n        this.stamp.width = stampConfig.width;\n        this.stamp.height = stampConfig.height;\n        this.stamp.alpha = stampConfig.alpha;\n\n        this.addChild(this.stamp);\n    }\n\n    private getFormattedAmount(): string {\n        return Core.MONEY_MODE_IN_CREDITS.value ? this.amount.stringCredits : this.amount.stringMoney;\n    }\n\n    private createTextElement(config: IInnerTextConfig, text: string, style: TextStyle, suffix: string): Text {\n        const element = new Text(this.createTextConfig(config), text, style);\n        element.name = `${this.name}${suffix}`;\n\n        this.updateHorizontalPosition(element, config);\n\n        element.y = config.y;\n        element.visible = config.visible;\n\n        return element;\n    }\n\n    private createTextConfig(config: IInnerTextConfig): TextConfig {\n        const cnf = new TextConfig();\n        cnf.bounds.width = config.bounds.width;\n        cnf.bounds.height = config.bounds.height;\n        cnf.align = config.textAlign;\n        cnf.verticalAlign = VerticalTextAlign.CENTER;\n        cnf.debug = config.debug;\n        cnf.shouldFitInBounds = config.shouldFitInBounds;\n        return cnf;\n    }\n}\n","import { Circle, InteractionEvent, Rectangle, Sprite, Texture } from 'pixi.js';\nimport { Subject, fromEvent } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport ViewContainer from '../ViewContainer';\nimport ButtonShapes from './ButtonShapes';\nimport ButtonStates from './ButtonStates';\n\nexport default class Button extends ViewContainer {\n    public readonly CLICK = new Subject();\n    // public readonly VALUE_CHANGED = new Subject<{ property: string; value: boolean }>();\n    // public sendUpdate: boolean = true;\n\n    protected _state: ButtonStates;\n    protected _enabled: boolean = true;\n    protected _selected: boolean = false;\n    protected _shape: ButtonShapes = ButtonShapes.Rectangle;\n\n    protected button: Sprite;\n    protected background: Sprite;\n    protected textureNormal: Texture;\n    protected texturePressed: Texture;\n    protected textureOver: Texture;\n    protected textureDisabled: Texture;\n    protected textureBackgroundNormal: Texture;\n    protected textureBackgroundPressed: Texture;\n    protected textureBackgroundOver: Texture;\n    protected textureBackgroundDisabled: Texture;\n    protected textures: Texture[];\n    protected backgroundTextures: Texture[];\n    protected useAnchorOnCenter: boolean;\n    protected hitPadding: number = 0;\n\n    /**\n     *\n     * @param textures\n     * @param backgroundTextures\n     */\n    constructor(\n        textures?: Texture[],\n        backgroundTextures?: Texture[],\n        shape?: ButtonShapes,\n        useAnchorOnCenter: boolean = false,\n        hitPadding?: number,\n    ) {\n        super();\n\n        this.useAnchorOnCenter = useAnchorOnCenter;\n        this.button = new Sprite();\n        this.buttonMode = true;\n        this._state = ButtonStates.Normal;\n\n        if (hitPadding) {\n            this.hitPadding = hitPadding;\n        }\n\n        if (textures && textures.length === 1) {\n            textures.push(textures[0].clone());\n            textures.push(textures[0].clone());\n            textures.push(textures[0].clone());\n        }\n\n        if (textures) {\n            this.setTextures(textures);\n        }\n\n        if (useAnchorOnCenter) {\n            this.button.anchor.set(0.5);\n            this.button.x = this.button.width / 2;\n            this.button.y = this.button.height / 2;\n        }\n\n        if (backgroundTextures && backgroundTextures.length === 1) {\n            backgroundTextures.push(backgroundTextures[0].clone());\n            backgroundTextures.push(backgroundTextures[0].clone());\n            backgroundTextures.push(backgroundTextures[0].clone());\n        }\n\n        if (backgroundTextures) {\n            this.backgroundTextures = backgroundTextures;\n            this.background = new Sprite();\n            this.background.texture = this.backgroundTextures[this._state];\n            this.addChild(this.background);\n            if (useAnchorOnCenter) {\n                this.background.anchor.set(0.5);\n                this.background.x = this.background.width / 2;\n                this.background.y = this.background.height / 2;\n            }\n        }\n\n        // this.interactive = true;\n        // this.buttonMode = true;\n        this.button.interactive = true;\n        // this.interactiveChildren = true;\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/slot-features/ui-lib/src/egt/ui/buttons/Button.ts:95:9\",(this.button),\"pointerdown\"]), fromEvent(this.button, 'pointerdown')).pipe(takeUntil(this.DESTROY)).subscribe(this.onPointerDown.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/slot-features/ui-lib/src/egt/ui/buttons/Button.ts:97:9\",(this.button),\"pointerup\"]), fromEvent(this.button, 'pointerup')).pipe(takeUntil(this.DESTROY)).subscribe(this.onPointerUp.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/slot-features/ui-lib/src/egt/ui/buttons/Button.ts:99:9\",(this.button),\"pointerupoutside\"]), fromEvent(this.button, 'pointerupoutside'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerOut.bind(this));\n\n        fromEvent(this.button, 'pointerover').pipe(takeUntil(this.DESTROY)).subscribe(this.onPointerOver.bind(this));\n\n        fromEvent(this.button, 'pointerout').pipe(takeUntil(this.DESTROY)).subscribe(this.onPointerOut.bind(this));\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/slot-features/ui-lib/src/egt/ui/buttons/Button.ts:107:9\",(this.button),\"pointertap\"]), fromEvent(this.button, 'pointertap')).pipe(takeUntil(this.DESTROY)).subscribe(this.onPointerTap.bind(this));\n\n        if (shape) {\n            this._shape = shape;\n        }\n        this.generateHitArea(this._shape);\n\n        this.addChild(this.button);\n    }\n\n    public destroy(): void {\n        this.removeChildren();\n\n        if (this.button.hitArea) {\n            // @ts-ignore\n            this.button.hitArea = null;\n        }\n\n        this.button.destroy({ children: true });\n        if (this.textures) {\n            this.textures.forEach((texture) => {\n                texture.destroy();\n            });\n            this.textures = [];\n            // @ts-ignore\n            this.textures = null;\n        }\n\n        if (this.backgroundTextures) {\n            this.backgroundTextures.forEach((texture) => {\n                texture.destroy();\n            });\n            this.backgroundTextures = [];\n            // @ts-ignore\n            this.backgroundTextures = null;\n        }\n\n        // @ts-ignore\n        this.textureNormal = null;\n        // @ts-ignore\n        this.texturePressed = null;\n        // @ts-ignore\n        this.textureOver = null;\n        // @ts-ignore\n        this.textureDisabled = null;\n\n        // @ts-ignore\n        this.textureBackgroundNormal = null;\n        // @ts-ignore\n        this.textureBackgroundPressed = null;\n        // @ts-ignore\n        this.textureBackgroundOver = null;\n        // @ts-ignore\n        this.textureBackgroundDisabled = null;\n\n        super.destroy();\n    }\n    public get selected(): boolean {\n        return this._selected;\n    }\n\n    public set selected(value: boolean) {\n        this._selected = value;\n    }\n\n    public get enabled(): boolean {\n        return this._enabled;\n    }\n\n    public set enabled(value: boolean) {\n        this._enabled = value;\n        this.interactive = value;\n        if (this.textures) {\n            const texture = this.getTexture(this._state);\n            this.button.texture = this._enabled && texture ? texture : this.textureDisabled;\n        }\n        /*   if (this.sendUpdate) {\n            this.VALUE_CHANGED.next({ property: 'enabled', value: this._enabled });\n        } */\n\n        // this._state = (this._enabled) ? ButtonStates.Normal : ButtonStates.Disabled;\n    }\n\n    public set state(state: ButtonStates) {\n        this._state = state;\n        const texture: Texture | null = this.getTexture(state);\n        const backgroundTexture: Texture | null = this.getBackgroundTexture(state);\n        if (texture) {\n            this.button.texture = texture;\n        }\n        if (backgroundTexture) {\n            this.background.texture = backgroundTexture;\n        }\n    }\n\n    public get state(): ButtonStates {\n        return this._state;\n    }\n\n    public setHitArea(shape: Rectangle): void {\n        this.button.hitArea = shape;\n    }\n\n    /**\n     * should send only one or 4 textures\n     * @param texture\n     */\n    public setTextures(newTextures: Texture[]): void {\n        if (newTextures && newTextures.length === 1) {\n            newTextures.push(newTextures[0].clone());\n            newTextures.push(newTextures[0].clone());\n            newTextures.push(newTextures[0].clone());\n        }\n\n        this.textures = newTextures;\n\n        this.textureNormal = newTextures[ButtonStates.Normal];\n        this.texturePressed = newTextures[ButtonStates.Pressed];\n        this.textureOver = newTextures[ButtonStates.Over];\n        this.textureDisabled = newTextures[ButtonStates.Disabled];\n        if (this.enabled) {\n            this.button.texture = this.textures[this._state];\n        } else {\n            this.button.texture = this.textures[ButtonStates.Disabled];\n        }\n    }\n\n    /**\n     * should send only one or 4 textures\n     * @param texture\n     */\n    public setBackgroundTextures(newBackgroundTextures: Texture[]): void {\n        if (!this.background) {\n            return;\n        }\n        if (newBackgroundTextures && newBackgroundTextures.length === 1) {\n            newBackgroundTextures.push(newBackgroundTextures[0].clone());\n            newBackgroundTextures.push(newBackgroundTextures[0].clone());\n            newBackgroundTextures.push(newBackgroundTextures[0].clone());\n        }\n\n        this.backgroundTextures = newBackgroundTextures;\n\n        this.textureBackgroundNormal = newBackgroundTextures[ButtonStates.Normal];\n        this.textureBackgroundPressed = newBackgroundTextures[ButtonStates.Pressed];\n        this.textureBackgroundOver = newBackgroundTextures[ButtonStates.Over];\n        this.textureBackgroundDisabled = newBackgroundTextures[ButtonStates.Disabled];\n        if (this.enabled) {\n            this.background.texture = this.backgroundTextures[this._state];\n        } else {\n            this.background.texture = this.backgroundTextures[ButtonStates.Disabled];\n        }\n    }\n\n    public fakeClick(): void {\n        this.button.emit('pointertap');\n    }\n\n    /**\n     *\n     * @param event\n     */\n    public onPointerDown(): void {\n        if (!this._enabled) {\n            return;\n        }\n        this.state = ButtonStates.Pressed;\n    }\n\n    /**\n     *\n     */\n    public onPointerOut(): void {\n        if (!this._enabled || this._state === ButtonStates.Disabled) {\n            return;\n        }\n        this.state = ButtonStates.Normal;\n    }\n\n    public setEnabled(value: boolean): void {\n        this.enabled = value;\n    }\n\n    /**\n     *\n     * @param event\n     */\n\n    public get btnSprite(): Sprite {\n        return this.button;\n    }\n\n    protected onPointerUp(_event: InteractionEvent): void {\n        if (!this._enabled || this._state === ButtonStates.Disabled) {\n            return;\n        }\n        this.state = ButtonStates.Over;\n    }\n\n    /**\n     *\n     */\n    protected onPointerOver(): void {\n        if (!this._enabled || this._state === ButtonStates.Disabled) {\n            return;\n        }\n        this.state = ButtonStates.Over;\n    }\n\n    /**\n     *\n     */\n    protected onPointerTap(): void {\n        if (!this._enabled) {\n            return;\n        }\n        this.CLICK.next();\n    }\n\n    /**\n     *\n     * @param state\n     * @param texture\n     */\n    protected setTexture(state: ButtonStates, texture: Texture): void {\n        this.textures[state] = texture;\n    }\n\n    /**\n     *\n     * @param state\n     */\n    protected getTexture(state: ButtonStates): Texture | null {\n        return this.textures ? this.textures[state] : null;\n    }\n\n    /**\n     *\n     * @param state\n     */\n    protected getBackgroundTexture(state: ButtonStates): Texture | null {\n        return this.backgroundTextures ? this.backgroundTextures[state] : null;\n    }\n\n    private generateHitArea(shape: ButtonShapes): void {\n        const offsetX = this.useAnchorOnCenter ? this.button.width / 2 : 0;\n        const offsetY = this.useAnchorOnCenter ? this.button.height / 2 : 0;\n        switch (shape) {\n            case ButtonShapes.Rectangle:\n                this.button.hitArea = new Rectangle(\n                    this.button.x - offsetX,\n                    this.button.y - offsetY,\n                    this.button.width + this.hitPadding,\n                    this.button.height + this.hitPadding,\n                );\n\n                if (this.background) {\n                    this.background.hitArea = new Rectangle(\n                        this.button.x - offsetX,\n                        this.button.y - offsetY,\n                        this.button.width + this.hitPadding,\n                        this.button.height + this.hitPadding,\n                    );\n                }\n\n                // Uncomment this if you want to see the hit area on the stage\n\n                // const rectGraphic = new PIXI.Graphics();\n                // rectGraphic.beginFill(0xffffff, 0.4);\n                // rectGraphic.drawRect(this.button.x, this.button.y, this.button.width, this.button.height);\n                // rectGraphic.endFill();\n                // this.button.addChild(rectGraphic);\n\n                break;\n            case ButtonShapes.Circle:\n                this.button.hitArea = new Circle(\n                    this.button.width / 2 - offsetX,\n                    this.button.height / 2 - offsetY,\n                    this.button.width / 2 + this.hitPadding,\n                );\n\n                if (this.background) {\n                    this.background.hitArea = new Circle(\n                        this.button.width / 2 - offsetX,\n                        this.button.height / 2 - offsetY,\n                        this.button.width / 2 + this.hitPadding,\n                    );\n                }\n\n                // Uncomment this if you want to see the hit area on the stage\n\n                // const circGraphic = new PIXI.Graphics();\n                // circGraphic.beginFill(0xffffff, 0.4);\n                // circGraphic.drawCircle(this.button.width / 2, this.button.height / 2, this.button.width / 2);\n                // circGraphic.endFill();\n                // this.button.addChild(circGraphic);\n\n                break;\n        }\n    }\n}\n","enum ButtonShapes {\n    Rectangle,\n    Circle,\n}\nexport default ButtonShapes;\n","enum ButtonStates {\n    Normal,\n    Pressed,\n    Over,\n    Disabled,\n}\nexport default ButtonStates;\n","import Core from '@egt/core';\nimport { IDenomButtonStyle } from '@egt/slot';\nimport { Container, ITextStyle, Point, TextStyle, Texture } from 'pixi.js';\nimport { takeUntil } from 'rxjs/operators';\nimport Text from '../texts/Text';\nimport TextAlign from '../texts/TextAlign';\nimport TextConfig from '../texts/TextConfig';\nimport Button from './Button';\nimport ButtonStates from './ButtonStates';\n\nexport default class DenominationButton extends Button {\n    set selected(value: boolean) {\n        if (this._selected === value) {\n            return;\n        }\n\n        this._selected = value;\n        let texture: Texture;\n\n        if (this._selected && this._selectedTextures) {\n            texture = this._selectedTextures[ButtonStates.Normal];\n        } else {\n            texture = this.textures[ButtonStates.Normal];\n        }\n\n        this.setFonts();\n\n        this.denominationText.style.fill = this.denominationTextStyle.fill;\n        this.bottomText.style.fill = this.bottomTextStyle.fill;\n        this.levelTextText.style.fill = this.levelTextTextStyle.fill;\n        this.levelValueText.style.fill = this.levelValueTextStyle.fill;\n        this.topText.style.fill = this.topTextStyle.fill;\n\n        this.button.texture = texture;\n    }\n\n    get selected(): boolean {\n        return this._selected;\n    }\n\n    protected creditsContainer: Container;\n    protected currencyContainer: Container;\n\n    // credits\n    protected topText: Text;\n    protected denominationText: Text;\n    protected bottomText: Text;\n    // money\n    protected levelTextText: Text;\n    protected levelValueText: Text;\n\n    // credits\n    protected denominationTextStyle: TextStyle;\n    protected topTextStyle: TextStyle;\n    protected bottomTextStyle: TextStyle;\n\n    // money\n    protected levelValueTextStyle: TextStyle;\n    protected levelTextTextStyle: TextStyle;\n\n    private widthBuffer: number = 20;\n\n    constructor(\n        public name: string,\n        public denominationString: string,\n        public denominationValue: number,\n        public bottomTextValue: string,\n        protected _width: number,\n        protected _height: number,\n        protected currencyLevel: number,\n        textures?: Texture[],\n        protected _selectedTextures?: Texture[],\n        protected _selected: boolean = false,\n        protected _denomButtonStyles?: IDenomButtonStyle,\n    ) {\n        super(textures);\n        this.creditsContainer = new Container();\n        this.currencyContainer = new Container();\n\n        if (this._selected && this._selectedTextures) {\n            this.button.texture = this._selectedTextures[ButtonStates.Normal];\n        }\n        this.create();\n        Core.MONEY_MODE_IN_CREDITS.pipe(takeUntil(Core.ON_GAME_UNLOADED)).subscribe(this.onMoneyModeChanged.bind(this));\n    }\n\n    public destroy(): void {\n        // console.log('DenominationButton.destroy');\n        if (this.denominationText) {\n            this.denominationText.destroy();\n            // @ts-ignore\n            this.denominationText = null;\n        }\n\n        if (this.bottomText) {\n            this.bottomText.destroy();\n            // @ts-ignore\n            this.bottomText = null;\n        }\n\n        if (this.topText) {\n            this.topText.destroy();\n            // @ts-ignore\n            this.topText = null;\n        }\n\n        if (this.levelValueText) {\n            this.levelValueText.destroy();\n            // @ts-ignore\n            this.levelValueText = null;\n        }\n\n        if (this.levelTextText) {\n            this.levelTextText.destroy();\n            // @ts-ignore\n            this.levelTextText = null;\n        }\n\n        this.creditsContainer.destroy();\n        this.currencyContainer.destroy();\n\n        // @ts-ignore\n        this.topTextStyle = null;\n        // @ts-ignore\n        this.denominationTextStyle = null;\n        // @ts-ignore\n        this.bottomTextStyle = null;\n        // @ts-ignore\n        this.levelValueTextStyle = null;\n        // @ts-ignore\n        this.levelTextTextStyle = null;\n\n        super.destroy();\n    }\n\n    public enableButton(enable: boolean): void {\n        const tint = enable ? 0xffffff : 0x797979;\n        this.buttonMode = enable;\n        this.enabled = enable;\n        this.button.tint = tint;\n        this.topText.tintText(tint);\n        this.denominationText.tintText(tint);\n        this.bottomText.tintText(tint);\n        this.levelValueText.tintText(tint);\n        this.levelTextText.tintText(tint);\n\n        if (!enable) {\n            this.selected = false;\n        }\n    }\n\n    public setSelectedTextures(newTextures: Texture[]): void {\n        if (newTextures && newTextures.length === 1) {\n            newTextures.push(newTextures[0].clone());\n            newTextures.push(newTextures[0].clone());\n            newTextures.push(newTextures[0].clone());\n        }\n\n        this._selectedTextures = newTextures;\n\n        if (this._selected && this._selectedTextures) {\n            this.button.texture = this._selectedTextures[ButtonStates.Normal];\n        }\n    }\n\n    /**\n     * @override\n     */\n    protected getTexture(state: ButtonStates): Texture | null {\n        let texture: Texture;\n        if (this._selected && this._selectedTextures) {\n            texture = this._selectedTextures[state];\n        } else {\n            texture = this.textures[state];\n        }\n        return texture || null;\n    }\n\n    protected setFonts(): void {\n        const denomButtonType = this._selected\n            ? this._denomButtonStyles?.buttonStandardPressed\n            : this._denomButtonStyles?.buttonStandard;\n        this.topTextStyle = new TextStyle({\n            fontFamily: denomButtonType?.topTextStyle?.fontFamily || 'FuturaPT, Arial, sans-serif',\n            fontSize: denomButtonType?.topTextStyle?.fontSize || 23,\n            fontWeight: denomButtonType?.topTextStyle?.fontWeight || '',\n            fill: denomButtonType?.topTextStyle?.fill || '#FFD200',\n        } as Partial<ITextStyle>);\n\n        this.denominationTextStyle = new TextStyle({\n            fontFamily: denomButtonType?.denominationTextStyle?.fontFamily || 'FuturaPT-ExtraBold, Arial, sans-serif',\n            fontWeight: denomButtonType?.denominationTextStyle?.fontWeight || '',\n            fontSize: denomButtonType?.denominationTextStyle?.fontSize || 39,\n            fill: denomButtonType?.denominationTextStyle?.fill || (this.selected ? '#FFFFFF' : '#C6C5C5'),\n        } as Partial<ITextStyle>);\n\n        this.bottomTextStyle = new TextStyle({\n            fontFamily: denomButtonType?.bottomTextStyle?.fontFamily || 'FuturaPT, Arial, sans-serif',\n            fontSize: denomButtonType?.bottomTextStyle?.fontSize || 18,\n            fontWeight: denomButtonType?.bottomTextStyle?.fontWeight || '',\n            fill: denomButtonType?.bottomTextStyle?.fill || (this.selected ? '#FFFFFF' : '#C6C5C5'),\n        } as Partial<ITextStyle>);\n\n        this.levelValueTextStyle = new TextStyle({\n            fontFamily: denomButtonType?.levelValueTextStyle?.fontFamily || 'FuturaPT-ExtraBold, Arial, sans-serif',\n            fontSize: denomButtonType?.levelValueTextStyle?.fontSize || 39,\n            fontWeight: denomButtonType?.levelValueTextStyle?.fontWeight || '',\n            fill: denomButtonType?.levelValueTextStyle?.fill || (this.selected ? '#FFFFFF' : '#C6C5C5'),\n        } as Partial<ITextStyle>);\n\n        this.levelTextTextStyle = new TextStyle({\n            fontFamily: denomButtonType?.levelTextTextStyle?.fontFamily || 'FuturaPT, Arial, sans-serif',\n            fontSize: denomButtonType?.levelTextTextStyle?.fontSize || 23,\n            fontWeight: denomButtonType?.levelTextTextStyle?.fontWeight || '',\n            fill: denomButtonType?.levelTextTextStyle?.fill || '#FFD200',\n            padding: denomButtonType?.levelTextTextStyle?.padding || 5,\n        } as Partial<ITextStyle>);\n    }\n\n    /**\n     *\n     */\n    protected create(): void {\n        const _selectedColor: string = this.selected ? '#FFFFFF' : '#C6C5C5';\n        this.setFonts();\n\n        this.topText = new Text(this.createConfig(), this.denominationString, this.topTextStyle);\n        this.topText.pivot = new Point(this.topText.textBounds.width / 2, 0);\n        this.topText.x = this.width / 2;\n        this.topText.y = 5;\n        this.topText.name = this.name + 'Top';\n\n        this.denominationText = new Text(\n            this.createConfig(),\n            (this.denominationValue / 100).toFixed(2).toString(),\n            this.denominationTextStyle,\n        );\n        this.denominationText.name = this.name + 'Middle';\n        this.denominationText.pivot = new Point(\n            this.denominationText.textBounds.width / 2,\n            this.denominationText.textBounds.height / 2,\n        );\n        this.denominationText.x = this.width / 2;\n\n        this.denominationText.y = this.height / 2;\n\n        this.bottomText = new Text(this.createConfig(), this.bottomTextValue, this.bottomTextStyle);\n        this.bottomText.name = this.name + 'Bottom';\n        this.bottomText.pivot = new Point(this.bottomText.textBounds.width / 2, 0);\n        this.bottomText.x = this.width / 2;\n        this.bottomText.y = this._height - this.bottomText.height - 2;\n\n        this.addChild(this.creditsContainer);\n        this.creditsContainer.addChild(this.topText);\n        this.creditsContainer.addChild(this.denominationText);\n        this.creditsContainer.addChild(this.bottomText);\n\n        this.levelValueText = new Text(\n            this.createConfig(),\n            (this.currencyLevel + 1).toString(),\n            this.levelValueTextStyle,\n        );\n        this.levelValueText.name = this.name + 'currencyLevel';\n        this.levelValueText.pivot = new Point(this.levelValueText.textBounds.width / 2, 0);\n        this.levelValueText.x = this.width / 2;\n        this.levelValueText.y = 15;\n\n        this.levelTextText = new Text(this.createConfig(), Core.translator.translate('LEVEL'), this.levelTextTextStyle);\n        this.levelTextText.pivot = new Point(this.levelTextText.textBounds.width / 2, 0);\n        this.levelTextText.x = this.width / 2;\n        this.levelTextText.y = 55;\n\n        this.addChild(this.currencyContainer);\n        this.currencyContainer.addChild(this.levelValueText);\n        this.currencyContainer.addChild(this.levelTextText);\n\n        // this.onMoneyModeChanged();\n    }\n\n    /**\n     *\n     */\n    protected createConfig(): TextConfig {\n        const config: TextConfig = new TextConfig();\n        config.bounds.width = this._width - this.widthBuffer;\n        config.bounds.height = this._height / 3;\n        config.align = TextAlign.CENTER;\n        config.shouldFitInBounds = true;\n        return config;\n    }\n\n    protected onMoneyModeChanged(): void {\n        if (Core.MONEY_MODE_IN_CREDITS.value) {\n            this.creditsContainer.visible = true;\n            this.currencyContainer.visible = false;\n        } else {\n            this.creditsContainer.visible = false;\n            this.currencyContainer.visible = true;\n        }\n        // this.selected = this.denomination === Core.SELECTED_DENOMINATION.value;\n    }\n}\n","import Core from '@egt/core';\nimport { IDenomButtonStyle } from '@egt/slot';\nimport { Container, ITextStyle, Point, TextStyle, Texture } from 'pixi.js';\nimport { takeUntil } from 'rxjs/operators';\nimport { injectable } from 'tsyringe';\nimport Text from '../texts/Text';\nimport TextAlign from '../texts/TextAlign';\nimport TextConfig from '../texts/TextConfig';\nimport Button from './Button';\nimport ButtonStates from './ButtonStates';\n\n@injectable()\nexport default class DenominationButtonDesktop extends Button {\n    protected creditsContainer: Container;\n    protected currencyContainer: Container;\n\n    // credits\n    protected topText: Text;\n    protected denominationText: Text;\n    protected bottomText: Text;\n    // money\n    protected levelTextText: Text;\n    protected levelValueText: Text;\n\n    // credits\n    protected denominationTextStyle: TextStyle;\n    protected topTextStyle: TextStyle;\n    protected bottomTextStyle: TextStyle;\n\n    // money\n    protected levelValueTextStyle: TextStyle;\n    protected levelTextTextStyle: TextStyle;\n\n    private contentLeftOffset: number = 20;\n\n    constructor(\n        public name: string,\n        public denomiantionString: string,\n        public denominationValue: number,\n        public bottomTextValue: string,\n        protected _width: number,\n        protected _height: number,\n        protected currencyLevel: number,\n        textures?: Texture[],\n        protected _selectedTextures?: Texture[],\n        protected _selected: boolean = false,\n        protected _denomButtonStyles?: IDenomButtonStyle,\n    ) {\n        super(textures);\n        this.creditsContainer = new Container();\n        this.currencyContainer = new Container();\n\n        if (this._selected && this._selectedTextures) {\n            this.button.texture = this._selectedTextures[ButtonStates.Normal];\n        }\n        this.create();\n        Core.MONEY_MODE_IN_CREDITS.pipe(takeUntil(Core.ON_GAME_UNLOADED)).subscribe(this.onMoneyModeChanged.bind(this));\n    }\n\n    public destroy(): void {\n        if (this.denominationText) {\n            this.denominationText.destroy();\n            // @ts-ignore\n            this.denominationText = null;\n        }\n\n        if (this.bottomText) {\n            this.bottomText.destroy();\n            // @ts-ignore\n            this.bottomText = null;\n        }\n\n        if (this.topText) {\n            this.topText.destroy();\n            // @ts-ignore\n            this.topText = null;\n        }\n\n        if (this.levelValueText) {\n            this.levelValueText.destroy();\n            // @ts-ignore\n            this.levelValueText = null;\n        }\n\n        if (this.levelTextText) {\n            this.levelTextText.destroy();\n            // @ts-ignore\n            this.levelTextText = null;\n        }\n\n        this.creditsContainer.destroy();\n        this.currencyContainer.destroy();\n\n        // @ts-ignore\n        this.topTextStyle = null;\n        // @ts-ignore\n        this.denominationTextStyle = null;\n        // @ts-ignore\n        this.bottomTextStyle = null;\n        // @ts-ignore\n        this.levelValueTextStyle = null;\n        // @ts-ignore\n        this.levelTextTextStyle = null;\n\n        super.destroy();\n    }\n\n    set selected(value: boolean) {\n        if (this._selected === value) {\n            return;\n        }\n\n        this._selected = value;\n        let texture: Texture;\n\n        if (this._selected && this._selectedTextures) {\n            texture = this._selectedTextures[ButtonStates.Normal];\n        } else {\n            texture = this.textures[ButtonStates.Normal];\n        }\n\n        this.setFonts();\n\n        this.denominationText.style.fill = this.denominationTextStyle.fill;\n        this.bottomText.style.fill = this.bottomTextStyle.fill;\n        this.levelTextText.style.fill = this.levelTextTextStyle.fill;\n        this.levelValueText.style.fill = this.levelValueTextStyle.fill;\n        this.topText.style.fill = this.topTextStyle.fill;\n\n        this.button.texture = texture;\n    }\n\n    get selected(): boolean {\n        return this._selected;\n    }\n\n    protected getTexture(state: ButtonStates): Texture | null {\n        let texture: Texture;\n        if (this._selected && this._selectedTextures) {\n            texture = this._selectedTextures[state];\n        } else {\n            texture = this.textures[state];\n        }\n        return texture || null;\n    }\n\n    protected setFonts(): void {\n        const denomButtonType = this._selected\n            ? this._denomButtonStyles?.buttonStandardPressed\n            : this._denomButtonStyles?.buttonStandard;\n        this.topTextStyle = new TextStyle({\n            fontFamily: denomButtonType?.topTextStyle?.fontFamily || 'FuturaPT, Arial, sans-serif',\n            fontSize: denomButtonType?.topTextStyle?.fontSize || 14,\n            fontWeight: denomButtonType?.topTextStyle?.fontWeight || '',\n            fill: denomButtonType?.topTextStyle?.fill || '#FFD200',\n        } as Partial<ITextStyle>);\n\n        this.denominationTextStyle = new TextStyle({\n            fontFamily: denomButtonType?.denominationTextStyle?.fontFamily || 'FuturaPT-ExtraBold, Arial, sans-serif',\n            fontWeight: denomButtonType?.denominationTextStyle?.fontWeight || '',\n            fontSize: denomButtonType?.denominationTextStyle?.fontSize || 28,\n            fill: denomButtonType?.denominationTextStyle?.fill || (this.selected ? '#FFFFFF' : '#C6C5C5'),\n        } as Partial<ITextStyle>);\n\n        this.bottomTextStyle = new TextStyle({\n            fontFamily: denomButtonType?.bottomTextStyle?.fontFamily || 'FuturaPT, Arial, sans-serif',\n            fontSize: denomButtonType?.bottomTextStyle?.fontSize || 16,\n            fontWeight: denomButtonType?.bottomTextStyle?.fontWeight || '',\n            fill: denomButtonType?.bottomTextStyle?.fill || (this.selected ? '#FFFFFF' : '#C6C5C5'),\n        } as Partial<ITextStyle>);\n\n        this.levelValueTextStyle = new TextStyle({\n            fontFamily: denomButtonType?.levelValueTextStyle?.fontFamily || 'FuturaPT-ExtraBold, Arial, sans-serif',\n            fontSize: denomButtonType?.levelValueTextStyle?.fontSize || 31,\n            fontWeight: denomButtonType?.levelValueTextStyle?.fontWeight || '',\n            fill: denomButtonType?.levelValueTextStyle?.fill || (this.selected ? '#FFFFFF' : '#C6C5C5'),\n        } as Partial<ITextStyle>);\n\n        this.levelTextTextStyle = new TextStyle({\n            fontFamily: denomButtonType?.levelTextTextStyle?.fontFamily || 'FuturaPT, Arial, sans-serif',\n            fontSize: denomButtonType?.levelTextTextStyle?.fontSize || 18,\n            fontWeight: denomButtonType?.levelTextTextStyle?.fontWeight || '',\n            fill: denomButtonType?.levelTextTextStyle?.fill || '#FFD200',\n            padding: denomButtonType?.levelTextTextStyle?.padding || 5,\n        } as Partial<ITextStyle>);\n    }\n\n    /**\n     *\n     */\n    protected create(): void {\n        this.width = this._width;\n        this.height = this._height;\n        const textTopOffset = 3;\n\n        this.setFonts();\n\n        this.topText = new Text(this.createConfig(), this.denomiantionString, this.topTextStyle);\n        this.topText.pivot = new Point(this.topText.textBounds.width / 2, 0);\n        this.topText.x = this.width / 2;\n        this.topText.y = textTopOffset;\n        this.topText.name = this.name + 'Top';\n\n        this.denominationText = new Text(\n            this.createConfig(),\n            (this.denominationValue / 100).toFixed(2).toString(),\n            this.denominationTextStyle,\n        );\n        this.denominationText.name = this.name + 'Middle';\n        this.denominationText.pivot = new Point(this.denominationText.textBounds.width / 2, 0);\n        this.denominationText.x = this.width / 2;\n        this.denominationText.y = this.height / 3;\n\n        this.bottomText = new Text(this.createConfig(), this.bottomTextValue, this.bottomTextStyle);\n        this.bottomText.name = this.name + 'Bottom';\n        this.bottomText.pivot = new Point(this.bottomText.textBounds.width / 2, 0);\n        this.bottomText.x = this.width / 2;\n        this.bottomText.y = this.height - this.bottomText.textBounds.height - textTopOffset;\n\n        this.addChild(this.creditsContainer);\n        this.creditsContainer.addChild(this.topText);\n        this.creditsContainer.addChild(this.denominationText);\n        this.creditsContainer.addChild(this.bottomText);\n\n        const bounds = this.getLocalBounds();\n\n        this.levelValueText = new Text(\n            this.createConfig(),\n            (this.currencyLevel + 1).toString(),\n            this.levelValueTextStyle,\n        );\n        this.levelValueText.pivot = new Point(this.levelValueText.textBounds.width / 2, 0);\n        this.levelValueText.name = this.name + 'currencyLevel';\n\n        this.levelValueText.x = bounds.width / 2;\n        this.levelValueText.y = 10;\n\n        this.levelTextText = new Text(this.createConfig(), Core.translator.translate('LEVEL'), this.levelTextTextStyle);\n        this.levelTextText.pivot = new Point(this.levelTextText.textBounds.width / 2, 0);\n        this.levelTextText.x = bounds.width / 2;\n        this.levelTextText.y = this.height - this.levelTextText.textBounds.height - textTopOffset * 2;\n\n        this.addChild(this.currencyContainer);\n        this.currencyContainer.addChild(this.levelValueText);\n        this.currencyContainer.addChild(this.levelTextText);\n\n        // this.onMoneyModeChanged();\n    }\n\n    public setSelectedTextures(newTextures: Texture[]): void {\n        if (newTextures && newTextures.length === 1) {\n            newTextures.push(newTextures[0].clone());\n            newTextures.push(newTextures[0].clone());\n            newTextures.push(newTextures[0].clone());\n        }\n\n        this._selectedTextures = newTextures;\n\n        if (this._selected && this._selectedTextures) {\n            this.button.texture = this._selectedTextures[ButtonStates.Normal];\n        }\n    }\n\n    /**\n     *\n     */\n    protected createConfig(): TextConfig {\n        const config: TextConfig = new TextConfig();\n        config.bounds.width = this._width - this.contentLeftOffset;\n        config.bounds.height = this._height / 3;\n        config.align = TextAlign.CENTER;\n        config.shouldFitInBounds = true;\n        return config;\n    }\n\n    protected onMoneyModeChanged(): void {\n        if (Core.MONEY_MODE_IN_CREDITS.value) {\n            this.creditsContainer.visible = true;\n            this.currencyContainer.visible = false;\n        } else {\n            this.creditsContainer.visible = false;\n            this.currencyContainer.visible = true;\n        }\n        // this.selected = this.denomination === Core.SELECTED_DENOMINATION.value;\n    }\n}\n","import Core from '@egt/core';\nimport { IDenomOptionButtonConfig } from '@egt/slot';\nimport { Text as PixiText, Rectangle, TextStyle } from 'pixi.js';\nimport { takeUntil } from 'rxjs/operators';\nimport Text from '../texts/Text';\nimport TextAlign from '../texts/TextAlign';\nimport TextConfig from '../texts/TextConfig';\nimport Button from './Button';\nimport ButtonStates from './ButtonStates';\n\nexport default class DenominationOptionButton extends Button {\n    protected _state: ButtonStates;\n    protected _enabled: boolean = true;\n    protected currency: string;\n    protected denominations: number[];\n    protected denominationTitleText: PixiText;\n    protected denominationText: Text;\n    protected denominationTitleTextVerticalOffset: number;\n    protected denominationTextVerticalOffset: number;\n    protected denominationTextHorizontalOffset: number;\n    protected denominationTitleTextFontOffset: number;\n    protected denominationButtonWidth: number;\n    protected denominationDefaultFontSize: number;\n    protected denominationTitleTextStyle: TextStyle;\n    protected denominationTextStyle: TextStyle;\n    protected positions: any;\n    protected haveText: boolean = true;\n\n    /**\n     *\n     * @param textures\n     * @param backgroundTextures\n     */\n    constructor(config: IDenomOptionButtonConfig) {\n        super(config.textures, config.backgroundTextures, config.shape);\n        this.currency = config.currency;\n        this.denominations = config.denominations;\n        this.denominationTitleTextVerticalOffset = config.denominationTitleTextVerticalOffset || 0;\n        this.denominationTextVerticalOffset = config.denominationTextVerticalOffset || 0;\n        this.denominationTextHorizontalOffset = config.denominationTextHorizontalOffset || 0;\n        this.denominationTitleTextFontOffset = config.denominationTitleTextFontOffset;\n\n        this.setTextStyles(config.denominationTitleTextStyle, config.denominationTextStyle);\n        if (config.haveText === false) {\n            this.haveText = false;\n        } else {\n            this.addTexts();\n            this.setOrientation();\n            Core.MONEY_MODE_IN_CREDITS.pipe(takeUntil(Core.ON_GAME_UNLOADED)).subscribe(\n                this.onMoneyModeChanged.bind(this),\n            );\n\n            Core.SELECTED_DENOMINATION.pipe(takeUntil(Core.ON_GAME_UNLOADED)).subscribe(\n                this.onDenominationChanged.bind(this),\n            );\n        }\n    }\n\n    public destroy(): void {\n        // @ts-ignore\n        this.denominationTextStyle = null;\n        // @ts-ignore\n\n        this.denominationTitleTextStyle = null;\n        // @ts-ignore\n        this.backgroundTextures = null;\n\n        if (this.denominationTitleText) {\n            this.denominationTitleText.destroy();\n            // @ts-ignore\n            this.denominationTitleText = null;\n        }\n\n        if (this.denominationText) {\n            this.denominationText.destroy();\n            // @ts-ignore\n            this.denominationText = null;\n        }\n\n        // @ts-ignore\n        this.shape = null;\n        if (this.textures) {\n            this.textures.forEach((texture) => {\n                texture.destroy();\n                // @ts-ignore\n                texture = null;\n            });\n            // @ts-ignore\n            this.textures = null;\n        }\n\n        if (this.backgroundTextures) {\n            this.backgroundTextures.forEach((texture) => {\n                texture.destroy();\n                // @ts-ignore\n                texture = null;\n            });\n            // @ts-ignore\n            this.backgroundTextures = null;\n        }\n        this.denominations = [];\n\n        if (this.positions) {\n            this.positions = null;\n        }\n\n        this.removeChildren();\n\n        super.destroy();\n    }\n\n    protected setTextStyles(denominationTitleTextStyle: TextStyle, denominationTextStyle: TextStyle): void {\n        this.denominationTextStyle = denominationTextStyle;\n        this.denominationTitleTextStyle = denominationTitleTextStyle;\n        this.denominationButtonTextSetPositions();\n    }\n\n    protected setOrientation(): void {\n        this.positions = {\n            landscape: {\n                sidePanel: this.createLandscapeConfig(),\n            },\n            portrait: {\n                sidePanel: this.createPortraitConfig(),\n            },\n        };\n    }\n\n    protected addTexts(): void {\n        this.denominationTitleText = new PixiText(this.currency, this.denominationTitleTextStyle);\n        this.denominationTitleText.anchor.set(0, 0.5);\n        this.denominationTitleText.name = 'denominationTitleText';\n        this.denominationTitleText.resolution = 2;\n        this.addChild(this.denominationTitleText);\n\n        const textConfig = new TextConfig();\n        textConfig.bounds = new Rectangle(0, 0, 90, 30);\n        textConfig.align = TextAlign.CENTER;\n        textConfig.shouldFitInBounds = true;\n\n        this.denominationText = new Text(\n            textConfig,\n            (Core.SELECTED_DENOMINATION.value / 100).toFixed(2).toString(),\n            this.denominationTextStyle,\n        );\n\n        this.denominationText.name = 'denominationText';\n        this.addChild(this.denominationText);\n        this.denominationButtonWidth = this.width;\n        this.denominationDefaultFontSize = Number(this.denominationTitleText.style.fontSize);\n    }\n\n    protected createLandscapeConfig(): any {\n        const config: any = {};\n\n        config.denominationTitleTextX = (this.width - this.denominationTitleText.width) / 2;\n        config.denominationTitleTextY = this.height / 2;\n        config.denominationTextX = (this.width - this.denominationText.width) / 2;\n        config.denominationTextY = 90;\n\n        const leftHandModeConfig: any = {};\n\n        leftHandModeConfig.denominationTitleTextX = (this.width - this.denominationTitleText.width) / 2;\n        leftHandModeConfig.denominationTitleTextY = this.height / 2;\n        leftHandModeConfig.denominationTextX = (this.width - this.denominationText.width) / 2;\n        leftHandModeConfig.denominationTextY = 90;\n\n        config.leftHandMode = leftHandModeConfig;\n\n        return config;\n    }\n\n    protected createPortraitConfig(): any {\n        const config: any = {};\n        config.denominationTitleTextX = (this.width - this.denominationTitleText.width) / 2;\n        config.denominationTitleTextY = this.height / 2;\n        config.denominationTextX = (this.width - this.denominationText.width) / 2;\n        config.denominationTextY = 90;\n\n        return config;\n    }\n\n    protected onMoneyModeChanged(): void {\n        this.denominationText.visible = true;\n        this.denominationTitleText.style.wordWrap = this.denominationTitleTextStyle.wordWrap;\n        this.denominationTitleText.style.wordWrapWidth = this.denominationTitleTextStyle.wordWrapWidth;\n\n        const maxWidth = this.denominationButtonWidth - this.denominationTitleTextFontOffset;\n\n        if (Core.MONEY_MODE_IN_CREDITS.value) {\n            this.denominationTitleText.text = this.currency;\n            this.denominationTitleText.style.fontSize = this.denominationDefaultFontSize;\n        } else if (this.denominations.length === 1 || Core.isReplayer) {\n            this.denominationTitleText.text = Core.translator.translate('BET LEVELS');\n            this.denominationText.visible = false;\n            this.denominationTitleText.style.wordWrap = true;\n\n            this.denominationButtonTextSetPositions();\n            const buttonCenterY = this.denominationButtonWidth / 2;\n            const textCenterY = this.denominationTitleText.y + this.denominationTitleText.height / 2;\n            const offset = Math.abs(buttonCenterY - textCenterY);\n\n            const wrapWidth = this.getWidthAtOffset(maxWidth, offset);\n            this.denominationTitleText.style.wordWrapWidth = wrapWidth;\n            this.scaleTitleText(wrapWidth);\n        } else {\n            this.denominationTitleText.text = Core.translator.translate('BET LEVEL');\n            this.scaleTitleText(maxWidth);\n        }\n\n        this.denominationTitleText.x = (maxWidth - this.denominationTitleText.width) / 2;\n\n        this.onDenominationChanged();\n        this.denominationButtonTextSetPositions();\n    }\n\n    /**\n     * Calculates the width at a given vertical offset from a circle's center\n     */\n    private getWidthAtOffset(denominationButtonWidth: number, offset: number): number {\n        const radius = denominationButtonWidth / 2;\n        return offset > radius ? denominationButtonWidth : 2 * Math.sqrt(radius ** 2 - offset ** 2);\n    }\n\n    private scaleTitleText(maxWidth: number) {\n        if (this.denominationTitleText.width > maxWidth) {\n            const scale = maxWidth / this.denominationTitleText.width;\n            this.denominationTitleText.style.fontSize = Math.round(\n                Number(this.denominationTitleText.style.fontSize) * scale,\n            );\n        }\n    }\n\n    protected onDenominationChanged(): void {\n        // Update denomination button text.\n        if (Core.MONEY_MODE_IN_CREDITS.value) {\n            this.denominationText.text = (Core.SELECTED_DENOMINATION.value / 100).toFixed(2).toString();\n        } else {\n            this.denominationText.text = this.getCurrentLevel();\n        }\n    }\n\n    protected denominationButtonTextSetPositions(): void {\n        if (!this.positions) {\n            return;\n        }\n        const config = this.positions[Core.ORIENTATION.value.orientation.toLowerCase()].sidePanel;\n\n        const width = this.width;\n        if (Core.MONEY_MODE_IN_CREDITS.value) {\n            this.denominationText.y = config.denominationTextY - 10 + this.denominationTextVerticalOffset;\n            this.denominationTitleText.y = config.denominationTitleTextY - 8 + this.denominationTitleTextVerticalOffset;\n        } else if (this.denominations.length === 1) {\n            this.denominationTitleText.y = config.denominationTitleTextY + 10;\n        } else {\n            this.denominationText.y = config.denominationTextY + this.denominationTextVerticalOffset;\n            this.denominationTitleText.y = config.denominationTitleTextY + this.denominationTitleTextVerticalOffset;\n        }\n        this.denominationText.x = 22 + this.denominationTextHorizontalOffset;\n        this.denominationTitleText.x = (width / this.scale.x - this.denominationTitleText.width) / 2;\n    }\n\n    private getCurrentLevel(): string {\n        let level: string = '0';\n        for (let i: number = 0; i < this.denominations.length; i++) {\n            if (this.denominations[i] === Core.SELECTED_DENOMINATION.value) {\n                level = (i + 1).toString();\n            }\n        }\n        return level;\n    }\n\n    public set enabled(value: boolean) {\n        this._enabled = value;\n        this.interactive = value;\n        if (this.textures) {\n            const texture = this.getTexture(this._state);\n            this.button.texture = this._enabled && texture ? texture : this.textureDisabled;\n            if (this.haveText) {\n                this.denominationTitleText.alpha = this._enabled ? 1 : 0.4;\n                this.denominationText.alpha = this._enabled ? 1 : 0.4;\n            }\n        }\n        // this._state = (this._enabled) ? ButtonStates.Normal : ButtonStates.Disabled;\n    }\n}\n","import Core from '@egt/core';\nimport { IBetButtonConfig } from '../interfaces/Interfaces';\nimport BetButton from './BetButton';\n\nexport default class FakeBetButton extends BetButton {\n    constructor(config: IBetButtonConfig) {\n        super(config);\n    }\n\n    get denomination(): number {\n        return this._denomination;\n    }\n\n    set denomination(value: number) {\n        this._denomination = value;\n        // this.setCorrectTextValues();\n\n        this.updateVerticalPosition();\n    }\n\n    protected setCorrectTextValues(): void {\n        if (Core.MONEY_MODE_IN_CREDITS.value) {\n            // this.find(this.name + 'Money').moneyValues.amountMoney = this.credits * Core.SELECTED_DENOMINATION.value;\n            this.find(this.name + 'Amount').text = this.credits;\n        } else {\n            // this.find(this.name + 'Money').moneyValues.amountMoney = this.credits * Core.SELECTED_DENOMINATION.value;\n            this.amount.amountMoney = this.credits * this.denomination;\n            if (this.amount.amountMoney >= 100 && Number.isInteger(this.amount.amountMoney)) {\n                this.find(this.name + 'Amount').text = this.amount.stringMoneyWithoutCents;\n            } else {\n                this.find(this.name + 'Amount').text = this.amount.stringMoney;\n            }\n        }\n        this.updateVerticalPosition();\n\n        this.maxBetCheck();\n    }\n}\n","import Core from '@egt/core';\nimport { BetButton, IBetButtonConfig } from '..';\n\nexport default class HighCashBetButton extends BetButton {\n    constructor(config: IBetButtonConfig) {\n        super(config);\n    }\n\n    get denomination(): number {\n        return this._denomination;\n    }\n\n    set denomination(value: number) {\n        this._denomination = value;\n        // this.setCorrectTextValues();\n\n        this.updateVerticalPosition();\n    }\n\n    protected setCorrectTextValues(): void {\n        if (Core.MONEY_MODE_IN_CREDITS.value) {\n            // this.find(this.name + 'Money').moneyValues.amountMoney = this.credits * Core.SELECTED_DENOMINATION.value;\n            this.find(this.name + 'Amount').text = this.credits;\n        } else {\n            // this.find(this.name + 'Money').moneyValues.amountMoney = this.credits * Core.SELECTED_DENOMINATION.value;\n            this.amount.amountMoney = this.credits * this.denomination;\n            if (this.amount.amountMoney >= 1000 && Number.isInteger(this.amount.amountMoney)) {\n                this.find(this.name + 'Amount').text = this.amount.stringMoneyWithoutCents;\n            } else {\n                this.find(this.name + 'Amount').text = this.amount.stringMoney;\n            }\n        }\n        this.updateVerticalPosition();\n    }\n}\n","import { ButtonShapes, ViewContainer } from '@egt/ui-lib';\nimport { Sprite, Text, TextStyle, Texture } from 'pixi.js';\nimport { fromEvent, Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\n\nexport default class KeyboardActionButtonNumeric extends ViewContainer {\n    public readonly CLICK = new Subject();\n    protected buttonBackground: Sprite;\n    protected _shape: ButtonShapes = ButtonShapes.Rectangle;\n    protected btnText: Text;\n    protected btnTextStyleNormal: TextStyle;\n    protected label?: string;\n    protected textures: NumericKeyboardActionButtonTextures;\n\n    constructor(textures: NumericKeyboardActionButtonTextures, btnTextStyleNormal: TextStyle, label?: string) {\n        super();\n        this.interactive = true;\n        this.textures = textures;\n        this.btnTextStyleNormal = btnTextStyleNormal;\n        this.label = label;\n        this.createBtnBackground();\n        this.addBtnText();\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/slot-features/ui-lib/src/egt/ui/buttons/KeyboardActionButtonNumeric.ts:24:9\",(this.buttonBackground),\"pointertap\"]), fromEvent(this.buttonBackground, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerTap.bind(this));\n    }\n\n    public destroy(): void {\n        this.removeChildren();\n\n        this.buttonBackground.destroy({ children: true });\n        this.textures.destroy();\n        // @ts-ignore\n        this.textures = null;\n\n        if (this.btnText) {\n            this.btnText.destroy();\n            // @ts-ignore\n            this.btnText = null;\n        }\n\n        super.destroy();\n    }\n\n    protected createBtnBackground(): void {\n        this.buttonBackground = new Sprite(this.textures.normalTexture);\n\n        this.buttonBackground.interactive = true;\n        this.addChild(this.buttonBackground);\n    }\n\n    protected addBtnText(): void {\n        this.btnText = new Text(this.label ?? '', this.btnTextStyleNormal);\n        this.btnText.resolution = 2;\n        this.btnText.anchor.set(0.5);\n        this.btnText.x = this.width / 2;\n        this.btnText.y = this.height / 2;\n        const padding = 6;\n        const maxWidth = this.buttonBackground.width - padding;\n        if (this.btnText.width > maxWidth) {\n            const scale = maxWidth / this.btnText.width;\n            this.btnText.scale.set(scale);\n        }\n\n        this.addChild(this.btnText);\n    }\n\n    public tintBtn(): void {\n        if (this.buttonBackground) {\n            this.buttonBackground.tint = 0x717171;\n            this.buttonBackground.interactive = false;\n        }\n        if (this.btnText) {\n            this.btnText.tint = 0x717171;\n        }\n        this.interactive = false;\n        this.cursor = 'pointer';\n    }\n\n    public untintBtn(): void {\n        if (this.buttonBackground) {\n            this.buttonBackground.tint = 0xffffff;\n            this.buttonBackground.interactive = true;\n        }\n        if (this.btnText) {\n            this.btnText.tint = 0xffffff;\n        }\n        this.interactive = true;\n        this.cursor = 'pointer';\n    }\n\n    protected onPointerTap(): void {\n        this.CLICK.next(this);\n    }\n}\n\nexport class NumericKeyboardActionButtonTextures {\n    constructor(public normalTexture: Texture) {}\n\n    public destroy() {\n        this.normalTexture.destroy();\n        // @ts-ignore\n        this.normalTexture = null;\n    }\n}\n","import { ButtonShapes, ViewContainer } from '@egt/ui-lib';\nimport { Sprite, Text, TextStyle, Texture } from 'pixi.js';\nimport { fromEvent, Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\n\nexport default class NumericKeyboardButton extends ViewContainer {\n    public readonly CLICK = new Subject();\n    protected buttonBackground: Sprite;\n    protected _shape: ButtonShapes = ButtonShapes.Rectangle;\n    protected btnText: Text;\n    protected btnTextStyleNormal: TextStyle;\n    protected textures: NumericKeyboardButtonTextures;\n    public value: string;\n\n    constructor(textures: NumericKeyboardButtonTextures, btnTextStyleNormal: TextStyle, value: string) {\n        super();\n        this.interactive = true;\n        this.textures = textures;\n        this.btnTextStyleNormal = btnTextStyleNormal;\n        this.createBtnBackground();\n        this.addBtnText(value);\n        this.value = value;\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/slot-features/ui-lib/src/egt/ui/buttons/KeyboardButtonNumeric.ts:23:9\",(this.buttonBackground),\"pointertap\"]), fromEvent(this.buttonBackground, 'pointertap'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onPointerTap.bind(this));\n    }\n\n    public destroy(): void {\n        this.removeChildren();\n\n        this.buttonBackground.destroy({ children: true });\n        this.textures.destroy();\n        // @ts-ignore\n        this.textures = null;\n\n        if (this.btnText) {\n            this.btnText.destroy();\n            // @ts-ignore\n            this.btnText = null;\n        }\n\n        super.destroy();\n    }\n\n    protected createBtnBackground(): void {\n        this.buttonBackground = new Sprite(this.textures.normalTexture);\n\n        this.buttonBackground.interactive = true;\n        this.addChild(this.buttonBackground);\n    }\n\n    protected addBtnText(value: string): void {\n        this.btnText = new Text(value, this.btnTextStyleNormal);\n        this.btnText.resolution = 2;\n        this.btnText.anchor.set(0.5);\n        this.btnText.x = this.width / 2;\n        this.btnText.y = this.height / 2;\n        this.addChild(this.btnText);\n    }\n\n    protected onPointerTap(): void {\n        this.CLICK.next(this);\n    }\n}\n\nexport class NumericKeyboardButtonTextures {\n    constructor(public normalTexture: Texture) {}\n    public destroy() {\n        this.normalTexture.destroy();\n        // @ts-ignore\n        this.normalTexture = null;\n    }\n}\n","import { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport ViewContainer from '../ViewContainer';\nimport Button from './Button';\n\nexport default class ToggleButton extends ViewContainer {\n    public readonly SWITCH = new Subject();\n    public readonly SWITCH_ON = new Subject();\n    public readonly SWITCH_OFF = new Subject();\n\n    protected buttonSelected: Button;\n    protected buttonDeselected: Button;\n\n    protected _selected: boolean = true;\n    protected _enabled: boolean = true;\n\n    constructor(buttonSelected: Button, buttonDeselected: Button) {\n        super();\n\n        this.buttonSelected = buttonSelected;\n        this.buttonDeselected = buttonDeselected;\n\n        this.addChild(this.buttonSelected);\n        this.addChild(this.buttonDeselected);\n\n        this.buttonSelected.CLICK.pipe(takeUntil(this.DESTROY)).subscribe(this.onSelectedClicked.bind(this));\n\n        this.buttonDeselected.CLICK.pipe(takeUntil(this.DESTROY)).subscribe(this.onDeselectedClicked.bind(this));\n\n        this.selected = false;\n\n        this.interactive = true;\n    }\n\n    public destroy(): void {\n        this.buttonSelected.destroy();\n        // @ts-ignore\n        this.buttonSelected = null;\n        this.buttonDeselected.destroy();\n        // @ts-ignore\n        this.buttonDeselected = null;\n        this.SWITCH.complete();\n        this.SWITCH_OFF.complete();\n        this.SWITCH_ON.complete();\n        // @ts-ignore\n        this.SWITCH = null;\n        // @ts-ignore\n        this.SWITCH_OFF = null;\n        // @ts-ignore\n        this.SWITCH_ON = null;\n        super.destroy({ children: true, texture: true });\n    }\n    set enabled(value: boolean) {\n        this._enabled = value;\n        this.interactive = value;\n        this.buttonSelected.interactive = value;\n        this.buttonSelected.enabled = value;\n        this.buttonDeselected.interactive = value;\n        this.buttonDeselected.enabled = value;\n        this.buttonDeselected.cursor = value ? 'pointer' : 'normal';\n    }\n\n    get selected(): boolean {\n        return this._selected;\n    }\n\n    set selected(value: boolean) {\n        this.setSelection(value, false);\n    }\n\n    set interactiveMode(value: boolean) {\n        this.interactive = value;\n        this.buttonSelected.interactive = value;\n        this.buttonDeselected.interactive = value;\n    }\n\n    protected onSelectedClicked(): void {\n        if (!this._enabled) {\n            return;\n        }\n        this.setSelection(false, true);\n    }\n\n    protected onDeselectedClicked(): void {\n        if (!this._enabled) {\n            return;\n        }\n        this.setSelection(true, true);\n    }\n\n    protected setSelection(selected: boolean, triggerEvents: boolean): void {\n        if (this._selected !== selected) {\n            this._selected = selected;\n\n            this.buttonSelected.visible = selected;\n            this.buttonSelected.enabled = selected;\n            this.buttonDeselected.visible = !selected;\n            this.buttonDeselected.enabled = !selected;\n\n            if (triggerEvents) {\n                this.SWITCH.next(selected);\n                if (selected) {\n                    this.SWITCH_ON.next(selected);\n                } else {\n                    this.SWITCH_OFF.next(selected);\n                }\n            }\n        }\n    }\n}\n","import { TextStyle, Texture } from 'pixi.js';\nimport Text from '../texts/Text';\nimport TextAlign from '../texts/TextAlign';\nimport TextConfig from '../texts/TextConfig';\nimport Button from './Button';\nimport ButtonStates from './ButtonStates';\n\nexport default class ValueButton extends Button {\n    protected textTopOffset: number = 7;\n    protected textLeftOffset: number = 7;\n\n    constructor(\n        public name: string,\n        protected _value: string,\n        protected _style: TextStyle,\n        protected _width: number,\n        protected _height: number,\n        textures?: Texture[],\n        protected _selectedTextures?: Texture[],\n        protected _selected: boolean = false,\n    ) {\n        super(textures);\n\n        this.button.width = this._width;\n        this.button.height = this._height;\n\n        if (this._selected && this._selectedTextures) {\n            this.button.texture = this._selectedTextures[ButtonStates.Normal];\n        }\n        this.enabled = true;\n        this.createValues();\n    }\n\n    get buttonValue(): string {\n        return this._value;\n    }\n\n    set buttonValue(value: string) {\n        this._value = value;\n\n        this.setCorrectTextValues();\n    }\n\n    get style(): TextStyle {\n        return this._style;\n    }\n\n    set selected(value: boolean) {\n        if (this._selected === value) {\n            return;\n        }\n\n        this._selected = value;\n        let texture: Texture;\n\n        if (this._selected && this._selectedTextures) {\n            texture = this._selectedTextures[ButtonStates.Normal];\n        } else {\n            texture = this.textures[ButtonStates.Normal];\n        }\n\n        this.button.texture = texture;\n    }\n\n    get selected(): boolean {\n        return this._selected;\n    }\n\n    public hideValue(): void {\n        this.children.forEach((child) => {\n            if (child.name === this.name + 'Value') {\n                this.button.removeChild(child);\n                child.destroy();\n            }\n        });\n    }\n\n    /**\n     * @override\n     */\n    protected getTexture(state: ButtonStates): Texture | null {\n        let texture: Texture;\n        if (this._selected && this._selectedTextures) {\n            texture = this._selectedTextures[state];\n        } else {\n            texture = this.textures[state];\n        }\n        return texture || null;\n    }\n\n    protected createValues(): void {\n        const debug: boolean = false;\n\n        const config: TextConfig = new TextConfig();\n        config.bounds.width = this._width - this.textLeftOffset * 2;\n        config.align = TextAlign.CENTER;\n        config.debug = debug;\n        config.shouldFitInBounds = true;\n\n        const valueText: Text = new Text(config, this._value, this._style);\n        valueText.name = this.name + 'Value';\n        valueText.x = this.textLeftOffset;\n        valueText.y = (this._height - config.bounds.height) / 2;\n\n        this.addChild(valueText);\n    }\n\n    protected setCorrectTextValues(): void {\n        this.find(this.name + 'Money').buttonValue = this._value;\n    }\n}\n","import Core from '@egt/core';\nimport { Point, Sprite, TextStyle, Texture } from 'pixi.js';\nimport ViewContainer from '../ViewContainer';\nimport Text from '../texts/Text';\nimport TextAlign from '../texts/TextAlign';\nimport TextConfig from '../texts/TextConfig';\nimport ButtonStates from './ButtonStates';\nexport default class WaysPayWinlinesButton extends ViewContainer {\n    protected waysPayWinlinesButton: Sprite;\n    protected waysCount: Text;\n    protected waysCountTextStyle: TextStyle;\n    protected waysLable: Text;\n    protected waysLableTextStyle: TextStyle;\n\n    constructor(\n        protected _lines: number,\n        protected _width: number,\n        protected _height: number,\n        protected _textures: Texture[],\n    ) {\n        super();\n        this.create();\n    }\n\n    public destroy(): void {\n        this.removeChildren();\n        this.waysPayWinlinesButton.destroy({ children: true });\n\n        if (this._textures) {\n            this._textures.forEach((texture) => texture.destroy());\n            this._textures = [];\n            // @ts-ignore\n            this._textures = null;\n        }\n        this.waysCount.destroy();\n        this.waysLable.destroy();\n\n        // @ts-ignore\n        this.waysCount = null;\n        // @ts-ignore\n        this.waysLable = null;\n        // @ts-ignore\n        this.waysCountTextStyle = null;\n        // @ts-ignore\n        this.waysLableTextStyle = null;\n\n        super.destroy();\n    }\n\n    protected createTextStyles(): void {\n        this.waysCountTextStyle = new TextStyle({\n            fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n            fontSize: 39,\n            fill: '#FFFFFF',\n        });\n\n        this.waysLableTextStyle = new TextStyle({\n            fontFamily: 'FuturaPT, Arial, sans-serif',\n            fontSize: 23,\n            fill: '#FFFFFF',\n        });\n    }\n\n    protected createTextsConfig(): TextConfig {\n        const config = new TextConfig();\n        config.bounds.width = this._width - 14;\n        config.bounds.height = this._height / 3;\n        config.align = TextAlign.CENTER;\n        config.shouldFitInBounds = true;\n        return config;\n    }\n\n    protected create(): void {\n        this.createTextStyles();\n\n        this.waysPayWinlinesButton = new Sprite();\n        this.waysPayWinlinesButton.texture = this._textures[ButtonStates.Normal];\n        this.addChild(this.waysPayWinlinesButton);\n\n        this.waysCount = new Text(this.createTextsConfig(), this._lines.toString(), this.waysCountTextStyle);\n        this.waysCount.pivot = new Point(this.waysCount.textBounds.width / 2, 0);\n        this.addChild(this.waysCount);\n\n        this.waysLable = new Text(\n            this.createTextsConfig(),\n            Core.translator.translate('FIXED'),\n            this.waysLableTextStyle,\n        );\n        this.waysLable.pivot = new Point(this.waysLable.textBounds.width / 2, 0);\n        this.addChild(this.waysLable);\n\n        this.positionButtonTexts();\n    }\n\n    protected positionButtonTexts(): void {\n        this.waysCount.x = this.waysPayWinlinesButton.width / 2;\n        this.waysLable.x = this.waysPayWinlinesButton.width / 2;\n\n        const totalSpacing =\n            this.waysPayWinlinesButton.height - this.waysCount.textBounds.height - this.waysLable.textBounds.height;\n        const singleSpacing = Math.round(totalSpacing / 3) + 2;\n\n        this.waysCount.y = singleSpacing;\n        this.waysLable.y = this.waysCount.y + this.waysCount.textBounds.height + singleSpacing;\n    }\n}\n","import { TextStyle, Texture } from 'pixi.js';\nimport TextAlign from '../texts/TextAlign';\nimport TextConfig from '../texts/TextConfig';\nimport WaysPayWinlinesButton from './WaysPayWinlinesButton';\nexport default class WaysPayWinlinesButtonDesktop extends WaysPayWinlinesButton {\n    constructor(\n        protected _lines: number,\n        protected _width: number,\n        protected _height: number,\n        protected _textures: Texture[],\n    ) {\n        super(_lines, _width, _height, _textures);\n    }\n\n    public destroy(): void {\n        super.destroy();\n    }\n\n    protected createTextStyles(): void {\n        this.waysCountTextStyle = new TextStyle({\n            fontFamily: 'FuturaPT-ExtraBold, Arial, sans-serif',\n            fontSize: 31,\n            fill: '#FFFFFF',\n        });\n\n        this.waysLableTextStyle = new TextStyle({\n            fontFamily: 'FuturaPT, Arial, sans-serif',\n            fontSize: 18,\n            fill: '#FFFFFF',\n        });\n    }\n\n    protected createTextsConfig(): TextConfig {\n        const config = new TextConfig();\n        config.bounds.width = this._width - 16;\n        config.bounds.height = this._height / 3;\n        config.align = TextAlign.CENTER;\n        config.shouldFitInBounds = true;\n        return config;\n    }\n}\n","import Core, { ITranslator } from '@egt/core';\nimport { TextStyle, Texture } from 'pixi.js';\nimport Text from '../texts/Text';\nimport TextAlign from '../texts/TextAlign';\nimport TextConfig from '../texts/TextConfig';\nimport Button from './Button';\nimport ButtonStates from './ButtonStates';\n\nexport default class WinlinesButton extends Button {\n    protected translator: ITranslator = Core.translator;\n    protected winlinesNumber: Text;\n\n    /**\n     *\n     * @param name\n     * @param _lines\n     * @param _width\n     * @param _height\n     * @param text\n     * @param textures\n     * @param _selectedTextures\n     * @param _selected\n     */\n    constructor(\n        public name: string,\n        protected _lines: number,\n        protected _width: number,\n        protected _height: number,\n        protected _fixed: boolean,\n        protected textures: Texture[],\n        protected _selectedTextures: Texture[],\n        protected _selected: boolean,\n        protected winlineTextStyle: TextStyle,\n        protected winlineTextOffsetY: number,\n        protected textTopOffset: number = 15,\n        protected textLeftOffset: number = 11,\n        protected defaultLinesValueTextStyle?: TextStyle,\n        protected selectedLinesValueTextStyle?: TextStyle,\n    ) {\n        super(textures);\n\n        if (this._selected && this._selectedTextures) {\n            this.button.texture = this._selectedTextures[ButtonStates.Normal];\n        }\n\n        this.create();\n    }\n\n    public setSelectedTextures(newTextures: Texture[]): void {\n        if (newTextures && newTextures.length === 1) {\n            newTextures.push(newTextures[0].clone());\n            newTextures.push(newTextures[0].clone());\n            newTextures.push(newTextures[0].clone());\n        }\n\n        this._selectedTextures = newTextures;\n\n        if (this._selected && this._selectedTextures) {\n            this.button.texture = this._selectedTextures[ButtonStates.Normal];\n        }\n    }\n\n    get selected(): boolean {\n        return this._selected;\n    }\n\n    set selected(value: boolean) {\n        if (this._selected === value) {\n            return;\n        }\n\n        this._selected = value;\n        let texture: Texture;\n\n        if (this._selected && this._selectedTextures) {\n            texture = this._selectedTextures[ButtonStates.Normal];\n        } else {\n            texture = this.textures[ButtonStates.Normal];\n        }\n\n        this.button.texture = texture;\n        this.winlinesNumber.style = this.setWinlinesNumberStyle();\n    }\n\n    get lines(): number {\n        return this._lines;\n    }\n\n    /**\n     * @override\n     */\n    protected getTexture(state: ButtonStates): Texture | null {\n        let texture: Texture;\n        if (this._selected && this._selectedTextures) {\n            texture = this._selectedTextures[state];\n        } else {\n            texture = this.textures[state];\n        }\n        return texture || null;\n    }\n\n    /**\n     *\n     */\n    protected create(): void {\n        const debug: boolean = false;\n\n        // const fixedTextStyle = new TextStyle({\n        //     fontFamily: 'Arial',\n        //     fontSize: 25,\n        //     fontWeight: 'bold',\n        //     fill: '#FFFFFF',\n        //     padding: 5,\n        // });\n        const winlinesNumberConfig: TextConfig = new TextConfig();\n        winlinesNumberConfig.bounds.width = this._width - 14;\n        winlinesNumberConfig.bounds.height = this._height / 3;\n        winlinesNumberConfig.align = TextAlign.CENTER;\n        winlinesNumberConfig.debug = debug;\n        winlinesNumberConfig.shouldFitInBounds = true;\n\n        this.winlinesNumber = new Text(winlinesNumberConfig, this.lines.toString(), this.setWinlinesNumberStyle());\n        this.winlinesNumber.name = this.name + 'Text';\n        this.winlinesNumber.x = this.textLeftOffset;\n        if (this._fixed) {\n            this.winlinesNumber.y = this.textTopOffset;\n        } else {\n            this.winlinesNumber.y = (this.height - this.winlinesNumber.height) / 2 + 5;\n        }\n\n        this.addChild(this.winlinesNumber);\n        if (this._fixed) {\n            const fixedText: Text = new Text(\n                winlinesNumberConfig,\n                this.translator.translate('FIXED'),\n                this.winlineTextStyle,\n            );\n            fixedText.name = this.name + 'Text';\n            fixedText.x = this.textLeftOffset;\n            fixedText.y = this.textTopOffset + this.winlinesNumber.height;\n            this.addChild(fixedText);\n        } else {\n            this.winlinesNumber.y = this.textTopOffset;\n\n            const linesText: Text = new Text(\n                winlinesNumberConfig,\n                this.translator.translate('LINES'),\n                this.winlineTextStyle,\n            );\n            linesText.name = this.name + 'Text';\n            linesText.x = this.textLeftOffset;\n            linesText.y = this.winlineTextOffsetY + this.winlinesNumber.height;\n            this.addChild(linesText);\n        }\n    }\n\n    protected setWinlinesNumberStyle(): TextStyle {\n        const selectedWinlinesNumberStyle =\n            this.selectedLinesValueTextStyle ??\n            new TextStyle({\n                fontFamily: 'Arial',\n                fontSize: 35,\n                fontWeight: 'bold',\n                fill: '#FFFFFF',\n            });\n\n        const defaultWinlinesNumberStyle =\n            this.defaultLinesValueTextStyle ??\n            new TextStyle({\n                fontFamily: 'Arial',\n                fontSize: 35,\n                fontWeight: 'bold',\n                fill: '#C6C5C5',\n            });\n        return this._selected ? selectedWinlinesNumberStyle : defaultWinlinesNumberStyle;\n    }\n}\n","import { Point, TextStyle, Texture } from 'pixi.js';\nimport Text from '../texts/Text';\nimport TextAlign from '../texts/TextAlign';\nimport TextConfig from '../texts/TextConfig';\nimport WinlinesButton from './WinlinesButton';\n\nexport default class WinlinesButtonDesktop extends WinlinesButton {\n    /**\n     *\n     * @param name\n     * @param _lines\n     * @param _width\n     * @param _height\n     * @param text\n     * @param textures\n     * @param _selectedTextures\n     * @param _selected\n     */\n    constructor(\n        public name: string,\n        protected _lines: number,\n        protected _width: number,\n        protected _height: number,\n        protected _fixed: boolean,\n        protected textures: Texture[],\n        protected _selectedTextures: Texture[],\n        protected _selected: boolean,\n        protected winlineTextStyle: TextStyle,\n        protected winlineTextOffsetY: number,\n        protected textTopOffset: number = 15,\n        protected textLeftOffset: number = 11,\n        protected defaultLinesValueTextStyle?: TextStyle,\n        protected selectedLinesValueTextStyle?: TextStyle,\n    ) {\n        super(\n            name,\n            _lines,\n            _width,\n            _height,\n            _fixed,\n            textures,\n            _selectedTextures,\n            _selected,\n            winlineTextStyle,\n            winlineTextOffsetY,\n            textTopOffset,\n            textLeftOffset,\n            defaultLinesValueTextStyle,\n            selectedLinesValueTextStyle,\n        );\n    }\n\n    protected create(): void {\n        const debug: boolean = false;\n        this.textTopOffset = 10;\n        this.textLeftOffset = 9;\n        this.width = this._width;\n        this.height = this._height;\n\n        // const fixedTextStyle = new TextStyle({\n        //     fontFamily: 'Arial',\n        //     fontSize: 18,\n        //     fontWeight: 'bold',\n        //     fill: '#FFFFFF',\n        //     padding: 5,\n        // });\n\n        const winlinesNumberConfig: TextConfig = new TextConfig();\n        winlinesNumberConfig.bounds.width = this._width - 16;\n        winlinesNumberConfig.bounds.height = this._height / 3;\n        winlinesNumberConfig.align = TextAlign.CENTER;\n        winlinesNumberConfig.debug = debug;\n        winlinesNumberConfig.shouldFitInBounds = true;\n\n        const bounds = this.getLocalBounds();\n        if (!this.winlinesNumber) {\n            this.winlinesNumber = new Text(winlinesNumberConfig, this.lines.toString(), this.setWinlinesNumberStyle());\n            this.winlinesNumber.pivot = new Point(this.winlinesNumber.textBounds.width / 2, 0);\n            this.winlinesNumber.name = this.name + 'Text';\n            this.winlinesNumber.x = bounds.width / 2;\n        }\n        if (this._fixed) {\n            this.winlinesNumber.y = this.textTopOffset;\n        } else {\n            this.winlinesNumber.y = (this.height - this.winlinesNumber.height) / 2 + 5;\n        }\n\n        this.addChild(this.winlinesNumber);\n        if (this._fixed) {\n            const fixedText: Text = new Text(\n                winlinesNumberConfig,\n                this.translator.translate('FIXED'),\n                this.winlineTextStyle,\n            );\n            fixedText.pivot = new Point(fixedText.textBounds.width / 2, 0);\n            fixedText.name = this.name + 'Text';\n            fixedText.x = bounds.width / 2;\n            fixedText.y = this.textTopOffset + this.winlinesNumber.height;\n            this.addChild(fixedText);\n        } else {\n            this.winlinesNumber.y = this.textTopOffset;\n\n            const linesText: Text = new Text(\n                winlinesNumberConfig,\n                this.translator.translate('LINES'),\n                this.winlineTextStyle,\n            );\n            linesText.name = this.name + 'Text';\n            linesText.x = this.textLeftOffset;\n            linesText.y = this.winlineTextOffsetY + this.winlinesNumber.height;\n            this.addChild(linesText);\n        }\n    }\n\n    protected setWinlinesNumberStyle(): TextStyle {\n        const selectedWinlinesNumberStyle =\n            this.selectedLinesValueTextStyle ??\n            new TextStyle({\n                fontFamily: 'Arial',\n                fontSize: 24,\n                fontWeight: 'bold',\n                fill: '#FFFFFF',\n            });\n        const defaultWinlinesNumberStyle =\n            this.defaultLinesValueTextStyle ??\n            new TextStyle({\n                fontFamily: 'Arial',\n                fontSize: 24,\n                fontWeight: 'bold',\n                fill: '#C6C5C5',\n            });\n        return this._selected ? selectedWinlinesNumberStyle : defaultWinlinesNumberStyle;\n    }\n}\n","import { Graphics, IBitmapTextStyle, TextStyle } from 'pixi.js';\nimport ViewContainer from '../ViewContainer';\nimport AnimatedMoneyTextV2 from '../texts/AnimatedMoneyTextV2';\nimport Text from '../texts/Text';\nimport TextConfig from '../texts/TextConfig';\nimport TextAlign from '../texts/TextAlign';\nimport AnimatedMoneyTextConfigV2 from '../texts/AnimatedMoneyTextConfigV2';\nimport Core from '@egt/core';\nimport VerticalTextAlign from '../texts/VerticalTextAlign';\nimport { IBoundsAndPositions } from '../interfaces/Interfaces';\n\nexport default class MoneyContainerGroup extends ViewContainer {\n    public moneyAnimatedText: AnimatedMoneyTextV2;\n    public creditsAnimatedText: AnimatedMoneyTextV2;\n    public labelText: Text;\n    public currencyText: Text;\n    public groupHitArea: Graphics;\n\n    constructor(\n        private id: string,\n        private label: string,\n        private containerWidth: number,\n        private containerHeight: number,\n        private boundsAndPositions: IBoundsAndPositions,\n        private textsStyles: {\n            currencyStyle: TextStyle;\n            labelStyle: TextStyle;\n            moneyStyle: TextStyle;\n            moneyTint: number;\n            creditsStyle: TextStyle;\n        },\n        private currency: string,\n        private units: number,\n    ) {\n        super();\n        this.createElements();\n    }\n\n    public onMoneyModeChanged(): void {\n        this.moneyAnimatedText.visible = this.moneyAnimatedText.visible = Core.MONEY_MODE_IN_CREDITS.value;\n        this.currencyText.visible = this.currencyText.visible = !Core.MONEY_MODE_IN_CREDITS.value;\n    }\n\n    public setOrientation(\n        containerWidth: number,\n        containerHeight: number,\n        boundsAndPositions: IBoundsAndPositions,\n    ): void {\n        this.containerWidth = containerWidth;\n        this.containerHeight = containerHeight;\n        this.boundsAndPositions = boundsAndPositions;\n        //MAKE THIS INTO CONFIG\n        const y = Core.ORIENTATION.value.isLandscape ? 10 : 12;\n        this.currencyText.y = this.boundsAndPositions.currency.lineOffset;\n        this.currencyText.style = this.boundsAndPositions.currency.style;\n        this.creditsAnimatedText.updateBounds(\n            0,\n            y,\n            this.boundsAndPositions.credits.width,\n            this.boundsAndPositions.credits.height,\n            this.boundsAndPositions.credits.style,\n        );\n        // this.creditsAnimatedText.y = this.boundsAndPositions.money.height + this.boundsAndPositions.credits.lineOffset;\n        this.creditsAnimatedText.y = this.moneyAnimatedText.y + this.boundsAndPositions.credits.lineOffset;\n        this.moneyAnimatedText.updateBounds(\n            0,\n            0,\n            this.boundsAndPositions.money.width,\n            this.boundsAndPositions.money.height,\n            this.boundsAndPositions.money.style,\n        );\n        this.moneyAnimatedText.y = -2;\n        // if (this.moneyAnimatedText.visible) {\n        //     this.creditsAnimatedText.y =\n        //         this.boundsAndPositions.money.height + this.boundsAndPositions.credits.lineOffset + 1;\n        // }\n        this.creditsAnimatedText.y = this.currencyText.y + this.boundsAndPositions.credits.lineOffset;\n\n        this.groupHitArea.width = this.containerWidth;\n        this.groupHitArea.height = this.containerHeight;\n        this.labelText.style = this.boundsAndPositions.label.style;\n        this.labelText.textBounds = {\n            width: this.boundsAndPositions.label.width,\n            height: this.boundsAndPositions.label.height,\n        };\n        this.labelText.y =\n            this.creditsAnimatedText.y + this.creditsAnimatedText.height + this.boundsAndPositions.label.lineOffset;\n        // this.labelText.y = 64;\n        this.currencyText.textBounds = {\n            width: this.boundsAndPositions.currency.width,\n            height: this.boundsAndPositions.currency.height,\n        };\n    }\n\n    public destroy(): void {\n        this.moneyAnimatedText.destroy();\n        this.creditsAnimatedText.destroy();\n        this.labelText.destroy();\n        this.currencyText.destroy();\n    }\n\n    public toggleInteractivity(interactive: boolean): void {\n        this.interactive = interactive;\n        this.buttonMode = interactive;\n        this.groupHitArea.interactive = interactive;\n        this.groupHitArea.buttonMode = interactive;\n    }\n\n    private createElements() {\n        const debug: boolean = false;\n        this.name = this.id + 'Container';\n        const currencyId: string = this.id + 'Currency';\n        const moneyId: string = this.id + 'Money';\n        const creditsId: string = this.id + 'Credits';\n        const textId: string = this.id + 'Text';\n\n        // create currency text\n        const currencyTextConfig: TextConfig = new TextConfig();\n        currencyTextConfig.bounds.width = this.boundsAndPositions.currency.width;\n        currencyTextConfig.bounds.height = this.boundsAndPositions.currency.height;\n        currencyTextConfig.align = TextAlign.CENTER;\n        currencyTextConfig.debug = debug;\n        currencyTextConfig.shouldFitInBounds = true;\n\n        this.currencyText = new Text(\n            currencyTextConfig,\n            Core.PLAYER_BALANCE.value.currency,\n            this.textsStyles.currencyStyle,\n        );\n        this.currencyText.name = currencyId;\n        // this.currencyText.x = this.currencyText.x;\n        this.addChild(this.currencyText);\n\n        // create money text\n        const monyConfig: AnimatedMoneyTextConfigV2 = new AnimatedMoneyTextConfigV2();\n        monyConfig.units = this.units;\n        monyConfig.bounds.x = 0;\n        monyConfig.bounds.y = 0;\n        monyConfig.bounds.width = this.boundsAndPositions.money.width;\n        monyConfig.bounds.height = this.boundsAndPositions.money.height;\n        monyConfig.align = TextAlign.CENTER;\n        monyConfig.debug = debug;\n        monyConfig.shouldFitInBounds = true;\n        monyConfig.showCurrency = true;\n        monyConfig.alwaysInCurrency = true;\n        monyConfig.currency = this.currency;\n        monyConfig.denomination = Core.SELECTED_DENOMINATION.value;\n        monyConfig.bitMapTextStyle = {\n            fontName: 'jackpotsCountersBitmapFont',\n            align: 'center',\n            fontSize: Number(this.textsStyles.moneyStyle.fontSize) * 2,\n            tint: this.textsStyles.moneyTint,\n        } as IBitmapTextStyle;\n\n        this.moneyAnimatedText = new AnimatedMoneyTextV2('moneyBitmapFont', monyConfig, 0, this.textsStyles.moneyStyle);\n        this.moneyAnimatedText.name = moneyId;\n        this.moneyAnimatedText.x = this.moneyAnimatedText.x;\n        this.moneyAnimatedText.visible = !Core.MONEY_MODE_IN_CREDITS.value;\n        this.addChild(this.moneyAnimatedText);\n\n        // create credits text\n        const creditsConfig: AnimatedMoneyTextConfigV2 = new AnimatedMoneyTextConfigV2();\n        creditsConfig.units = this.units;\n        creditsConfig.bounds.x = 0;\n        creditsConfig.bounds.y = Core.isDesktopMode || Core.ORIENTATION.value.orientation === 'Landscape' ? 10 : 12;\n        creditsConfig.bounds.width = this.boundsAndPositions.credits.width;\n        creditsConfig.bounds.height = this.boundsAndPositions.credits.height;\n        creditsConfig.align = TextAlign.CENTER;\n        creditsConfig.debug = debug;\n        creditsConfig.shouldFitInBounds = true;\n        creditsConfig.showCurrency = false;\n        creditsConfig.alwaysInCurrency = false;\n        creditsConfig.currency = this.currency;\n        creditsConfig.denomination = Core.SELECTED_DENOMINATION.value;\n        creditsConfig.bitMapTextStyle = {\n            fontName: 'jackpotsCountersBitmapFont',\n            align: 'center',\n            fontSize: Number(this.textsStyles.creditsStyle.fontSize) * 2,\n        } as IBitmapTextStyle;\n        // tint: 0x223344} as IBitmapTextStyle;\n\n        this.creditsAnimatedText = new AnimatedMoneyTextV2(\n            'creditsBitmapFont',\n            creditsConfig,\n            0,\n            this.textsStyles.creditsStyle,\n        );\n        this.creditsAnimatedText.name = creditsId;\n        this.creditsAnimatedText.x = this.creditsAnimatedText.x;\n\n        this.addChild(this.creditsAnimatedText);\n\n        // create label text\n        // const labelConfig: AnimatedMoneyTextConfigV2 = new AnimatedMoneyTextConfigV2();\n        // labelConfig.units = this.units;\n        // labelConfig.bounds.width = this.boundsAndPositions.money.width;\n        // labelConfig.bounds.height = this.boundsAndPositions.money.height;\n        // labelConfig.align = TextAlign.CENTER;\n        // labelConfig.debug = true;\n        // labelConfig.shouldFitInBounds = true;\n        // labelConfig.showCurrency = true;\n        // labelConfig.alwaysInCurrency = true;\n        // labelConfig.currency = this.currency;\n        // labelConfig.denomination = Core.SELECTED_DENOMINATION.value;\n\n        // this.labelText = new Text(labelConfig, this.label, this.textsStyles.labelStyle);\n        // this.labelText.name = textId;\n        // this.addChild(this.labelText);\n\n        // create label text\n        const labelConfig: TextConfig = new TextConfig();\n        labelConfig.bounds.width = this.boundsAndPositions.currency.width;\n        labelConfig.bounds.height = this.boundsAndPositions.currency.height;\n        labelConfig.align = TextAlign.CENTER;\n        labelConfig.verticalAlign = VerticalTextAlign.ALIGN_BASELINE;\n        labelConfig.debug = debug;\n        labelConfig.shouldFitInBounds = true;\n\n        this.labelText = new Text(labelConfig, this.label, this.textsStyles.labelStyle);\n        this.labelText.name = textId;\n        this.addChild(this.labelText);\n\n        // create hit area\n        this.groupHitArea = new Graphics();\n        this.groupHitArea.beginFill(0xffffff);\n        this.groupHitArea.alpha = 0;\n        this.groupHitArea.drawRect(0, 0, this.containerWidth, this.containerHeight);\n        this.groupHitArea.endFill();\n        this.groupHitArea.interactive = this.interactive;\n        this.groupHitArea.buttonMode = this.buttonMode;\n        this.addChild(this.groupHitArea);\n    }\n}\n","import * as ES6Promise from 'es6-promise';\nimport 'reflect-metadata';\nES6Promise.polyfill();\n\nimport BetButton from './buttons/BetButton';\nimport Button from './buttons/Button';\nimport ButtonShapes from './buttons/ButtonShapes';\nimport ButtonStates from './buttons/ButtonStates';\nimport DenominationButton from './buttons/DenominationButton';\nimport DenominationButtonDesktop from './buttons/DenominationButtonDesktop';\nimport DenominationOptionButton from './buttons/DenominationOptionButton';\nimport FakeBetButton from './buttons/FakeBetButton';\n// import DenominationOptionButtonDesktop from './buttons/DenominationOptionButtonDesktop';\nimport HighCashFakeBetButton from './buttons/HighCashFakeBetButton';\nimport ToggleButton from './buttons/ToggleButton';\nimport ValueButton from './buttons/ValueButton';\n// import NumericKeyboardButton from './buttons/NumericKeyboardButton';\nimport WaysPayWinlinesButton from './buttons/WaysPayWinlinesButton';\nimport WaysPayWinlinesButtonDesktop from './buttons/WaysPayWinlinesButtonDesktop';\nimport WinlinesButton from './buttons/WinlinesButton';\nimport WinlinesButtonDesktop from './buttons/WinlinesButtonDesktop';\nimport MoneyContainerGroup from './groups/MoneyContainerGroup';\nimport Slider from './Slider';\nimport SteppedSlider from './SteppedSlider';\nimport AnimatedMoneyText from './texts/AnimatedMoneyText';\nimport AnimatedMoneyTextConfigV2 from './texts/AnimatedMoneyTextConfigV2';\nimport AnimatedMoneyTextV2 from './texts/AnimatedMoneyTextV2';\nimport BangUpAnimatedCurrencyText from './texts/BangUpAnimatedCurrencyText';\nimport BangUpBitMapCurrencyText from './texts/BangUpBitMapCurrencyText';\nimport JackpotBangUpBitMapText from './texts/JackpotBangUpBitMapText';\nimport BangUpBitMapText from './texts/BangUpBitMapText';\nimport BangUpCurrencyText from './texts/BangUpCurrencyText';\nimport BangUpText from './texts/BangUpText';\nimport BangUpTextBounds from './texts/BangUpTextBounds';\nimport BluredText from './texts/BluredText';\nimport { ITextConfig } from './texts/ITextConfig';\nimport MoneyText from './texts/MoneyText';\nimport MoneyTextConfig from './texts/MoneyTextConfig';\nimport Text from './texts/Text';\nimport TextAlign from './texts/TextAlign';\nimport TextConfig from './texts/TextConfig';\nimport VerticalTextAlign from './texts/VerticalTextAlign';\nimport TitledWindow from './TitledWindow';\nimport UIBlocker from './UIBlocker';\nimport JackpotCounterBase, { JackpotLevel } from './JackpotCounterBase';\nimport ViewContainer from './ViewContainer';\nimport ViewVisibilityContainer from './ViewVisibilityContainer';\nimport { InputField } from './input-field/InputField';\nimport {\n    IContainerGraphicsInterfaceNumeric,\n    IKeyboardButtonPositionNumeric,\n    IKeyboardButtonTextConfigNumeric,\n    IKeyboardButtonsContainerPositionNumeric,\n    IKeyboardContainerPositionNumeric,\n    IKeyboardRowPositionNumeric,\n    IKeyboardShadowBackgroundConfigNumeric,\n    IPopUpCancelButtonInterface,\n    IPopUpDoneButtonInterface,\n    IBalanceAndBetTextNumeric,\n    IKeyboardScaleConfigNumeric,\n    IContainerGraphicsInterfaceMaxBet,\n    IKeyboardButtonTextConfigMaxBet,\n    IKeyboardButtonsContainerPositionMaxBet,\n    IKeyboardContainerPositionMaxBet,\n    IKeyboardButtonPositionMaxBet,\n    IKeyboardScaleConfigMaxBet,\n    IPopUpButtonInterfaceMaxBet,\n} from './interfaces/INumericKeyboard';\nimport { KeyboardNumeric } from './numeric-keyboard/KeyboardNumeric';\nimport KeyboardActionButtonNumeric from './buttons/KeyboardActionButtonNumeric';\nimport KeyboardButtonNumeric from './buttons/KeyboardButtonNumeric';\nimport BangUpBitMapCurrencyTextDynamicPivot from './texts/BangUpBitMapCurrencyTextDynamicPivot';\nimport BangUpBitMapTextDynamicPivot from './texts/BangUpBitMapTextDynamicPivot';\nexport * from './interfaces/IBackgroundAssets';\nexport * from './interfaces/Interfaces';\nexport * from './interfaces/ITitledWindowConfig';\nexport * from './interfaces/IViewVisiilityContainer';\nexport * from './texts/TextFitting';\n\nexport {\n    AnimatedMoneyText,\n    AnimatedMoneyTextConfigV2,\n    AnimatedMoneyTextV2,\n    BangUpAnimatedCurrencyText,\n    BangUpBitMapCurrencyText,\n    JackpotBangUpBitMapText,\n    BangUpBitMapText,\n    BangUpCurrencyText,\n    BangUpText,\n    BangUpTextBounds,\n    BetButton,\n    BluredText,\n    Button,\n    KeyboardButtonNumeric,\n    ButtonShapes,\n    ButtonStates,\n    DenominationButton,\n    DenominationButtonDesktop,\n    DenominationOptionButton,\n    IContainerGraphicsInterfaceNumeric,\n    IKeyboardButtonPositionNumeric,\n    IKeyboardButtonTextConfigNumeric,\n    IKeyboardButtonsContainerPositionNumeric,\n    IKeyboardContainerPositionNumeric,\n    KeyboardActionButtonNumeric,\n    InputField,\n    IKeyboardRowPositionNumeric,\n    IKeyboardScaleConfigNumeric,\n    IBalanceAndBetTextNumeric,\n    IKeyboardShadowBackgroundConfigNumeric,\n    IPopUpCancelButtonInterface,\n    IPopUpDoneButtonInterface,\n    KeyboardNumeric,\n    // IButtonTextStyleProperties,\n    // IBetButtonConfig,\n    // IBetButtonStyle,\n    // AutoAlign,\n    // IInnerTextConfig,\n    // IInnerStampConfig,\n    // IBetButtonsConfig,\n    FakeBetButton,\n    HighCashFakeBetButton,\n    ITextConfig,\n    JackpotCounterBase,\n    JackpotLevel,\n    MoneyContainerGroup,\n    MoneyText,\n    MoneyTextConfig,\n    Slider,\n    SteppedSlider,\n    // ITitledWindowConfig,\n    // IBackgroundAssets,\n    Text,\n    TextAlign,\n    TextConfig,\n    TitledWindow,\n    ToggleButton,\n    // IViewVisibilityContainer,\n    UIBlocker,\n    ValueButton,\n    VerticalTextAlign,\n    ViewContainer,\n    ViewVisibilityContainer,\n    WaysPayWinlinesButton,\n    WaysPayWinlinesButtonDesktop,\n    WinlinesButton,\n    WinlinesButtonDesktop,\n    IContainerGraphicsInterfaceMaxBet,\n    IKeyboardButtonsContainerPositionMaxBet,\n    IKeyboardButtonTextConfigMaxBet,\n    IKeyboardContainerPositionMaxBet,\n    IKeyboardScaleConfigMaxBet,\n    IKeyboardButtonPositionMaxBet,\n    IPopUpButtonInterfaceMaxBet,\n    BangUpBitMapCurrencyTextDynamicPivot,\n    BangUpBitMapTextDynamicPivot,\n};\n\n// biome-ignore lint/complexity/noBannedTypes: <explanation>\nexport function getInheritanceLevel(clazz: Function, level = 0): number {\n    if (clazz === Object || clazz === null) {\n        return level;\n    }\n    const prototype = Object.getPrototypeOf(clazz.prototype);\n    return getInheritanceLevel(prototype.constructor, level + 1);\n}\n\nexport const pipe =\n    (...fns: Array<(v: any) => any>) =>\n    (x: any) =>\n        fns.reduce((v: any, f) => f(v), x);\n","import { MoneyFormatter } from '@egt/core';\nimport { InputFieldConfig, ViewContainer } from '@egt/ui-lib';\nimport { Sprite, Text, TextStyle, Texture } from 'pixi.js';\nimport { Subject } from 'rxjs';\n\nexport class InputField extends ViewContainer {\n    public readonly FOCUS = new Subject<InputField>();\n    public readonly INPUT = new Subject<string>();\n    public readonly ERROR = new Subject<boolean>();\n\n    // UI elements\n    private inputBackground: Sprite;\n    private inputText: Text;\n    private caretText: Text;\n    private placeholderValueLabel: Text;\n    private placeholderCurrencyText: Text;\n    // private currencyYOffset: number = 2;\n\n    // Textures and styles\n    private normalTexture: Texture;\n    private selectedTexture: Texture;\n    private errorTexture: Texture;\n    private normalStyle: TextStyle;\n    private hilightedStyle: TextStyle;\n    private currencyNormalStyle: TextStyle;\n    private currencyHilightedStyle: TextStyle;\n\n    // State and value\n    private _state: FieldsStates = FieldsStates.Inactive;\n    private _value: string = '';\n    public hasError: boolean = false;\n    private caretInterval: any = null;\n    private isActive: boolean = false;\n    private _lastConfirmedValue: string = '';\n\n    // Configuration and settings\n    private config: InputFieldConfig;\n    private currency: string;\n    private maxValue: number | null = null;\n    private minValue: number | null = null;\n    private currencyOffset: number = 5;\n\n    constructor(config: InputFieldConfig) {\n        super();\n        this.config = config;\n        this.x = config.fieldX;\n        this.y = config.fieldY;\n        this.width = config.fieldWidth;\n        this.height = config.fieldHeight;\n        this.currency = config.currency;\n        this.initialRender();\n    }\n\n    private initialRender() {\n        this.initStylesAndTextures();\n        this.createInputBackground();\n        this.createInputText();\n        this.createCaretText();\n        this.createPlaceholderLabel();\n        this.setValue('');\n    }\n    private initStylesAndTextures(): void {\n        this.normalTexture = this.config.normalTexture;\n        this.selectedTexture = this.config.hilightedTexture;\n        this.normalStyle = this.config.fieldNormalTextStyle;\n        this.hilightedStyle = this.config.fieldHilightedTextStyle;\n        this.errorTexture = this.config.inputErrorTexture;\n        this.currencyNormalStyle = this.config.currencyNormaTextStyle;\n        this.currencyHilightedStyle = this.config.currencyHilightedTextStyle;\n\n        this.normalStyle.trim = true;\n        this.hilightedStyle.trim = true;\n        this.currencyNormalStyle.trim = true;\n        this.currencyHilightedStyle.trim = true;\n    }\n\n    private createInputBackground(): void {\n        this.inputBackground = new Sprite(this.normalTexture);\n        this.inputBackground.interactive = true;\n        // this.inputBackground.buttonMode = true;\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/slot-features/ui-lib/src/egt/ui/input-field/InputField.ts:81:9\",(this.inputBackground),\"pointertap\"]), this.inputBackground.on('pointertap', this.onInputClick, this));\n        this.addChild(this.inputBackground);\n    }\n\n    private createInputText(): void {\n        // set firs to 0 and then to empty string to get correct height of text input\n        this.inputText = new Text('0', this.normalStyle);\n        this.inputText.anchor.set(0.5, 1);\n        this.inputText.x = this.inputBackground.width / 2;\n        this.inputText.y = this.inputBackground.height / 2 + this.inputText.height / 2;\n        this.inputText.text = '';\n        this.addChild(this.inputText);\n    }\n\n    private createCaretText(): void {\n        this.caretText = new Text('|', this.normalStyle);\n        this.caretText.anchor.set(0.5, 1);\n        this.caretText.x = this.inputText.x + this.inputText.width / 2;\n        this.caretText.y = this.inputText.y;\n        this.caretText.visible = false;\n        this.addChild(this.caretText);\n    }\n\n    private startCaretBlink(): void {\n        if (this.caretInterval) return;\n        this.caretInterval = setInterval(() => {\n            this.caretText.visible = !this.caretText.visible;\n        }, 500);\n    }\n\n    private createPlaceholderLabel(): void {\n        this.placeholderValueLabel = new Text('0.00', this.normalStyle);\n        this.placeholderValueLabel.anchor.set(0.5, 1);\n\n        this.placeholderCurrencyText = new Text(this.currency, this.currencyNormalStyle);\n        this.placeholderCurrencyText.anchor.set(0, 1);\n\n        this.placeholderValueLabel.x = this.inputBackground.x + this.inputBackground.width / 2;\n        this.placeholderValueLabel.y = this.inputText.y;\n        this.placeholderCurrencyText.x =\n            this.placeholderValueLabel.x + this.placeholderValueLabel.width / 2 + this.currencyOffset;\n        this.placeholderCurrencyText.y = this.inputText.y;\n\n        this.addChild(this.placeholderValueLabel);\n        this.addChild(this.placeholderCurrencyText);\n    }\n\n    private stopCaretBlink(): void {\n        if (this.caretInterval) {\n            clearInterval(this.caretInterval);\n            this.caretInterval = null;\n        }\n        this.caretText.visible = false;\n    }\n\n    public setActive(): void {\n        this.isActive = true;\n        this.state = FieldsStates.Active;\n        this.placeholderValueLabel.visible = false;\n        this.inputText.visible = true;\n        this.inputText.style = this.hilightedStyle;\n        this.caretText.visible = true;\n        this.startCaretBlink();\n        this.setInteractive(false);\n        this.scaleTextToFit();\n        this.updateInputTextPosition();\n        this.updateCaretPosition();\n    }\n\n    public setInactive(): void {\n        this.isActive = false;\n        this.state = FieldsStates.Inactive;\n        this.caretText.visible = false;\n        this.stopCaretBlink();\n        this.updateVisibility();\n        this.updateCaretPosition();\n        this.setInteractive(true);\n        this.confirmValue();\n    }\n\n    private onInputClick() {\n        this.FOCUS.next(this);\n    }\n\n    public resetToInitial(): void {\n        this.setInactive();\n        this.setValue('', true);\n        this._lastConfirmedValue = '';\n        this.updatePlaceholderPosition();\n    }\n\n    public setMaxValue(value: number | null) {\n        this.maxValue = Math.ceil(value as number);\n        this.checkForError();\n    }\n    public getMaxValue(): number {\n        return this.maxValue ? this.maxValue : Number.MAX_VALUE;\n    }\n\n    public setMinValue(value: number | null) {\n        this.minValue = Math.ceil(value as number);\n        this.checkForError();\n    }\n\n    public getMinValue(): number {\n        return this.minValue ? this.minValue : 0;\n    }\n\n    private checkForError() {\n        let isError = false;\n        if (this.maxValue !== null && this._value) {\n            const numericValue = Number(this._value);\n            if (\n                (!isNaN(numericValue) && this.maxValue !== null && numericValue > this.maxValue / 100) ||\n                (!isNaN(numericValue) && this.minValue !== null && numericValue < this.minValue / 100)\n            ) {\n                this.inputBackground.texture = this.errorTexture;\n                isError = true;\n            } else if (this.state === FieldsStates.Active) {\n                this.inputBackground.texture = this.selectedTexture;\n            } else {\n                this.inputBackground.texture = this.normalTexture;\n            }\n        } else {\n            if (this.state === FieldsStates.Active) {\n                this.inputBackground.texture = this.selectedTexture;\n            } else {\n                this.inputBackground.texture = this.normalTexture;\n            }\n        }\n\n        // Check for invalid formats\n        if (/^\\d+\\.$/.test(this._value)) {\n            isError = true;\n            this.inputBackground.texture = this.errorTexture;\n        }\n\n        this.hasError = isError;\n        this.ERROR.next(isError);\n    }\n    // ...existing code...\n\n    private updateVisibility(): void {\n        if (!this._value || this._value.length === 0) {\n            if (this.state === FieldsStates.Inactive) {\n                this.placeholderValueLabel.visible = true;\n                this.inputText.visible = false;\n                this.updatePlaceholderPosition();\n                this.placeholderCurrencyText.style = this.currencyNormalStyle;\n            } else {\n                this.placeholderValueLabel.visible = false;\n                this.inputText.visible = true;\n                this.placeholderCurrencyText.style = this.currencyHilightedStyle;\n            }\n            this.inputText.text = '';\n        } else {\n            this.placeholderValueLabel.visible = false;\n            this.inputText.visible = true;\n\n            if (this._value.includes('.')) {\n                this.inputText.text =\n                    new MoneyFormatter(Number(this._value) * 100).stringMoneyWithoutCents.replace('.00', '') +\n                    '.' +\n                    this._value.split('.')[1];\n            } else {\n                this.inputText.text = new MoneyFormatter(Number(this._value) * 100).stringMoney.replace('.00', '');\n            }\n\n            this.placeholderCurrencyText.style = this.currencyHilightedStyle;\n        }\n    }\n\n    private updatePlaceholderPosition(): void {\n        const numberWidth = this.placeholderValueLabel.width;\n        const totalWidth = numberWidth + this.placeholderCurrencyText.width + this.currencyOffset;\n        const centerX = this.inputBackground.x + this.inputBackground.width / 2;\n        const numberX = centerX - totalWidth / 2 + numberWidth / 2;\n\n        this.placeholderValueLabel.x = numberX;\n        this.placeholderCurrencyText.x = numberX + numberWidth / 2 + this.currencyOffset;\n        this.placeholderCurrencyText.y = this.inputText.y;\n    }\n\n    private updateInputTextPosition(): void {\n        const numberWidth = this.inputText.width;\n        const totalWidth = numberWidth + this.placeholderCurrencyText.width + this.currencyOffset;\n        const centerX = this.inputBackground.x + this.inputBackground.width / 2;\n        const numberX = centerX - totalWidth / 2 + numberWidth / 2;\n\n        this.inputText.x = numberX;\n\n        // const inputTextBottom = this.inputText.y + this.inputText.height * 0.5;\n\n        this.placeholderCurrencyText.x = numberX + numberWidth / 2 + this.currencyOffset;\n        this.placeholderCurrencyText.y = this.inputText.y;\n    }\n\n    private updateCaretPosition(): void {\n        this.caretText.x = this.inputText.x + this.inputText.width / 2;\n        this.caretText.y = this.inputText.y;\n    }\n\n    public set state(state: FieldsStates) {\n        this._state = state;\n        if (this.hasError) {\n            this.inputBackground.texture = this.errorTexture;\n        } else if (state === FieldsStates.Active) {\n            this.inputBackground.texture = this.selectedTexture;\n        } else {\n            this.inputBackground.texture = this.normalTexture;\n        }\n\n        if (state === FieldsStates.Active) {\n            this.inputText.style = this.hilightedStyle;\n            this.placeholderCurrencyText.style = this.currencyHilightedStyle;\n        } else {\n            if (this._value && this._value.length > 0) {\n                this.inputText.style = this.hilightedStyle;\n                this.placeholderCurrencyText.style = this.currencyHilightedStyle;\n            } else {\n                this.inputText.style = this.normalStyle;\n                this.placeholderCurrencyText.style = this.currencyNormalStyle;\n            }\n        }\n    }\n\n    private scaleTextToFit(): void {\n        const bounds = this.inputBackground.width - this.currencyOffset * 3;\n        const numberText = this.inputText.visible ? this.inputText : this.placeholderValueLabel;\n\n        numberText.scale.set(1);\n        this.placeholderCurrencyText.scale.set(1);\n\n        const numberWidth = numberText.width;\n        const currencyWidth = this.placeholderCurrencyText.width;\n        const totalWidth = numberWidth + this.currencyOffset + currencyWidth;\n\n        let scale = 1;\n        if (totalWidth > bounds) {\n            scale = bounds / totalWidth;\n        }\n\n        numberText.scale.set(scale);\n        this.placeholderCurrencyText.scale.set(scale);\n    }\n\n    private setInteractive(interactive: boolean): void {\n        this.inputBackground.interactive = interactive;\n        this.inputBackground.buttonMode = interactive;\n    }\n\n    private confirmValue(): void {\n        this._lastConfirmedValue = this._value;\n    }\n\n    public restoreLastConfirmedValue(): void {\n        this.setValue(this._lastConfirmedValue);\n    }\n\n    public get state(): FieldsStates {\n        return this._state;\n    }\n\n    private normalizeInputValue(value: string): string {\n        let filtered = value.replace(/[^0-9.]/g, '');\n\n        const parts = filtered.split('.');\n\n        filtered = parts[0];\n        if (parts.length > 1) {\n            filtered += '.' + parts[1].slice(0, 2);\n        }\n\n        if (filtered.startsWith('00')) {\n            filtered = filtered.replace(/^0+/, '0');\n        }\n\n        if (/^0[0-9]+/.test(filtered)) {\n            filtered = filtered.replace(/^0+/, '');\n        }\n\n        if (filtered.startsWith('.')) {\n            filtered = '0' + filtered;\n        }\n\n        if (filtered === '.') {\n            filtered = '';\n        }\n\n        return filtered;\n    }\n\n    public setValue(value: string, forceUpdate: boolean = false) {\n        if (!this.isActive && !forceUpdate) {\n            return;\n        }\n        this._value = this.normalizeInputValue(value);\n\n        if (this._state === FieldsStates.Inactive && value && value.length > 0) {\n            this.setActive();\n        }\n\n        this.placeholderCurrencyText.visible = true;\n        this.updateVisibility();\n        this.scaleTextToFit();\n\n        if (this.inputText.visible) {\n            this.updateInputTextPosition();\n        } else {\n            this.updatePlaceholderPosition();\n        }\n\n        if (this.isActive) {\n            this.caretText.visible = true;\n            this.updateCaretPosition();\n        } else {\n            this.caretText.visible = false;\n        }\n\n        this.checkForError();\n        this.INPUT.next(this._value);\n    }\n\n    public getValue(): string {\n        return this._value;\n    }\n}\n\nexport enum FieldsStates {\n    Inactive,\n    Active,\n}\n","import { TextStyle, TextStyleFontWeight, Texture } from 'pixi.js';\nimport { TextAlign } from '..';\n\nexport interface IButtonTextStyleProperties {\n    fontFamily?: string;\n    fontSize?: number;\n    fontWeight?: TextStyleFontWeight;\n    fill?: string;\n    padding?: number;\n}\n\nexport interface IBetButtonsConfig {\n    currency: IInnerTextConfig;\n    amount: IInnerTextConfig;\n    label: IInnerTextConfig;\n    stamp: IInnerStampConfig;\n    textures: string[];\n    selectedTextures: string[];\n    fakeMaskTexture: string;\n    width: number;\n    height: number;\n}\nexport interface IBetButtonsBuyBonusConfig {\n    textures: string[];\n}\n\nexport interface IBetButtonConfig {\n    name: string;\n    betPerLine: number;\n    currency: string;\n    units: number;\n    denomination: number;\n    lines: number;\n    factor: number;\n    width: number;\n    height: number;\n    text: string;\n    textures?: Texture[];\n    selectedTextures?: Texture[];\n    fakeMaskTexture?: Texture;\n    selected?: boolean;\n    // betButtonStyles?: IBetButtonStyle;\n    dynamicConfig?: IBetButtonsConfig;\n    maxBet?: number;\n    maxBetBuyBonus?: number;\n}\n\nexport interface IBetButtonStyle {\n    buttonStandard?: {\n        // currency\n        currencyStyle?: IButtonTextStyleProperties;\n        // amount\n        amountStyle?: IButtonTextStyleProperties;\n        // play\n        labelStyle?: IButtonTextStyleProperties;\n    };\n    buttonStandardPressed?: {\n        currencyStyle?: IButtonTextStyleProperties;\n        amountStyle?: IButtonTextStyleProperties;\n        labelStyle?: IButtonTextStyleProperties;\n    };\n}\n\nexport enum AutoAlign {\n    CENTER = 'Center',\n}\n\nexport interface IInnerTextConfig {\n    visible: boolean;\n    defaultStyle: TextStyle;\n    selectedStyle: TextStyle;\n    x: number | AutoAlign.CENTER;\n    y: number;\n    bounds: { width: number; height: number };\n    shouldFitInBounds: boolean;\n    textAlign: TextAlign;\n    debug: boolean;\n}\n\nexport interface IInnerStampConfig {\n    hasStamp: boolean;\n    x: number;\n    y: number;\n    width: number;\n    height: number;\n    alpha: number;\n    texture: { source: string; name: string };\n}\n\nexport interface IBoundsAndPositions {\n    currency: { width: number; height: number; lineOffset: number; style: TextStyle };\n    money: { width: number; height: number; lineOffset: number; style: TextStyle };\n    credits: { width: number; height: number; lineOffset: number; style: TextStyle };\n    label: { width: number; height: number; lineOffset: number; style: TextStyle };\n}\n\n// Configuration interface for the input field\nexport interface InputFieldConfig {\n    containerX: number;\n    containerY: number;\n    fieldX: number;\n    fieldY: number;\n    fieldWidth: number;\n    fieldHeight: number;\n    fieldNormalTextStyle: TextStyle;\n    fieldHilightedTextStyle: TextStyle;\n    currencyNormaTextStyle: TextStyle;\n    currencyHilightedTextStyle: TextStyle;\n    normalTexture: Texture;\n    hilightedTexture: Texture;\n    inputErrorTexture: Texture;\n    currency: string;\n}\n\n// Interface for field object configuration\nexport interface IInputFieldObject {\n    containerX: number;\n    containerY: number;\n    fieldX: number;\n    fieldY: number;\n    titleX: number;\n    titleY: number;\n    underTitleX: number;\n    underTitleY: number;\n    fieldWidth: number;\n    fieldHeight: number;\n    errorFill: string;\n    fieldNormalTextStyle: TextStyle;\n    fieldHilightedTextStyle: TextStyle;\n    currencyNormaTextStyle: TextStyle;\n    currencyHilightedTextStyle: TextStyle;\n    titleTextStyle: TextStyle;\n    titleTextMaxWidth: number;\n    underTitleTextStyle: TextStyle;\n}\n","import { InputField, ViewContainer } from '@egt/ui-lib';\nimport { Graphics, Container, TextStyle, Texture, Text, Sprite } from 'pixi.js';\n\nimport { Subject } from 'rxjs';\nimport Core from '@egt/core';\nimport { takeUntil } from 'rxjs/operators';\nimport KeyboardButtonNumeric, { NumericKeyboardButtonTextures } from '../buttons/KeyboardButtonNumeric';\nimport KeyboardActionButtonNumeric, {\n    NumericKeyboardActionButtonTextures as KeyboardActionButtonTexturesNumeric,\n} from '../buttons/KeyboardActionButtonNumeric';\n\nexport class KeyboardNumeric extends ViewContainer {\n    private keyboardContainer: Sprite;\n    //UI containers and graphics\n    private background: Graphics;\n    private topLine: Graphics;\n    private separatorLine: Graphics;\n    private shadowBackground: Sprite;\n    private buttonsContainer: Container;\n\n    //Keyboard buttons\n    private buttons: KeyboardButtonNumeric[][] = [];\n    public doneButton: KeyboardActionButtonNumeric;\n    private cancelButton: KeyboardActionButtonNumeric;\n\n    //Input field reference\n    private currentField: InputField;\n\n    //Balance display elements\n    private numericBalanceTextContainer: Container;\n    private numericBalanceText: Text;\n    private numericBalanceTextValue: Text;\n    private numericBalanceTextCurrency: Text;\n\n    //Bet display elements\n    private numericBetTextContainer: Container;\n    private numericBetText: Text;\n    private numericBetTextValue: Text;\n    private numericBetTextCurrency: Text;\n\n    //Configuration and layout\n    private componentConfiguration: any;\n    private wordSpacing: number = 6;\n\n    //Events\n    public readonly ON_DONE = new Subject<void>();\n    public readonly ON_CANCEL = new Subject<void>();\n    public readonly ON_INPUT = new Subject<string>();\n\n    constructor(componentConfiguration: any) {\n        super();\n        this.componentConfiguration = componentConfiguration;\n\n        this.createKeyboardContainer();\n        this.createBackground(this.componentConfiguration.autoPlayNumericContainerGraphicsConfig);\n        this.createNumericKeyboardActionButtons();\n        this.createKeyboardBalanceText();\n        this.createKeyboardBetText();\n        this.createShadowBackground();\n    }\n\n    private createKeyboardContainer(): void {\n        this.keyboardContainer = new Sprite();\n        this.addChild(this.keyboardContainer);\n    }\n\n    //UI creation methods\n\n    private createBackground(config: any): void {\n        this.background = new Graphics();\n        this.background.beginFill(0x1a1a1a);\n        this.background.drawRect(0, 0, config.width, config.height);\n        this.background.endFill();\n        // this.background.x = config.x;\n        // this.background.y = config.y;\n        this.background.interactive = true;\n        this.background.buttonMode = false;\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/slot-features/ui-lib/src/egt/ui/numeric-keyboard/KeyboardNumeric.ts:78:9\",(this.background),\"pointerdown\"]), this.background.on('pointerdown', (e) => {\n            e.stopPropagation();\n        }));\n        this.keyboardContainer.addChild(this.background);\n\n        this.topLine = new Graphics();\n        this.topLine.beginFill(0x444444);\n        this.topLine.drawRect(0, 0, config.width, config.lineHeight);\n        this.topLine.endFill();\n        this.topLine.x = config.topLineX;\n        this.topLine.y = config.topLineY;\n        this.keyboardContainer.addChild(this.topLine);\n\n        this.separatorLine = new Graphics();\n        this.separatorLine.beginFill(0x444444);\n        this.separatorLine.drawRect(0, 0, config.width, config.lineHeight);\n        this.separatorLine.endFill();\n        this.separatorLine.x = config.separatorLineX;\n        this.separatorLine.y = config.separatorLineY;\n        this.keyboardContainer.addChild(this.separatorLine);\n    }\n\n    private createShadowBackground(): void {\n        this.shadowBackground = new Sprite(\n            Core.assets.getTextureFromSpriteSheet('numericInput', 'shadowBackgraund.png'),\n        );\n        this.shadowBackground.visible = false;\n        this.shadowBackground.alpha = 1;\n        this.shadowBackground.name = 'shadowBackground';\n        this.keyboardContainer.addChildAt(this.shadowBackground, 0);\n    }\n\n    private createNumericKeyboardActionButtons(): void {\n        const saveBtnTextures = new KeyboardActionButtonTexturesNumeric(Core.assets.getAsset('svgButtonDone').texture);\n        const cancelBtnTextures = new KeyboardActionButtonTexturesNumeric(Core.assets.getAsset('svgClose').texture);\n\n        this.cancelButton = this.createActionBtn(\n            cancelBtnTextures,\n            this.componentConfiguration.doneBtn.textStyle,\n            this.componentConfiguration.cancelBtn.x,\n            this.componentConfiguration.cancelBtn.y,\n            undefined, // if we need label, we can pass it here\n        );\n        this.cancelButton.CLICK.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            if (this.currentField) {\n                this.currentField.restoreLastConfirmedValue();\n                this.currentField.setInactive();\n            }\n            this.ON_CANCEL.next();\n        });\n\n        this.doneButton = this.createActionBtn(\n            saveBtnTextures,\n            this.componentConfiguration.doneBtn.textStyle,\n            this.componentConfiguration.doneBtn.x,\n            this.componentConfiguration.doneBtn.y,\n            Core.translator.translate('DONE'),\n        );\n\n        this.doneButton.CLICK.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n            if (this.currentField) {\n                // this.currentField.confirmValue();\n                this.currentField.setInactive();\n                this.ON_DONE.next();\n            }\n        });\n\n        this.keyboardContainer.addChild(this.cancelButton);\n        this.keyboardContainer.addChild(this.doneButton);\n\n        this.createNumericKeyboardButtons();\n        this.positionNumericKeyboardButtons();\n    }\n\n    private createActionBtn(\n        textures: KeyboardActionButtonTexturesNumeric,\n        btnTextStyle: TextStyle,\n        x: number,\n        y: number,\n        label?: string,\n    ): KeyboardActionButtonNumeric {\n        const button = new KeyboardActionButtonNumeric(textures, btnTextStyle, label);\n        button.x = x;\n        button.y = y;\n        return button;\n    }\n\n    private createNumericKeyboardButtons(): void {\n        this.buttons.forEach((row) => row.forEach((btn) => btn.destroy()));\n        this.buttons = [];\n\n        if (!this.buttonsContainer) {\n            this.buttonsContainer = new ViewContainer();\n            this.keyboardContainer.addChild(this.buttonsContainer);\n        } else {\n            this.buttonsContainer.removeChildren();\n        }\n\n        const buttonValues: string[][] = this.componentConfiguration.numericKeyboardButtonValues;\n\n        for (let row = 0; row < buttonValues.length; row++) {\n            this.buttons[row] = [];\n            for (let col = 0; col < buttonValues[row].length; col++) {\n                const value = buttonValues[row][col];\n                const texture = this.getNumericKeyboardButtonTexture(value);\n\n                const showText = value !== '.' && value !== '<';\n                const textures = new NumericKeyboardButtonTextures(texture);\n                const button = new KeyboardButtonNumeric(\n                    textures,\n                    this.componentConfiguration.numericKeyboardButtonText.textStyle,\n                    showText ? value : '',\n                );\n                button.value = value;\n\n                this.buttons[row][col] = button;\n\n                this.buttonsContainer.addChild(button);\n\n                button.CLICK.pipe(takeUntil(this.DESTROY)).subscribe(() => {\n                    this.onNumericKeyboardButtonClick(value);\n                });\n            }\n        }\n    }\n\n    private positionNumericKeyboardButtons(): void {\n        const rowPositions = this.componentConfiguration.numericKeyboardRowPositions;\n        const colPositions = this.componentConfiguration.numericKeyboardBtnPositions;\n        const btnConfig = this.componentConfiguration.numericKeyboardButtonText;\n\n        const rowOffset = rowPositions.length - this.buttons.length;\n\n        const scale = this.componentConfiguration.numericKeyboardScale.scale;\n\n        for (let row = 0; row < this.buttons.length; row++) {\n            for (let col = 0; col < this.buttons[row].length; col++) {\n                const button = this.buttons[row][col];\n\n                button.pivot.set(button.width / 2, button.height / 2);\n\n                button.x = colPositions[col].get('x') + button.width / 2;\n                button.y = rowPositions[row + rowOffset].get('y') + button.height / 2;\n\n                button.width = btnConfig.width;\n                button.height = btnConfig.height;\n                button.scale.set(scale);\n            }\n        }\n    }\n\n    private createKeyboardBalanceText(): void {\n        const balanceConfig = this.componentConfiguration.balanceTextKeyboard;\n        const currency = this.componentConfiguration.currency;\n\n        this.numericBalanceTextContainer = new Container();\n        this.numericBalanceTextContainer.x = balanceConfig.x;\n        this.numericBalanceTextContainer.y = balanceConfig.y;\n\n        balanceConfig.textStyle.trim = true;\n        this.numericBalanceText = new Text(Core.translator.translate('BALANCE') + ':', balanceConfig.textStyle);\n        this.numericBalanceText.resolution = 2;\n        this.numericBalanceText.anchor.set(0, 1);\n        this.numericBalanceTextContainer.addChild(this.numericBalanceText);\n\n        balanceConfig.valueStyle.trim = true;\n        this.numericBalanceTextValue = new Text('0.00', balanceConfig.valueStyle);\n        this.numericBalanceTextValue.anchor.set(0, 1);\n        this.numericBalanceTextValue.resolution = 2;\n        this.numericBalanceTextValue.x = this.numericBalanceText.x + this.numericBalanceText.width + this.wordSpacing;\n        this.numericBalanceTextContainer.addChild(this.numericBalanceTextValue);\n\n        balanceConfig.currencyStyle.trim = true;\n        this.numericBalanceTextCurrency = new Text(currency, balanceConfig.currencyStyle);\n        this.numericBalanceTextCurrency.anchor.set(0, 1);\n        this.numericBalanceTextCurrency.resolution = 2;\n        this.numericBalanceTextCurrency.x =\n            this.numericBalanceTextValue.x + this.numericBalanceTextValue.width + this.wordSpacing;\n        this.numericBalanceTextContainer.addChild(this.numericBalanceTextCurrency);\n\n        this.keyboardContainer.addChild(this.numericBalanceTextContainer);\n    }\n\n    private createKeyboardBetText(): void {\n        const betConfig = this.componentConfiguration.betTextKeyboard;\n        const currency = this.componentConfiguration.currency;\n\n        this.numericBetTextContainer = new Container();\n        this.numericBetTextContainer.x = betConfig.x;\n        this.numericBetTextContainer.y = betConfig.y;\n\n        betConfig.textStyle.trim = true;\n        this.numericBetText = new Text(Core.translator.translate('BET') + ':', betConfig.textStyle);\n        this.numericBetText.resolution = 2;\n        this.numericBetText.anchor.set(0, 1);\n        this.numericBetTextContainer.addChild(this.numericBetText);\n\n        betConfig.valueStyle.trim = true;\n        this.numericBetTextValue = new Text('0.00', betConfig.valueStyle);\n        this.numericBetTextValue.resolution = 2;\n        this.numericBetTextValue.anchor.set(0, 1);\n        this.numericBetTextValue.x = this.numericBetText.x + this.numericBetText.width + this.wordSpacing;\n        this.numericBetTextContainer.addChild(this.numericBetTextValue);\n\n        betConfig.currencyStyle.trim = true;\n        this.numericBetTextCurrency = new Text(currency, betConfig.currencyStyle);\n        this.numericBetTextCurrency.resolution = 2;\n        this.numericBetTextCurrency.anchor.set(0, 1);\n        this.numericBetTextCurrency.x = this.numericBetTextValue.x + this.numericBetTextValue.width + this.wordSpacing;\n        this.numericBetTextContainer.addChild(this.numericBetTextCurrency);\n\n        this.keyboardContainer.addChild(this.numericBetTextContainer);\n    }\n\n    //UI update and layout methods\n\n    public showShadowBackground(): void {\n        if (!this.shadowBackground) return;\n        if (Core.ORIENTATION.value.isPortrait) {\n            const shadowConfig = this.componentConfiguration.numericKeyboardShadowBackground;\n            this.shadowBackground.visible = true;\n            this.shadowBackground.x = shadowConfig.x;\n            this.shadowBackground.y = shadowConfig.y;\n            this.shadowBackground.width = shadowConfig.width;\n            this.shadowBackground.height = shadowConfig.height;\n            this.keyboardContainer.setChildIndex(this.shadowBackground, 0);\n            this.shadowBackground.interactive = true;\n        } else {\n            this.shadowBackground.visible = false;\n        }\n    }\n\n    public hideShadowBackground(): void {\n        if (this.shadowBackground) {\n            this.shadowBackground.visible = false;\n        }\n    }\n\n    public reposition(): void {\n        this.positionNumericKeyboardButtons();\n\n        const config = this.componentConfiguration.autoPlayNumericContainerGraphicsConfig;\n\n        // Background\n        if (this.background) {\n            this.background.x = config.x;\n            this.background.y = config.y;\n            this.background.width = Core.ORIENTATION.value.isPortrait ? Core.display.stage.width : config.width;\n            this.background.height = config.height;\n        }\n\n        // Top line\n        if (this.topLine) {\n            this.topLine.x = config.topLineX;\n            this.topLine.y = config.topLineY;\n            this.topLine.width = Core.ORIENTATION.value.isPortrait ? Core.display.stage.width : config.width;\n            this.topLine.height = config.lineHeight;\n        }\n\n        // Separator line\n        if (this.separatorLine) {\n            this.separatorLine.x = config.separatorLineX;\n            this.separatorLine.y = config.separatorLineY;\n            this.separatorLine.width = Core.ORIENTATION.value.isPortrait ? Core.display.stage.width : config.width;\n            this.separatorLine.height = config.lineHeight;\n        }\n\n        // Cancel and Done\n        if (this.cancelButton) {\n            this.cancelButton.x = this.componentConfiguration.cancelBtn.x;\n            this.cancelButton.y = this.componentConfiguration.cancelBtn.y;\n            this.cancelButton.scale.set(this.componentConfiguration.cancelBtn.scale);\n        }\n        if (this.doneButton) {\n            this.doneButton.x = this.componentConfiguration.doneBtn.x;\n            this.doneButton.y = this.componentConfiguration.doneBtn.y;\n            this.doneButton.scale.set(this.componentConfiguration.doneBtn.scale);\n        }\n\n        // Balance and Bet\n        if (this.numericBalanceTextContainer) {\n            this.numericBalanceTextContainer.x = this.componentConfiguration.balanceTextKeyboard.x;\n            this.numericBalanceTextContainer.y = this.componentConfiguration.balanceTextKeyboard.y;\n        }\n        if (this.numericBetTextContainer) {\n            this.numericBetTextContainer.x = this.componentConfiguration.betTextKeyboard.x;\n            this.numericBetTextContainer.y = this.componentConfiguration.betTextKeyboard.y;\n        }\n\n        // Keyboard buttons container\n        if (this.buttonsContainer) {\n            const pos = this.componentConfiguration.numericKeyboardButtonsContainerPosition;\n            this.buttonsContainer.x = pos.x;\n            this.buttonsContainer.y = pos.y;\n        }\n\n        this.keyboardContainer.x =\n            Core.LEFT_HAND_MODE.value && Core.ORIENTATION.value.isLandscape\n                ? this.componentConfiguration.numericKeyboardContainerPosition.leftHandX\n                : this.componentConfiguration.numericKeyboardContainerPosition.x;\n        this.keyboardContainer.y = this.componentConfiguration.numericKeyboardContainerPosition.y;\n\n        this.showShadowBackground();\n    }\n\n    private fitKeyboardBalanceAndBetInBounds(): void {\n        const maxWidth = Math.abs(this.numericBetTextContainer.x - this.numericBalanceTextContainer.x);\n\n        const balanceWidth =\n            this.numericBalanceText.width +\n            this.numericBalanceTextValue.width +\n            this.numericBalanceTextCurrency.width +\n            2 * this.wordSpacing;\n\n        const betWidth =\n            this.numericBetText.width +\n            this.numericBetTextValue.width +\n            this.numericBetTextCurrency.width +\n            2 * this.wordSpacing;\n\n        const actualWidth = balanceWidth + this.wordSpacing + betWidth;\n\n        this.numericBalanceTextContainer.scale.set(1);\n        this.numericBetTextContainer.scale.set(1);\n\n        if (actualWidth > maxWidth) {\n            const scaleFactor = maxWidth / actualWidth;\n            this.numericBalanceTextContainer.scale.set(scaleFactor);\n            this.numericBetTextContainer.scale.set(scaleFactor);\n        }\n    }\n\n    private positionKeyboardBetBalance(): void {\n        if (this.numericBalanceTextCurrency && this.numericBalanceTextValue) {\n            this.numericBalanceTextCurrency.x =\n                this.numericBalanceTextValue.x + this.numericBalanceTextValue.width + this.wordSpacing;\n        }\n        if (this.numericBetTextCurrency && this.numericBetTextValue) {\n            this.numericBetTextCurrency.x =\n                this.numericBetTextValue.x + this.numericBetTextValue.width + this.wordSpacing;\n        }\n        if (\n            this.numericBetTextContainer &&\n            this.numericBetText &&\n            this.numericBetTextValue &&\n            this.numericBetTextCurrency\n        ) {\n            this.numericBetTextContainer.pivot.set(\n                this.numericBetText.width +\n                    this.numericBetTextValue.width +\n                    this.numericBetTextCurrency.width +\n                    2 * this.wordSpacing,\n                0,\n            );\n        }\n    }\n\n    private getNumericKeyboardButtonTexture(value: string): Texture {\n        switch (value) {\n            case '.':\n                return Core.assets.getAsset('svgButtonDot').texture;\n            case '<':\n                return Core.assets.getAsset('svgButtonClear').texture;\n            default:\n                return Core.assets.getAsset('svgButtonStandard').texture;\n        }\n    }\n\n    private onNumericKeyboardButtonClick(value: string): void {\n        if (!this.currentField) return;\n\n        if (value === '<') {\n            const current = this.currentField.getValue();\n            const newValue = current.slice(0, -1);\n\n            this.currentField.setValue(newValue);\n        } else {\n            const current = this.currentField.getValue();\n            this.currentField.setValue(current + value);\n        }\n    }\n\n    public setCurrentField(field: InputField) {\n        this.currentField = field;\n    }\n\n    //Public update methods for external use\n\n    public updateKeyboardBalanceValue(value: string): void {\n        if (this.numericBalanceTextValue) {\n            this.numericBalanceTextValue.text = value;\n            this.fitKeyboardBalanceAndBetInBounds();\n            this.positionKeyboardBetBalance();\n        }\n    }\n\n    public updateKeyboardBetValue(value: string): void {\n        if (this.numericBetTextValue) {\n            this.numericBetTextValue.text = value;\n            this.fitKeyboardBalanceAndBetInBounds();\n            this.positionKeyboardBetBalance();\n        }\n    }\n\n    public updateCurrency(currency: string): void {\n        if (this.numericBalanceTextCurrency) {\n            this.numericBalanceTextCurrency.text = currency;\n        }\n        if (this.numericBetTextCurrency) {\n            this.numericBetTextCurrency.text = currency;\n        }\n    }\n}\n","import Core, { Money } from '@egt/core';\nimport { BitmapFont, BitmapText, Graphics, TextStyle } from 'pixi.js';\nimport { takeUntil } from 'rxjs/operators';\nimport ViewContainer from '../ViewContainer';\nimport MoneyTextConfig from './MoneyTextConfig';\nimport TextAlign from './TextAlign';\n\nexport default class AnimatedMoneyText extends ViewContainer {\n    public moneyValues: Money;\n\n    protected moneyTextParts: any = {};\n    protected number: BitmapText;\n    protected exponent: BitmapText;\n    protected bounds: Graphics;\n\n    protected _moneyText: string;\n    protected _currency: BitmapText;\n    private _bmpF: BitmapFont;\n\n    private isCredits: boolean;\n\n    constructor(\n        protected id: string,\n        protected _config: MoneyTextConfig,\n        protected _money: number,\n        protected _style?: any,\n    ) {\n        super();\n\n        this.moneyValues = new Money(_money);\n\n        this.moneyValues.MONEY_UPDATED.pipe(takeUntil(this.DESTROY)).subscribe(this.onMoneyUpdated.bind(this));\n\n        this.bounds = new Graphics();\n        this.bounds.beginFill(0xff0000);\n        this.bounds.alpha = this._config.debug ? 0.3 : 0;\n        this.bounds.drawRect(0, 0, this._config.bounds.width, this._config.bounds.height);\n        this.bounds.endFill();\n\n        this.addChild(this.bounds);\n        const resolution = 2;\n        this._bmpF = BitmapFont.from(\n            this.id,\n            new TextStyle({\n                fontFamily: 'Arial',\n                fontWeight: 'bold',\n                fill: this._style.fill,\n                fontSize: this._style.fontSize * resolution,\n            }),\n            {\n                chars: [\n                    [' ', '.'],\n                    ['0', '9'],\n                    ['A', 'Z'],\n                ],\n            },\n        );\n\n        this.createNumber();\n        this.createExponent();\n        this.createCurrency();\n    }\n\n    get moneyText(): string {\n        return this._moneyText;\n    }\n\n    get config(): MoneyTextConfig {\n        return this._config;\n    }\n\n    set config(value: MoneyTextConfig) {\n        this._config = value;\n        this.setText();\n    }\n\n    get money(): number {\n        return this._money;\n    }\n\n    set money(value: number) {\n        this.moneyValues.amountMoney = value;\n        this._money = value;\n        this.setText();\n    }\n\n    get denomination(): number {\n        return this._config.denomination;\n    }\n\n    set denomination(value: number) {\n        this._config.denomination = value;\n        // this.setText();\n    }\n\n    get currency(): string {\n        return this._config.currency;\n    }\n\n    set currency(value: string) {\n        this._config.currency = value;\n        this.setText();\n    }\n\n    get showCurrency(): boolean {\n        return this._config.showCurrency;\n    }\n\n    set showCurrency(value: boolean) {\n        this._config.showCurrency = value;\n        this.setText();\n    }\n\n    get showCredits(): boolean {\n        return this._config.showCredits;\n    }\n\n    set showCredits(value: boolean) {\n        this._config.showCredits = value;\n        this.setText();\n    }\n\n    get spaceBetweenMoneyAndCents(): number {\n        return this._config.spaceBetweenMoneyAndCents;\n    }\n\n    set spaceBetweenMoneyAndCents(value: number) {\n        this._config.spaceBetweenMoneyAndCents = value;\n        this.setText();\n    }\n\n    get spaceBetweenMoneyAndCurrency(): number {\n        return this._config.spaceBetweenMoneyAndCurrency;\n    }\n\n    set spaceBetweenMoneyAndCurrency(value: number) {\n        this._config.spaceBetweenMoneyAndCurrency = value;\n        this.setText();\n    }\n\n    get centerAlignOnlyMoney(): boolean {\n        return this._config.centerAlignOnlyMoney;\n    }\n\n    set centerAlignOnlyMoney(value: boolean) {\n        this._config.centerAlignOnlyMoney = value;\n        this.setText();\n    }\n\n    /**\n     * Sets denomination without changing the text value\n     */\n    public setDenomination(denomination: number): void {\n        this._config.denomination = denomination;\n    }\n\n    public destroy(): void {\n        if (this._style) {\n            this._style = null;\n        }\n        this.number.destroy();\n        this.exponent.destroy();\n\n        BitmapFont.uninstall(this.id);\n        this._bmpF.destroy();\n        this.bounds.destroy();\n\n        // @ts-ignore\n        this.number = null;\n        // @ts-ignore\n        this.exponent = null;\n        // @ts-ignore\n        this._bmpF = null;\n        // @ts-ignore\n        this.bounds = null;\n\n        // @ts-ignore\n        this._config = null;\n        super.destroy.apply(this, arguments);\n    }\n\n    /**\n     * Sets a display text based on the money and the configuration.\n     */\n    protected setText(): void {\n        // 1. Sets the money text based on the money and the money config.\n        this.setMoneyText();\n\n        // 2. Set all inner text fields based on the money text parts.\n        this.number.text = this.moneyTextParts.number;\n\n        if (this.moneyTextParts.exponent) {\n            this.exponent.text = '.' + this.moneyTextParts.exponent;\n        }\n\n        if (this.moneyTextParts.currency) {\n            this._currency.text = this.moneyTextParts.currency;\n        }\n\n        // 3. Ensure texts fit to bounds.\n        this.fitToBounds();\n\n        // 4. Align and position.\n        this.positionTexts();\n    }\n\n    /**\n     * Resets the text in the money field to empty string.\n     */\n    protected resetText(): void {\n        this.number.fontSize = this._style.fontSize;\n        this.exponent.fontSize = this._style.fontSize;\n        this._currency.fontSize = this.number.fontSize / 2;\n    }\n\n    /**\n     * Creates a formatted money text based on the money property.\n     * Separate parts are stored in _moneyTextParts.\n     *\n     * E.g.\n     * 107894 money with currency \"EUR\" will be formatted to: \"107 894.00 EUR\"\n     */\n    protected setMoneyText(): void {\n        const money: number = this.money || 0;\n        let formatted: string = money.toString();\n        // Convert credits to money\n        if (!this._config.showCredits) {\n            // formatted = (money / this._config.units).toFixed(2).toString();\n            // if selected mode is currency or we do not change value when mode is changed\n            if (!Core.MONEY_MODE_IN_CREDITS.value || !this._config.useMoneyMode) {\n                formatted = this.moneyValues.amountMoney.toFixed(2).toString();\n                this.isCredits = false;\n            } else {\n                formatted = this.moneyValues.amountCredits.toString();\n                this.isCredits = true;\n            }\n        } else {\n            // credits are rounded down\n            // if selected mode is credit or we do not change value when mode is changed\n            if (!Core.MONEY_MODE_IN_CREDITS.value || !this._config.useMoneyMode) {\n                formatted = this.moneyValues.amountCredits.toString();\n                this.isCredits = true;\n            } else {\n                formatted = this.moneyValues.amountMoney.toFixed(2).toString();\n                this.isCredits = false;\n            }\n            // formatted = Math.floor(money / this._config.denomination).toString();\n        }\n        // Split floating point numbers to avoid formatting of the numbers after the floating point.\n        const splitted: string[] = formatted.split('.');\n        formatted = splitted[0];\n        let exponent = '';\n        this.moneyTextParts.exponent = '';\n        this.exponent.text = '';\n        if (splitted[1]) {\n            exponent = this._config.showRoundedValue ? '00' : splitted[1];\n            this.moneyTextParts.exponent = exponent;\n        }\n\n        // Split value into chunks of 3 characters.\n        const matches: string[] | null = formatted.match(/(\\d+?)(?=(\\d{3})+(?!\\d)|$)/g);\n        if (matches) {\n            formatted = matches.join(' ');\n        }\n        this.moneyTextParts.number = formatted;\n        if (exponent) {\n            formatted += '.' + exponent;\n        }\n\n        if (!this.isCredits && this._config.showCurrency && this._config.currency) {\n            formatted += ' ' + this._config.currency;\n            this.moneyTextParts.currency = this._config.currency;\n            if (!this.find('currency')) {\n                this.createCurrency();\n            }\n        } else {\n            this.removeChild(this._currency);\n        }\n\n        this._moneyText = formatted;\n    }\n\n    /**\n     * Recursively change fontSize to enforce the text to fit to the bounds.\n     */\n    protected fitToBounds(): void {\n        if (!this._config.shouldFitInBounds) {\n            return;\n        }\n\n        this.resetText();\n\n        const totalWidth: number = this.getTotalWidth();\n        const fontSize: number = this.number.fontSize;\n\n        if (totalWidth > this._config.bounds.width && fontSize > this._config.minFontSize) {\n            const newFontSize = Math.floor(fontSize * (this._config.bounds.width / totalWidth));\n            this._calculateNewBitmapFontSize(this.number, fontSize, newFontSize);\n            this._calculateNewBitmapFontSize(this.exponent, fontSize, newFontSize);\n            this._calculateNewBitmapFontSize(this._currency, fontSize, newFontSize);\n        }\n    }\n\n    protected _calculateNewBitmapFontSize(text: BitmapText, baseFontSize: number, newFontSize: number): void {\n        if (text.fontSize === baseFontSize) {\n            text.fontSize = newFontSize;\n        } else {\n            const fontSize: number = text.fontSize;\n            text.fontSize = fontSize - Math.round((baseFontSize - newFontSize) / (baseFontSize / fontSize));\n        }\n    }\n\n    /**\n     * Position and align all inner text fields horizontally and vertically.\n     */\n    protected positionTexts(): void {\n        // Align number horizontally.\n        if (this._config.align === TextAlign.LEFT) {\n            this.number.x = 0;\n        } else if (this._config.align === TextAlign.CENTER) {\n            let newX: number = this.getHorizontalFreeSpace() / 2;\n            const newXCenterAlignOnlyMoney: number = (this._config.bounds.width - this.number.textWidth) / 2;\n            const newXCenterAlignOnlyMoneyWillFit: boolean =\n                this._config.bounds.width >= this.getTotalWidth() + newXCenterAlignOnlyMoney;\n            if (this._config.centerAlignOnlyMoney && newXCenterAlignOnlyMoneyWillFit) {\n                newX = newXCenterAlignOnlyMoney;\n            }\n            this.number.x = newX;\n        } else if (this._config.align === TextAlign.RIGHT) {\n            this.number.x = this.getHorizontalFreeSpace();\n        }\n\n        // Align number vertically.\n        this.number.y = Math.floor((this._config.bounds.height - this.number.height) / 2);\n\n        // Align exponent vertically and horizontally based on the number text field.\n        if (this.moneyTextParts.exponent) {\n            this.exponent.x = this.number.x + this.number.textWidth + this._config.spaceBetweenMoneyAndCents;\n            this.exponent.y = this.number.y;\n        }\n\n        // Align currency vertically and horizontally based on the number text field.\n        if (!this.isCredits && this.moneyTextParts.currency) {\n            this._currency.x =\n                this.number.x +\n                this.exponent.textWidth +\n                this.number.textWidth +\n                this._config.spaceBetweenMoneyAndCents +\n                this._config.spaceBetweenMoneyAndCurrency;\n            this._currency.y = Math.round(this.number.y + this.number.fontSize / 2 - 1);\n        }\n    }\n\n    /**\n     * Returns the total width used by all text fields.\n     */\n    protected getTotalWidth(): number {\n        let width: number = this.number.textWidth;\n\n        if (this.moneyTextParts.exponent) {\n            width += this.exponent.textWidth + this._config.spaceBetweenMoneyAndCents;\n        }\n        if (!this.isCredits && this.moneyTextParts.currency) {\n            width += this._currency.width + this._config.spaceBetweenMoneyAndCurrency;\n        }\n\n        return width;\n    }\n\n    /**\n     * Returns the horizontal free space.\n     */\n    protected getHorizontalFreeSpace(): number {\n        let freeSpace: number = this._config.bounds.width - this.number.textWidth;\n\n        if (this.moneyTextParts.exponent) {\n            freeSpace -= this.exponent.textWidth;\n            freeSpace -= this._config.spaceBetweenMoneyAndCents;\n        }\n        if (!this.isCredits && this.moneyTextParts.currency) {\n            freeSpace -= this._currency.width;\n            freeSpace -= this._config.spaceBetweenMoneyAndCurrency;\n        }\n\n        return freeSpace;\n    }\n\n    protected createNumber(): void {\n        this.number = new BitmapText('', {\n            fontName: this.id,\n            align: 'center',\n        });\n\n        this.addChild(this.number);\n    }\n\n    protected createExponent(): void {\n        this.exponent = new BitmapText('', {\n            fontName: this.id,\n            align: 'center',\n        });\n        this.addChild(this.exponent);\n    }\n\n    protected createCurrency(): void {\n        this._currency = new BitmapText('', {\n            fontName: this.id,\n            align: 'center',\n        });\n        this._currency.fontSize = this.number.fontSize / 2;\n        this.addChild(this._currency);\n        this._currency.name = 'currency';\n    }\n\n    private onMoneyUpdated(): void {\n        this.setText();\n    }\n}\n","import { IBitmapTextStyle } from 'pixi.js';\nimport TextConfig from './TextConfig';\n\nexport default class AnimatedMoneyTextConfigV2 extends TextConfig {\n    private _bitMapTextStyle: IBitmapTextStyle = {\n        fontName: 'jackpotsCountersBitmapFont',\n        align: 'center',\n        fontSize: 24,\n    } as IBitmapTextStyle;\n\n    protected _moneyFontSize: number = 24;\n    protected _centsFontSize: number = 24;\n    protected _currencyFontSize: number = 12;\n    protected _spaceBetweenMoneyAndCurrency: number = 8;\n    protected _shouldHideWhenMoneyValueIsZero: boolean = false;\n    protected _showCurrency: boolean = true;\n    protected _units: number = 100;\n    protected _showRoundedValue: boolean = false;\n\n    /**\n     * If true change mode affect this moneytext field and value is changed when\n     * MONEY_MODE_IN_CURRENCY mode is chganged\n     * If false allways use _showCredits setting and do not change on mode change\n     */\n    protected _alwaysInCurrency: boolean = false;\n\n    /**\n     * The currency symbol to put at the end of the string.\n     */\n    protected _currency: string = '';\n\n    /**\n     * The real currency is calculated based on the money and denomination values.\n     * If denomination is 2 and money is 1000 the real currency value will be 500.\n     */\n    protected _denomination: number = 1;\n\n    /**\n     * Should the center alignement be based on the money only or both the money and currency.\n     */\n    protected _centerAlignOnlyMoney: boolean = false;\n\n    get denomination(): number {\n        return this._denomination;\n    }\n\n    set denomination(value: number) {\n        this._denomination = value;\n    }\n\n    get currency(): string {\n        return this._currency;\n    }\n\n    set currency(value: string) {\n        this._currency = value;\n    }\n\n    get showCurrency(): boolean {\n        return this._showCurrency;\n    }\n\n    set showCurrency(value: boolean) {\n        this._showCurrency = value;\n    }\n\n    get alwaysInCurrency(): boolean {\n        return this._alwaysInCurrency;\n    }\n\n    set alwaysInCurrency(value: boolean) {\n        this._alwaysInCurrency = value;\n    }\n\n    get moneyFontSize(): number {\n        return this._moneyFontSize;\n    }\n\n    set moneyFontSize(value: number) {\n        this._moneyFontSize = value;\n    }\n\n    get centsFontSize(): number {\n        return this._centsFontSize;\n    }\n\n    set centsFontSize(value: number) {\n        this._centsFontSize = value;\n    }\n\n    get currencyFontSize(): number {\n        return this._currencyFontSize;\n    }\n\n    set currencyFontSize(value: number) {\n        this._currencyFontSize = value;\n    }\n\n    get spaceBetweenMoneyAndCurrency(): number {\n        return this._spaceBetweenMoneyAndCurrency;\n    }\n\n    set spaceBetweenMoneyAndCurrency(value: number) {\n        this._spaceBetweenMoneyAndCurrency = value;\n    }\n\n    get centerAlignOnlyMoney(): boolean {\n        return this._centerAlignOnlyMoney;\n    }\n\n    set centerAlignOnlyMoney(value: boolean) {\n        this._centerAlignOnlyMoney = value;\n    }\n\n    get shouldHideWhenMoneyValueIsZero(): boolean {\n        return this._shouldHideWhenMoneyValueIsZero;\n    }\n\n    set shouldHideWhenMoneyValueIsZero(value: boolean) {\n        this._shouldHideWhenMoneyValueIsZero = value;\n    }\n\n    get units(): number {\n        return this._units;\n    }\n\n    set units(value: number) {\n        this._units = value;\n    }\n\n    get showRoundedValue(): boolean {\n        return this._showRoundedValue;\n    }\n\n    set showRoundedValue(value: boolean) {\n        this._showRoundedValue = value;\n    }\n\n    get bitMapTextStyle(): IBitmapTextStyle {\n        return this._bitMapTextStyle;\n    }\n    set bitMapTextStyle(value: IBitmapTextStyle) {\n        this._bitMapTextStyle = value;\n    }\n}\n","import Core, { Money } from '@egt/core';\nimport { BitmapFont, BitmapText, Container, Graphics, TextStyle } from 'pixi.js';\nimport { takeUntil } from 'rxjs/operators';\nimport ViewContainer from '../ViewContainer';\nimport AnimatedMoneyTextConfigV2 from './AnimatedMoneyTextConfigV2';\nimport TextAlign from './TextAlign';\nimport Text from '../texts/Text';\nimport TextConfig from './TextConfig';\nimport VerticalTextAlign from './VerticalTextAlign';\nexport default class AnimatedMoneyTextV2 extends ViewContainer {\n    public moneyValue: Money;\n\n    protected moneyTextValue: BitmapText;\n    protected bounds: Graphics;\n    protected textContainer: Container;\n    protected currency: Text;\n    protected bmpF: BitmapFont;\n\n    protected containerYOffset: number = 0;\n    protected textOriginalHeight: number = 0;\n\n    constructor(\n        protected id: string,\n        protected config: AnimatedMoneyTextConfigV2,\n        protected _money: number,\n        protected _style: TextStyle,\n    ) {\n        super();\n\n        this.moneyValue = new Money(_money);\n\n        this.moneyValue.MONEY_UPDATED.pipe(takeUntil(this.DESTROY)).subscribe(this.onMoneyUpdated.bind(this));\n\n        this.textContainer = new Container();\n        this.addChild(this.textContainer);\n\n        this.bounds = new Graphics();\n        this.bounds.beginFill(0xff0000);\n        this.bounds.drawRect(0, 0, this.config.bounds.width, this.config.bounds.height);\n        this.bounds.endFill();\n        this.bounds.alpha = 0;\n        this.bounds.y = this.config.bounds.y;\n        this.addChild(this.bounds);\n\n        this.createNumber();\n\n        this.setText();\n    }\n\n    get money(): number {\n        return this._money;\n    }\n\n    set money(value: number) {\n        if (value !== undefined && value !== null) {\n            this.moneyValue.amountMoney = value;\n            this._money = value;\n            this.setText();\n        }\n    }\n\n    /**\n     * Sets denomination without changing the text value\n     */\n    protected setDenomination(denomination: number): void {\n        this.config.denomination = denomination;\n    }\n\n    public updateBounds(x: number, y: number, width: number, height: number, style: TextStyle): void {\n        this.bounds.width = width;\n        this.bounds.height = height;\n        this.bounds.x = x;\n        this.bounds.y = y;\n        this._style = style;\n        this.setText();\n    }\n\n    public destroy(): void {\n        // First cleanup the DESTROY subject from ViewContainer\n        super.destroy.apply(this, arguments);\n\n        // Then safely cleanup all child components\n        if (this.moneyTextValue) {\n            this.moneyTextValue.destroy({ children: true });\n            // @ts-ignore\n            this.moneyTextValue = null;\n        }\n\n        if (this.currency) {\n            this.currency.destroy();\n            // @ts-ignore\n            this.currency = null;\n        }\n\n        if (this.bounds) {\n            this.bounds.destroy();\n            // @ts-ignore\n            this.bounds = null;\n        }\n\n        if (this.textContainer) {\n            this.textContainer.destroy({ children: true });\n            // @ts-ignore\n            this.textContainer = null;\n        }\n\n        // Cleanup bitmap font only if it exists and hasn't been uninstalled\n        if (this.bmpF && BitmapFont.available[this.id]) {\n            BitmapFont.uninstall(this.id);\n            this.bmpF.destroy();\n\n            // @ts-ignore\n            this.bmpF = null;\n        }\n\n        if (this._style) {\n            // @ts-ignore\n            this._style = null;\n        }\n\n        // @ts-ignore\n        this.config = null;\n    }\n\n    /**\n     * Sets a display text based on the money and the configuration.\n     */\n    protected setText(): void {\n        // 1. Sets the money text based on the money and the money config.\n        this.setMoneyText();\n\n        // 2. Align and position.\n        this.positionTexts();\n\n        // 3. Ensure texts fit to bounds.\n        this.fitToBounds();\n\n        // 3. Position text container\n        this.positionTextContainer();\n    }\n\n    protected positionTextContainer(): void {\n        if (this.config.align === TextAlign.LEFT) {\n            this.textContainer.x = 0;\n        } else if (this.config.align === TextAlign.CENTER) {\n            this.textContainer.x = this.bounds.width / 2 - this.textContainer.width / 2;\n        } else if (this.config.align === TextAlign.RIGHT) {\n            this.textContainer.x = this.bounds.width - this.textContainer.width;\n        }\n        this.textContainer.y = this.containerYOffset;\n    }\n\n    /**\n     * Creates a formatted money text based on the money property.\n     * Separate parts are stored in _moneyTextParts.\n     *\n     * E.g.\n     * 107894 money with currency \"EUR\" will be formatted to: \"107 894.00 EUR\"\n     */\n    protected setMoneyText(): void {\n        if (this.config.alwaysInCurrency) {\n            this.moneyTextValue.text = this.moneyValue.stringMoney;\n            if (this.config.showCurrency) {\n                this.currency;\n            }\n        } else {\n            if (Core.MONEY_MODE_IN_CREDITS.value) {\n                this.moneyTextValue.text = this.moneyValue.stringCredits;\n            } else {\n                this.moneyTextValue.text = this.moneyValue.stringMoney;\n            }\n        }\n    }\n\n    /**\n     * Recursively change fontSize to enforce the text to fit to the bounds.\n     */\n    protected fitToBounds(): void {\n        if (!this.config.shouldFitInBounds) {\n            return;\n        }\n\n        let scaleFactor: number = 1;\n        let scaleFactorWidth: number = 1;\n        let scaleFactorHeight: number = 1;\n        this.textContainer.scale.set(1);\n        if (this.moneyTextValue.width > this.bounds.width) {\n            scaleFactorWidth = this.bounds.width / this.moneyTextValue.width;\n        }\n        if (this.moneyTextValue.height > this.bounds.height) {\n            scaleFactorHeight = this.bounds.height / this.moneyTextValue.height;\n        }\n        scaleFactor = scaleFactorWidth > scaleFactorHeight ? scaleFactorHeight : scaleFactorWidth;\n        this.textContainer.scale.set(scaleFactor);\n        // For bottom-aligned text with (0,1) anchor, simply set to bounds height\n        this.containerYOffset = this.bounds.height + this.bounds.y;\n    }\n\n    /**\n     * Position and align all inner text fields horizontally and vertically.\n     */\n    protected positionTexts(): void {\n        // Align currency vertically and horizontally based on the number text field.\n        if (this.config.showCurrency) {\n            this.currency.x =\n                this.moneyTextValue.x +\n                // this.exponent.textWidth +\n                this.moneyTextValue.textWidth +\n                this.config.spaceBetweenMoneyAndCurrency;\n            // this.currency.y = Math.round(this.moneyTextValue.y + this.moneyTextValue.fontSize / 2 - 1);\n            this.currency.y = this.moneyTextValue.y;\n        }\n    }\n\n    /**\n     * Returns the total width used by all text fields.\n     */\n    protected getTotalWidth(): number {\n        let width: number = this.moneyTextValue.textWidth;\n\n        if (this.config.showCurrency && !Core.MONEY_MODE_IN_CREDITS.value) {\n            width += this.currency.width + this.config.spaceBetweenMoneyAndCurrency;\n        }\n\n        return width;\n    }\n\n    /**\n     * Returns the horizontal free space.\n     */\n    protected getHorizontalFreeSpace(): number {\n        let freeSpace: number = this.config.bounds.width - this.moneyTextValue.textWidth;\n        if (this.config.showCurrency && !Core.MONEY_MODE_IN_CREDITS.value) {\n            freeSpace -= this.currency.width;\n            freeSpace -= this.config.spaceBetweenMoneyAndCurrency;\n        }\n\n        return freeSpace;\n    }\n\n    protected createNumber(): void {\n        this.moneyTextValue = new BitmapText('', this.config.bitMapTextStyle);\n        this.moneyTextValue.anchor.set(0, 1);\n        this.textContainer.addChild(this.moneyTextValue);\n        if (this.config.showCurrency) {\n            this.createCurrency();\n        }\n    }\n\n    protected createCurrency(): void {\n        const currencyConfig: TextConfig = new TextConfig();\n        currencyConfig.align = TextAlign.LEFT;\n        currencyConfig.verticalAlign = VerticalTextAlign.ALIGN_BASELINE;\n        this.currency = new Text(currencyConfig, this.config.currency, {\n            fontSize: Number(this._style.fontSize) * 2,\n            fill: this._style.fill,\n            fontFamily: this._style.fontFamily,\n        });\n        this.textContainer.addChild(this.currency);\n        this.currency.name = 'currency';\n\n        this.currency.text = this.config.currency;\n    }\n\n    private onMoneyUpdated(): void {\n        this.setText();\n    }\n}\n","import { Timers } from '@egt/core';\nimport { gsap } from 'gsap';\nimport { BitmapText, Graphics, TextMetrics, TextStyle } from 'pixi.js';\nimport BangUpCurrencyText from './BangUpCurrencyText';\nimport MoneyText from './MoneyText';\nimport MoneyTextConfig from './MoneyTextConfig';\n\nexport enum BangUpStages {\n    STAGE_ONE = 1,\n    STAGE_TWO = 2,\n    STAGE_THREE = 3,\n    LAST_STAGE = STAGE_THREE,\n}\n\nexport default class BangUpAnimatedCurrencyText extends BangUpCurrencyText {\n    protected minTickInterval: number = 100;\n    protected maxTickInterval: number = 1000;\n\n    private stage: BangUpStages;\n    private stageOneTimeBeforeEnd: number = 1000;\n    private stageTwoTimeBeforeEnd: number = 750;\n    private stageThreeTimeBeforeEnd: number = 500;\n\n    private stageTwoValueBeforeEnd: number = 5;\n    private stageThreeValueBeforeEnd: number = 1;\n    private stagingNeeded: boolean = true;\n\n    private easing: string = 'none';\n\n    private secondArrayDigits: BitmapText[];\n    private digitsMask: Graphics;\n\n    private digitTween: any[] = [];\n    private secondDigitTween: any[] = [];\n\n    private lastTweenedElementIndex: number;\n    private unUsedDigitsWhenBangDown: number;\n\n    private _dimensionsSettings: any = { maxWidth: 260, originalScale: 1, width: 260, height: 30, x: 0, y: 0 };\n\n    public currencyYOffset: number = 0;\n\n    /**\n     * Constructor\n     * @param currencyValue\n     * @param textStyle\n     * @param align\n     */\n    constructor(\n        protected currencyValue: string,\n        protected textStyle: TextStyle,\n        protected align: string,\n        currencyTextStyle?: TextStyle,\n        protected verticalCurrency?: boolean,\n    ) {\n        super(currencyValue, textStyle, align, currencyTextStyle);\n\n        this.stage = BangUpStages.STAGE_ONE;\n        this.secondArrayDigits = [];\n        // this.digitsMask = new Graphics();\n        // this.addChild(this.digitsMask);\n        // this.mask = this.digitsMask;\n        // this.digitsMask.beginFill(0xff0000);\n        // this.digitsMask.drawRect(0, 0, 10, 10);\n    }\n\n    public get dimensionsSettings(): any {\n        return this._dimensionsSettings;\n    }\n\n    public set dimensionsSettings(settings: any) {\n        this._dimensionsSettings.maxWidth = settings.maxWidth;\n        this._dimensionsSettings.originalScale = settings.originalScale;\n        this._dimensionsSettings.width = settings.width;\n        this._dimensionsSettings.height = settings.height;\n        this._dimensionsSettings.x = settings.x;\n        this._dimensionsSettings.y = settings.y;\n    }\n\n    /**\n     * @param bangUpTo value where want bang up to finish in cents\n     * @param startFrom value for starting bang up in cents\n     * @param bangUpTime how many time want to banging up in milliseconds\n     * Use this method to start bang up animation.\n     */\n    public start(bangUpTo: number, startFrom: number, bangUpTime: number): void {\n        if (bangUpTo === startFrom) {\n            return;\n        } else if (bangUpTo < startFrom) {\n            this.setValue(bangUpTo);\n            return;\n        }\n        this.easing = 'none';\n        this.bangUpInterval = bangUpTime / (bangUpTo - startFrom);\n        this.stagingNeeded =\n            this.bangUpInterval <= this.stageTwoTimeBeforeEnd / this.stageTwoValueBeforeEnd && !this.bangDown;\n\n        if (this.bangingUp) {\n            this.continue(bangUpTo, bangUpTime);\n        } else {\n            if (this.stagingNeeded) {\n                this.stage = BangUpStages.STAGE_ONE;\n                this.setStage(bangUpTo, startFrom, bangUpTime);\n            } else {\n                super.start(bangUpTo, startFrom, bangUpTime);\n            }\n        }\n    }\n\n    /**\n     *\n     * @param value Use this method when want to visualize value without bang up for first time\n     */\n    public setValue(value: number): void {\n        if (this.moneyText === undefined) {\n            const moneyConfig: MoneyTextConfig = new MoneyTextConfig();\n            moneyConfig.currency = this.currencyValue;\n\n            this.moneyText = new MoneyText(moneyConfig, this.bangUpTo, new TextStyle({}));\n            super.addCurrencySign();\n        }\n        this.goToValueAndStop(value);\n    }\n\n    /**\n     * This method set the counter to exact value and stop on it.\n     * @param value\n     */\n    public goToValueAndStop(value: number): void {\n        if (this.bangUpTo === value) {\n            return;\n        }\n        this.bangUpTo = this.startFrom = value;\n        this.stagingNeeded = false;\n\n        const currentDigits = this.currentDigits();\n        if (this.arrayDigits.length < currentDigits.length) {\n            this.addDigit(currentDigits.length - this.arrayDigits.length);\n        } else if (this.arrayDigits.length > currentDigits.length) {\n            this.removeDigits();\n        }\n        for (let i: number = 0; i < this.arrayDigits.length; i++) {\n            this.arrayDigits[i].text = currentDigits[i];\n            this.secondArrayDigits[i].text = currentDigits[i];\n        }\n        this.formatDigits();\n        if (this.bangingUp) {\n            this.stop();\n        }\n        this.bangingUp = false;\n    }\n\n    /**\n     * Use this method for remove destroy and remove elements for banging up component.\n     */\n    public destroy(): void {\n        this.bangingUp = false;\n        this.digitTween.forEach((tween) => {\n            if (tween) {\n                // this.digitTween.progress(1, true);\n                tween.kill();\n            }\n        });\n        this.secondDigitTween.forEach((tween) => {\n            if (tween) {\n                // this.secondDigitTween.progress(1, true);\n                tween.kill();\n            }\n        });\n\n        // moneyText is destroyed by BangUpCurrencyText.destroy()\n        if (this.secondArrayDigits) {\n            this.secondArrayDigits.forEach((digit) => {\n                digit.destroy();\n            });\n        }\n\n        super.destroy.apply(this, arguments);\n        // Timers.setTimeout(() => {\n        //     for (let i: number = 0; i < this.arrayDigits.length; i++) {\n        //         this.removeChild(this.arrayDigits[i]);\n        //         this.removeChild(this.secondArrayDigits[i]);\n        //         this.arrayDigits[i].destroy();\n        //         this.secondArrayDigits[i].destroy();\n        //     }\n        //     this.removeChild(this.currencyText);\n        //     this.currencyText.destroy();\n        // }, this.bangUpInterval);\n    }\n\n    /**\n     * Use this method when want to stop banging up animation before complete.\n     */\n    public stop(): void {\n        if (this.stage === BangUpStages.STAGE_TWO && this.stagingNeeded) {\n            this.startFrom = this.bangUpTo + this.stageThreeValueBeforeEnd;\n        } else if (this.stage === BangUpStages.STAGE_ONE && this.stagingNeeded) {\n            this.startFrom = this.bangUpTo + this.stageThreeValueBeforeEnd + this.stageTwoValueBeforeEnd;\n        } else {\n            this.startFrom = this.bangUpTo;\n        }\n        const currentDigits: string = this.currentDigits();\n        if (this.arrayDigits.length < currentDigits.length) {\n            this.addDigit(currentDigits.length - this.arrayDigits.length);\n        }\n        for (let i: number = 0; i < this.arrayDigits.length; i++) {\n            this.arrayDigits[i].text = currentDigits[i];\n            this.secondArrayDigits[i].text = currentDigits[i];\n        }\n\n        this.bangingUp = false;\n        this.digitTween.forEach((tween) => {\n            tween.progress(1);\n        });\n        this.secondDigitTween.forEach((tween) => {\n            tween.progress(1);\n        });\n        this.formatDigits();\n    }\n\n    /**\n     * Use when want to count down existing value in counter.\n     * @param bangDownValue where to stop banging down in cents\n     * @param time time in milliseconds\n     */\n    public bangDownTo(bangDownValue: number, time: number): void {\n        super.bangDownTo(bangDownValue, time);\n        this.unUsedDigitsWhenBangDown = this.secondArrayDigits.length - this.currentDigits().length;\n    }\n\n    public setStyle(textStyle: TextStyle, currencyStyle?: TextStyle): void {\n        this.textStyle = textStyle;\n        this.children.forEach((digitText: BitmapText) => {\n            digitText.fontSize = Number(textStyle.fontSize);\n        });\n        if (currencyStyle) {\n            this.currencyText.style = currencyStyle;\n        }\n        this.presetCurrencyStyle();\n        this.formatDigits();\n    }\n\n    /**\n     * This method is used for formating the digits value For example after adding new digit or resize.\n     */\n    public formatDigits(): void {\n        this.shouldFormatDigits = false;\n        const currentDigit: string = this.currentDigits();\n        const alignmentOffset: number = this.setAlignment();\n        let digits: BitmapText[];\n        if (this.bangDown) {\n            digits = this.arrayDigits;\n        } else {\n            digits = this.secondArrayDigits;\n        }\n        for (let i: number = 0; i < currentDigit.length; i++) {\n            if (i !== 0) {\n                this.arrayDigits[i].x = digits[i - 1].x + digits[i - 1].width;\n                this.secondArrayDigits[i].x = digits[i - 1].x + digits[i - 1].width;\n            } else {\n                this.arrayDigits[i].x = alignmentOffset * -1;\n                this.secondArrayDigits[i].x = alignmentOffset * -1;\n            }\n\n            this.secondArrayDigits[i].y = this.arrayDigits[i].height;\n        }\n\n        let currencyOffset: number = 0;\n\n        if (this.verticalCurrency) {\n            this.currencyText.y = -2 + this.currencyYOffset;\n            currencyOffset = 3;\n        } else {\n            const currencyAscent: number = TextMetrics.measureFont(this.currencyText.style.toFontString()).ascent;\n            this.currencyText.y =\n                this.arrayDigits[0].height - this.currencyText.height + (this.currencyText.height - currencyAscent) / 2;\n        }\n        this.currencyText.x =\n            digits[currentDigit.length - 1].x + digits[currentDigit.length - 1].width + currencyOffset;\n\n        this.digitsWidth = this.currencyText.x + this.currencyText.width + alignmentOffset;\n        this.digitsHeight = this.arrayDigits[0].height;\n\n        if (this.digitsWidth > this.dimensionsSettings.maxWidth) {\n            this.scale.set(\n                (this.dimensionsSettings.maxWidth / this.digitsWidth) * this.dimensionsSettings.originalScale,\n                this.dimensionsSettings.originalScale,\n            );\n        } else {\n            this.scale.set(this.dimensionsSettings.originalScale, this.dimensionsSettings.originalScale);\n        }\n\n        // this.generateMask();\n    }\n\n    /**\n     * Adding new digits for example when value increase from 999 to 1000\n     */\n    protected addDigit(addNewDigits: number): void {\n        if (addNewDigits <= 0) {\n            return;\n        }\n        this.shouldFormatDigits = true;\n        const currentDigits: string = this.currentDigits();\n        for (let i: number = 0; i < addNewDigits; i++) {\n            const newDigit: BitmapText = new BitmapText(currentDigits[i], {\n                fontName: 'jackpotsBitmapFont',\n                fontSize: Number(this.textStyle.fontSize),\n                align: 'center',\n            });\n            const secondDigit: BitmapText = new BitmapText(currentDigits[i], {\n                fontName: 'jackpotsBitmapFont',\n                fontSize: Number(this.textStyle.fontSize),\n                align: 'center',\n            });\n\n            this.addChild(newDigit);\n            this.addChild(secondDigit);\n            this.arrayDigits.push(newDigit);\n            this.secondArrayDigits.push(secondDigit);\n        }\n    }\n\n    /**\n     * Position digits left right or center based on x 0 point\n     */\n    protected setAlignment(): number {\n        if (this.align === BangUpAnimatedCurrencyText.LEFT) {\n            return 0;\n        }\n        let digitWidth: number = 0;\n        let digits: BitmapText[];\n        if (this.bangDown) {\n            digits = this.arrayDigits;\n        } else {\n            digits = this.secondArrayDigits;\n        }\n        for (let i: number = 0; i < this.currentDigits().length; i++) {\n            digitWidth += digits[i].width;\n        }\n        digitWidth += this.currencyText.width;\n\n        if (this.align === BangUpAnimatedCurrencyText.RIGHT) {\n            return digitWidth;\n        }\n        return digitWidth / 2;\n    }\n\n    /**\n     * change the digits value after every tick\n     */\n    protected updateValue(): void {\n        if (!this.bangingUp) {\n            return;\n        }\n\n        let haveUpdates: boolean = false;\n        const currentDigits: string = this.currentDigits();\n        for (let i: number = 0; i < this.arrayDigits.length; i++) {\n            let tweenType: any;\n            if (this.bangDown) {\n                this.arrayDigits[i].text = currentDigits[i];\n                tweenType = gsap.from;\n            } else {\n                this.secondArrayDigits[i].text = currentDigits[i];\n                tweenType = gsap.to;\n            }\n            if (this.shouldFormatDigits && i === currentDigits.length - 1) {\n                this.formatDigits();\n            }\n\n            if (this.secondArrayDigits[i].text !== this.arrayDigits[i].text) {\n                /*  if (this.digitTween) {\n                    this.digitTween.kill();\n                } */\n                this.digitTween[i] = tweenType(this.secondArrayDigits[i], {\n                    duration: this.bangUpInterval / 1000,\n                    y: 0,\n                    ease: this.easing,\n                    snap: { y: 1 },\n                });\n                /* if (this.secondDigitTween) {\n                    this.secondDigitTween.kill();\n                } */\n                this.secondDigitTween[i] = tweenType(this.arrayDigits[i], {\n                    duration: this.bangUpInterval / 1000,\n                    y: this.arrayDigits[i].height * -1,\n                    ease: this.easing,\n                    snap: { y: 1 },\n                    onComplete: this.returnToOriginalPosition.bind(this, i),\n                });\n                haveUpdates = true;\n                this.lastTweenedElementIndex = i;\n            }\n        }\n        if (!haveUpdates) {\n            this.bangingUp = false;\n            if (this.stage < BangUpStages.LAST_STAGE && this.stagingNeeded) {\n                this.stage++;\n                this.setStage(this.bangUpTo, this.startFrom, this.bangUpTime);\n            }\n            if (this.bangDown) {\n                this.removeDigits();\n            }\n        }\n    }\n\n    /**\n     * this method trigger changes when is time for change\n     */\n    protected tick(): void {\n        this.startFrom += this.tickValue;\n        let currentDigit: string = this.currentDigits();\n        if (this.bangDown) {\n            if (this.startFrom < this.bangUpTo) {\n                this.startFrom = this.bangUpTo;\n                currentDigit = this.currentDigits();\n            }\n            if (this.arrayDigits.length - this.unUsedDigitsWhenBangDown > currentDigit.length) {\n                this.unUsedDigitsWhenBangDown = this.arrayDigits.length - currentDigit.length;\n                this.shouldFormatDigits = true;\n            }\n        } else {\n            if (this.startFrom > this.bangUpTo) {\n                this.startFrom = this.bangUpTo;\n                currentDigit = this.currentDigits();\n            }\n            if (this.arrayDigits.length < currentDigit.length) {\n                this.addDigit(currentDigit.length - this.arrayDigits.length);\n            }\n        }\n\n        this.updateValue();\n    }\n\n    /**\n     * Remove digits from component\n     * @param numOfDigits\n     */\n    protected removeDigits(): void {\n        /*         this.digitTween.forEach(tween =>{\n            if (tween) {\n                tween.progress(1, true);\n                tween.kill();\n            }\n        });\n        this.secondDigitTween.forEach(tween =>{\n            if (tween) {\n                tween.progress(1, true);\n                tween.kill();\n            }\n        }); */\n\n        Timers.setTimeout(() => {\n            const currentDigits = this.currentDigits();\n            if (this.arrayDigits.length - currentDigits.length > 0) {\n                for (let i: number = 0; i < this.arrayDigits.length - currentDigits.length; i++) {\n                    this.removeChild(this.arrayDigits[this.arrayDigits.length - 1]);\n                    this.arrayDigits[this.arrayDigits.length - 1].destroy();\n                    this.arrayDigits.pop();\n                    this.removeChild(this.secondArrayDigits[this.secondArrayDigits.length - 1]);\n                    this.secondArrayDigits[this.secondArrayDigits.length - 1].destroy();\n                    this.secondArrayDigits.pop();\n                }\n            }\n        }, this.bangUpInterval);\n    }\n\n    /**\n     *\n     * @param bangUpTo\n     * @param bangUpTime\n     * when bang up is in progress and receive new value should set new end values\n     */\n    private continue(bangUpTo: number, bangUpTime: number): void {\n        if (this.stagingNeeded) {\n            this.stage = BangUpStages.STAGE_ONE;\n            this.bangUpTime =\n                bangUpTime - this.stageOneTimeBeforeEnd - this.stageTwoTimeBeforeEnd - this.stageThreeTimeBeforeEnd;\n            this.bangUpTo = bangUpTo - this.stageTwoValueBeforeEnd - this.stageThreeValueBeforeEnd;\n        } else {\n            this.bangUpTo = bangUpTo;\n            this.bangUpTime = this.bangUpTime;\n        }\n        this.bangUpInterval = this.bangUpTime / (this.bangUpTo - this.startFrom);\n        if (this.bangUpInterval < this.minTickInterval) {\n            this.bangUpInterval = this.minTickInterval;\n        } else if (this.bangUpInterval > this.maxTickInterval) {\n            this.bangUpInterval = this.maxTickInterval;\n        }\n        this.numOfTicks = this.bangUpTime / this.bangUpInterval;\n        super.setBangUpTickValue();\n    }\n\n    /**\n     * @param i array index in array arrayDigits\n     * Move back digits to initial positions after tween complete\n     */\n    private returnToOriginalPosition(i: number): void {\n        if (this.arrayDigits[i]) {\n            if (this.bangDown) {\n                this.secondArrayDigits[i].text = this.arrayDigits[i].text;\n            } else {\n                this.arrayDigits[i].text = this.secondArrayDigits[i].text;\n            }\n            this.arrayDigits[i].y = 0;\n            this.secondArrayDigits[i].y = this.arrayDigits[i].height;\n            if (i === this.lastTweenedElementIndex) {\n                Timers.setTimeout(() => {\n                    this.tick();\n                }, 0);\n            }\n        }\n    }\n\n    /**\n     *\n     * @param digitAscent\n     * create mask for digits rotation\n     */\n    private generateMask(): void {\n        this.digitsMask.width = this.digitsWidth;\n        this.digitsMask.height = this.digitsHeight;\n        this.digitsMask.y = 0;\n        if (this.align === BangUpAnimatedCurrencyText.RIGHT) {\n            this.digitsMask.x = this.digitsWidth * -1;\n        } else if (this.align === BangUpAnimatedCurrencyText.CENTER) {\n            this.digitsMask.x = (this.digitsWidth / 2) * -1;\n        }\n    }\n\n    /**\n     * @param bangUpTo\n     * @param startFrom\n     * @param bangUpTime\n     * At the end of the rotation we add different speed of rotation. To do this need to have different stages.\n     * This method set correct stage\n     */\n    private setStage(bangUpTo: number, startFrom: number, bangUpTime: number): void {\n        if (this.stage === BangUpStages.STAGE_ONE) {\n            bangUpTime =\n                bangUpTime - this.stageOneTimeBeforeEnd - this.stageTwoTimeBeforeEnd - this.stageThreeTimeBeforeEnd;\n            bangUpTo = bangUpTo - this.stageTwoValueBeforeEnd - this.stageThreeValueBeforeEnd;\n            this.easing = 'none';\n        } else if (this.stage === BangUpStages.STAGE_TWO) {\n            bangUpTime = this.stageTwoTimeBeforeEnd;\n            startFrom = bangUpTo;\n            bangUpTo = bangUpTo + this.stageTwoValueBeforeEnd;\n            this.easing = 'none';\n        } else if (this.stage === BangUpStages.STAGE_THREE) {\n            bangUpTime = this.stageThreeTimeBeforeEnd;\n            startFrom = bangUpTo;\n            bangUpTo = bangUpTo + this.stageThreeValueBeforeEnd;\n            this.easing = 'back.out(2)';\n        }\n        super.start(bangUpTo, startFrom, bangUpTime);\n    }\n}\n","import { Timers } from '@egt/core';\nimport { gsap } from 'gsap';\nimport { BitmapText, TextStyle } from 'pixi.js';\nimport BangUpCurrencyText from './BangUpCurrencyText';\nimport BangUpTextBounds from './BangUpTextBounds';\nimport MoneyText from './MoneyText';\nimport MoneyTextConfig from './MoneyTextConfig';\n\nexport default class BangUpBitMapCurrencyText extends BangUpCurrencyText {\n    protected currencyText: BitmapText;\n    protected moneyText: any;\n    protected tickIntervalTimer;\n    protected gsapSync: boolean = false;\n    protected timeline: any;\n    protected tmpObj = { val: 0 };\n\n    constructor(\n        currencyValue: string,\n        textStyle: TextStyle,\n        align: string,\n        protected bitMapFontName: string,\n        protected currencyYOffset?: number,\n        public bounds?: BangUpTextBounds,\n    ) {\n        super(currencyValue, textStyle, align);\n    }\n\n    public start(bangUpTo: number, startFrom: number, bangUpTime: number, gsapSync: boolean = false): void {\n        if (this.moneyText === undefined) {\n            const moneyConfig: MoneyTextConfig = new MoneyTextConfig();\n            moneyConfig.currency = this.currencyValue;\n\n            this.moneyText = new MoneyText(moneyConfig, bangUpTo, new TextStyle({}));\n            if (this.currencyValue !== '') {\n                this.addCurrencySign();\n            }\n        }\n        this.bangUpTo = bangUpTo;\n        this.startFrom = startFrom;\n        this.tmpObj.val = this.startFrom;\n        this.bangUpTime = bangUpTime;\n        this.shouldFormatDigits = false;\n        this.bangingUp = true;\n        this.addDigit(this.currentDigits().length - this.arrayDigits.length);\n\n        this.gsapSync = gsapSync;\n        if (gsapSync) {\n            this.setGsapParams();\n            this.tickGsap(this.startFrom);\n        } else {\n            this.setTimersParams();\n            this.tick();\n            this.tickInterval();\n        }\n    }\n\n    public destroy(): void {\n        this.bangingUp = false;\n        if (this.tickIntervalTimer) {\n            Timers.clearInterval(this.tickIntervalTimer);\n            this.tickIntervalTimer = null;\n        }\n        this.timeline?.totalProgress(1);\n        this.timeline?.kill();\n        this.timeline = null;\n        super.destroy();\n    }\n\n    public onComplete(): void {\n        // asign to this function from outside\n    }\n\n    public addDigit(addNewDigits: number): void {\n        for (let i: number = 0; i < addNewDigits; i++) {\n            const newDigit: BitmapText = new BitmapText('0', {\n                fontName: this.bitMapFontName,\n                fontSize: Number(this.textStyle.fontSize),\n                align: 'center',\n            });\n            this.addChild(newDigit);\n            this.arrayDigits.push(newDigit);\n        }\n        this.shouldFormatDigits = true;\n    }\n\n    protected setGsapParams(): void {\n        this.tmpObj.val = this.startFrom;\n        this.timeline = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/slot-features/ui-lib/src/egt/ui/texts/BangUpBitMapCurrencyText.ts:88:25\",null]), gsap.to(this.tmpObj, {\n            duration: this.bangUpTime / 1000,\n            val: this.bangUpTo,\n            ease: 'none',\n            snap: {\n                val: 1,\n            },\n            onUpdate: () => {\n                // console.log('** update', o.val, this.startFrom);\n                this.tickGsap(this.tmpObj.val);\n            },\n            onComplete: () => {\n                // console.log('** complete', this.startFrom);\n                this.onComplete();\n            },\n        }));\n    }\n\n    protected setTimersParams(): void {\n        if (this.bangDown) {\n            this.bangUpInterval = this.bangUpTime / (this.startFrom - this.bangUpTo);\n        } else {\n            this.bangUpInterval = this.bangUpTime / (this.bangUpTo - this.startFrom);\n        }\n        if (this.bangUpInterval < this.minTickInterval) {\n            this.bangUpInterval = this.minTickInterval;\n        } else if (this.bangUpInterval > this.maxTickInterval) {\n            this.bangUpInterval = this.maxTickInterval;\n        }\n        this.numOfTicks = this.bangUpTime / this.bangUpInterval;\n        this.setBangUpTickValue();\n    }\n\n    protected setBangUpTickValue(): void {\n        this.tickValue = Math.ceil((this.bangUpTo - this.startFrom) / (this.bangUpTime / this.bangUpInterval));\n        if (!(this.tickValue % 10)) {\n            this.tickValue++;\n        }\n    }\n\n    protected addCurrencySign(): void {\n        const currencyStyle: TextStyle = new TextStyle(this.textStyle);\n        currencyStyle.fontSize = Math.round(Number(this.textStyle.fontSize) / 2);\n        this.currencyText = new BitmapText(this.currencyValue, {\n            fontName: this.bitMapFontName,\n            fontSize: currencyStyle.fontSize,\n            letterSpacing: this.textStyle.letterSpacing || 0,\n            align: 'center',\n        });\n        this.addChild(this.currencyText);\n    }\n\n    protected tickGsap(newValue: number): void {\n        if (!this.bangingUp) {\n            this.timeline?.kill();\n            this.timeline = null;\n            return;\n        }\n        this.startFrom = newValue;\n        if (this.bangDown) {\n            if (this.startFrom < this.bangUpTo) {\n                this.startFrom = this.bangUpTo;\n            }\n        } else {\n            if (this.startFrom > this.bangUpTo) {\n                this.startFrom = this.bangUpTo;\n            }\n        }\n\n        const currentDigit: string = this.currentDigits();\n        if (this.arrayDigits.length < currentDigit.length) {\n            this.addDigit(currentDigit.length - this.arrayDigits.length);\n        } else if (this.arrayDigits.length > currentDigit.length) {\n            this.removeDigits(this.arrayDigits.length - currentDigit.length);\n        }\n\n        this.updateValue();\n\n        if (this.shouldFormatDigits) {\n            this.formatDigits();\n        }\n    }\n\n    protected tickInterval(): void {\n        this.tickIntervalTimer = Timers.setInterval(() => {\n            this.tick();\n        }, this.bangUpInterval);\n    }\n\n    protected tick(): void {\n        if (!this.bangingUp) {\n            Timers.clearInterval(this.tickIntervalTimer);\n            return;\n        }\n        this.startFrom += this.tickValue;\n        if (this.bangDown) {\n            if (this.startFrom < this.bangUpTo) {\n                this.startFrom = this.bangUpTo;\n            }\n        } else {\n            if (this.startFrom > this.bangUpTo) {\n                this.startFrom = this.bangUpTo;\n            }\n        }\n\n        const currentDigit: string = this.currentDigits();\n        if (this.arrayDigits.length < currentDigit.length) {\n            this.addDigit(currentDigit.length - this.arrayDigits.length);\n        } else if (this.arrayDigits.length > currentDigit.length) {\n            this.removeDigits(this.arrayDigits.length - currentDigit.length);\n        }\n\n        this.updateValue();\n\n        if (!(this.startFrom < this.bangUpTo && !this.bangDown)) {\n            this.bangingUp = false;\n            Timers.clearInterval(this.tickIntervalTimer);\n            this.onComplete();\n        }\n\n        if (this.shouldFormatDigits) {\n            this.formatDigits();\n        }\n    }\n\n    protected formatDigits(): void {\n        this.shouldFormatDigits = false;\n        const alignmentOffset: number = this.setAlignment();\n        const currentDigits: string = this.currentDigits();\n        for (let i: number = 0; i < currentDigits.length; i++) {\n            if (i !== 0) {\n                this.arrayDigits[i].x =\n                    this.arrayDigits[i - 1].x + this.arrayDigits[i - 1].width + (this.textStyle.letterSpacing || 0);\n            } else {\n                this.arrayDigits[i].x = alignmentOffset * -1;\n            }\n        }\n        const lastIdx = currentDigits.length - 1;\n        const currencyXOffset = 8;\n\n        if (this.currencyText) {\n            this.currencyText.x =\n                this.arrayDigits[lastIdx].x +\n                this.arrayDigits[lastIdx].width +\n                currencyXOffset +\n                (this.textStyle.letterSpacing || 0);\n\n            if (this.currencyYOffset !== undefined) {\n                this.currencyText.y = this.currencyText.height + this.currencyYOffset;\n            } else {\n                const currencyAscent: number = this.currencyText.height;\n                this.currencyText.y =\n                    this.arrayDigits[0].height -\n                    this.currencyText.height +\n                    (this.currencyText.height - currencyAscent) / 2;\n            }\n\n            this.digitsWidth = this.currencyText.x + this.currencyText.width + alignmentOffset;\n        } else {\n            this.digitsWidth = this.arrayDigits[lastIdx].x + this.arrayDigits[lastIdx].width + alignmentOffset;\n        }\n\n        this.digitsHeight = this.arrayDigits[0].height;\n        this.setBounds();\n    }\n\n    public setBounds(): void {\n        if (this.bounds) {\n            this.scale.set(1);\n            let scale = 1;\n            if (this.digitsWidth > this.bounds.width) {\n                scale = this.bounds.width / this.width;\n            }\n            if (this.digitsHeight > this.bounds.height) {\n                const scaleY = this.bounds.height / this.height;\n                scale = scaleY < scale ? scaleY : scale;\n            }\n            if (scale < 1) {\n                this.scale.set(scale);\n                // this.y = (this.height - this.height * this.scale.x) / 2 + this.bounds.y;\n                this.y = this.bounds.getScaledPositionY(this.height, scale);\n                this.x += this.bounds.x;\n            }\n        }\n    }\n    public setStyle(textStyle: TextStyle): void {\n        this.textStyle = textStyle;\n        this.children.forEach((digitText: BitmapText) => {\n            digitText.fontSize = Number(textStyle.fontSize);\n        });\n\n        this.currencyText.fontSize = Number(textStyle.fontSize) / 2;\n        this.formatDigits();\n    }\n\n    protected presetCurrencyStyle(): void {\n        const currencyStyle: TextStyle = new TextStyle(this.textStyle);\n        currencyStyle.fontSize = Math.round(Number(this.textStyle.fontSize) / 2);\n    }\n}\n","import BangUpBitMapCurrencyText from './BangUpBitMapCurrencyText';\nimport { TextStyle } from 'pixi.js';\nimport BangUpTextBounds from './BangUpTextBounds';\n\nexport default class BangUpBitMapCurrencyTextDynamicPivot extends BangUpBitMapCurrencyText {\n    constructor(\n        currencyValue: string,\n        textStyle: TextStyle,\n        align: string,\n        bitMapFontName: string,\n        currencyYOffset?: number,\n        bounds?: BangUpTextBounds,\n    ) {\n        super(currencyValue, textStyle, align, bitMapFontName, currencyYOffset, bounds);\n    }\n\n    protected setPivotAndYPosition(): void {\n        this.pivot.set(0, this.digitsHeight / 2);\n        this.y = this.pivot.y * -1;\n    }\n\n    protected formatDigits(): void {\n        super.formatDigits();\n        this.setPivotAndYPosition();\n    }\n}\n","import { Timers } from '@egt/core';\nimport { gsap } from 'gsap';\nimport { BitmapText, TextStyle } from 'pixi.js';\nimport BangUpText from './BangUpText';\nimport BangUpTextBounds from './BangUpTextBounds';\nimport MoneyText from './MoneyText';\nimport MoneyTextConfig from './MoneyTextConfig';\n\nexport default class BangUpBitMapText extends BangUpText {\n    protected moneyText: any;\n    protected tickIntervalTimer;\n    protected gsapSync: boolean = false;\n    protected timeline: any;\n    protected tmpObj = { val: 0 };\n\n    constructor(\n        textStyle: TextStyle,\n        align: string,\n        protected bitMapFontName: string,\n        public bounds?: BangUpTextBounds,\n    ) {\n        super(textStyle, align);\n    }\n\n    public start(bangUpTo: number, startFrom: number, bangUpTime: number, gsapSync: boolean = false): void {\n        if (this.moneyText === undefined) {\n            const moneyConfig: MoneyTextConfig = new MoneyTextConfig();\n\n            this.moneyText = new MoneyText(moneyConfig, bangUpTo, new TextStyle({}));\n        }\n        this.bangUpTo = bangUpTo;\n        this.startFrom = startFrom;\n        this.tmpObj.val = startFrom;\n        this.bangUpTime = bangUpTime;\n        this.shouldFormatDigits = false;\n        this.bangingUp = true;\n        this.addDigit(this.currentDigits().length - this.arrayDigits.length);\n\n        this.gsapSync = gsapSync;\n        if (gsapSync) {\n            this.setGsapParams();\n            this.tickGsap(this.startFrom);\n        } else {\n            this.setTimersParams();\n            this.tick();\n            this.tickInterval();\n        }\n    }\n\n    public onComplete(): void {\n        // asign to this function from outside\n    }\n\n    public destroy(): void {\n        this.bangingUp = false;\n        if (this.tickIntervalTimer) {\n            Timers.clearInterval(this.tickIntervalTimer);\n            this.tickIntervalTimer = null;\n        }\n        if (this.timeline) {\n            this.timeline.kill();\n            this.timeline = null;\n        }\n        // moneyText is a plain formatter object, never addChild-ed — destroy it\n        // explicitly or its Text canvas textures stay in the cache forever.\n        this.moneyText?.destroy();\n        this.moneyText = undefined;\n        super.destroy();\n    }\n\n    protected addDigit(addNewDigits: number): void {\n        for (let i: number = 0; i < addNewDigits; i++) {\n            const newDigit: BitmapText = new BitmapText('0', {\n                fontName: this.bitMapFontName,\n                fontSize: Number(this.textStyle.fontSize),\n                align: 'center',\n            });\n            this.addChild(newDigit);\n            this.arrayDigits.push(newDigit);\n        }\n        this.shouldFormatDigits = true;\n    }\n\n    protected setGsapParams(): void {\n        this.tmpObj.val = this.startFrom;\n        this.timeline = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/slot-features/ui-lib/src/egt/ui/texts/BangUpBitMapText.ts:86:25\",null]), gsap.to(this.tmpObj, {\n            duration: this.bangUpTime / 1000,\n            val: this.bangUpTo,\n            ease: 'none',\n            snap: {\n                val: 1,\n            },\n            onUpdate: () => {\n                // console.log('** update', o.val, this.startFrom);\n                this.tickGsap(this.tmpObj.val);\n            },\n            onComplete: () => {\n                // console.log('** compklete', this.startFrom);\n                this.onComplete();\n            },\n        }));\n    }\n\n    protected setTimersParams(): void {\n        if (this.bangDown) {\n            this.bangUpInterval = this.bangUpTime / (this.startFrom - this.bangUpTo);\n        } else {\n            this.bangUpInterval = this.bangUpTime / (this.bangUpTo - this.startFrom);\n        }\n        if (this.bangUpInterval < this.minTickInterval) {\n            this.bangUpInterval = this.minTickInterval;\n        } else if (this.bangUpInterval > this.maxTickInterval) {\n            this.bangUpInterval = this.maxTickInterval;\n        }\n        this.numOfTicks = this.bangUpTime / this.bangUpInterval;\n        this.setBangUpTickValue();\n    }\n\n    protected setBangUpTickValue(): void {\n        this.tickValue = Math.ceil((this.bangUpTo - this.startFrom) / (this.bangUpTime / this.bangUpInterval));\n        if (!(this.tickValue % 10)) {\n            this.tickValue++;\n        }\n    }\n\n    protected tickGsap(newValue: number): void {\n        if (!this.bangingUp) {\n            this.timeline?.kill();\n            this.timeline = null;\n            return;\n        }\n        const newValueRounded = Math.ceil(newValue);\n        if (this.startFrom === newValueRounded) {\n            return;\n        }\n        this.startFrom = newValueRounded;\n        if (this.bangDown) {\n            if (this.startFrom < this.bangUpTo) {\n                this.startFrom = this.bangUpTo;\n            }\n        } else {\n            if (this.startFrom > this.bangUpTo) {\n                this.startFrom = this.bangUpTo;\n            }\n        }\n\n        const currentDigit: string = this.currentDigits();\n        if (this.arrayDigits.length < currentDigit.length) {\n            this.addDigit(currentDigit.length - this.arrayDigits.length);\n        } else if (this.arrayDigits.length > currentDigit.length) {\n            this.removeDigits(this.arrayDigits.length - currentDigit.length);\n        }\n\n        this.updateValue();\n\n        if (this.shouldFormatDigits) {\n            this.formatDigits();\n        }\n    }\n\n    protected tickInterval(): void {\n        this.tickIntervalTimer = Timers.setInterval(() => {\n            this.tick();\n        }, this.bangUpInterval);\n    }\n\n    protected tick(): void {\n        if (!this.bangingUp) {\n            Timers.clearInterval(this.tickIntervalTimer);\n            return;\n        }\n        this.startFrom += this.tickValue;\n        if (this.bangDown) {\n            if (this.startFrom < this.bangUpTo) {\n                this.startFrom = this.bangUpTo;\n            }\n        } else {\n            if (this.startFrom > this.bangUpTo) {\n                this.startFrom = this.bangUpTo;\n            }\n        }\n\n        const currentDigit: string = this.currentDigits();\n        if (this.arrayDigits.length < currentDigit.length) {\n            this.addDigit(currentDigit.length - this.arrayDigits.length);\n        } else if (this.arrayDigits.length > currentDigit.length) {\n            this.removeDigits(this.arrayDigits.length - currentDigit.length);\n        }\n\n        this.updateValue();\n\n        if (!(this.startFrom < this.bangUpTo && !this.bangDown)) {\n            this.bangingUp = false;\n            Timers.clearInterval(this.tickIntervalTimer);\n            this.onComplete();\n        }\n\n        if (this.shouldFormatDigits) {\n            this.formatDigits();\n        }\n    }\n\n    protected formatDigits(): void {\n        super.formatDigits();\n\n        if (this.bounds) {\n            this.scale.set(1);\n            let scale = 1;\n            if (this.digitsWidth > this.bounds.width) {\n                scale = this.bounds.width / this.width;\n            }\n            if (this.digitsHeight > this.bounds.height) {\n                const scaleY = this.bounds.height / this.height;\n                scale = scaleY < scale ? scaleY : scale;\n            }\n            if (scale < 1) {\n                this.scale.set(scale);\n\n                this.y = this.bounds.getScaledPositionY(this.height, scale);\n                this.x += this.bounds.x;\n            }\n        }\n    }\n\n    protected presetCurrencyStyle(): void {\n        const currencyStyle: TextStyle = new TextStyle(this.textStyle);\n        currencyStyle.fontSize = Math.round(Number(this.textStyle.fontSize) / 2);\n    }\n}\n","import BangUpBitMapText from './BangUpBitMapText';\nimport { TextStyle } from 'pixi.js';\nimport BangUpTextBounds from './BangUpTextBounds';\n\nexport default class BangUpBitMapTextDynamicPivot extends BangUpBitMapText {\n    constructor(textStyle: TextStyle, align: string, bitMapFontName: string, bounds?: BangUpTextBounds) {\n        super(textStyle, align, bitMapFontName, bounds);\n    }\n    protected setPivotAndYPosition(): void {\n        this.pivot.set(0, this.digitsHeight / 2);\n        this.y = this.pivot.y * -1;\n    }\n\n    protected formatDigits(): void {\n        super.formatDigits();\n        this.setPivotAndYPosition();\n    }\n}\n","import { Text, TextMetrics, TextStyle } from 'pixi.js';\nimport BangUpText from './BangUpText';\nimport MoneyText from './MoneyText';\nimport MoneyTextConfig from './MoneyTextConfig';\n\nexport default class BangUpCurrencyText extends BangUpText {\n    protected currencyText: any;\n    protected moneyText: MoneyText;\n\n    /**\n     * Constructor\n     * @param currencyValue\n     * @param textStyle\n     * @param align\n     */\n    constructor(\n        protected currencyValue: string,\n        protected textStyle: TextStyle,\n        align: string,\n        protected currencyTextStyle?: TextStyle,\n        protected verticalCurrency?: boolean,\n    ) {\n        super(textStyle, align);\n    }\n\n    public destroy(): void {\n        // moneyText is a plain formatter object — it is never addChild-ed, so\n        // destroying children can't reach it. Without this its three Text\n        // canvas textures stay in the BaseTexture cache forever (currencyText\n        // IS a child and dies via super's { children: true }).\n        this.moneyText?.destroy();\n        // @ts-ignore\n        this.moneyText = undefined;\n        super.destroy();\n    }\n\n    /**\n     * @param bangUpTo value where want bang up to finish in cents\n     * @param startFrom value for starting bang up in cents\n     * @param bangUpTime how many time want to banging up in milliseconds\n     * Use this method to start bang up animation.\n     */\n    public start(bangUpTo: number, startFrom: number, bangUpTime: number): void {\n        if (this.moneyText === undefined) {\n            const moneyConfig: MoneyTextConfig = new MoneyTextConfig();\n            moneyConfig.currency = this.currencyValue;\n\n            this.moneyText = new MoneyText(moneyConfig, bangUpTo, new TextStyle({}));\n            this.addCurrencySign();\n        }\n        super.start(bangUpTo, startFrom, bangUpTime);\n    }\n\n    public get value(): number | undefined {\n        return this.moneyText ? this.moneyText.money : undefined;\n    }\n\n    /**\n     * return all symbols for banging up\n     */\n    protected currentDigits(): string {\n        this.moneyText.money = this.startFrom;\n        // we want to remove only the interval with currency, i.e. ' EGT'\n        if (this.moneyText.currency) {\n            return this.moneyText.moneyText.replace(' ' + this.moneyText.currency, '');\n        }\n        return this.moneyText.moneyText;\n    }\n\n    /**\n     * Position digits left right or center based on x 0 point\n     */\n\n    protected setAlignment(): number {\n        if (this.align === BangUpCurrencyText.LEFT) {\n            return 0;\n        }\n\n        let digitWidth: number = 0;\n        const len = this.currentDigits().length;\n        for (let i: number = 0; i < len; i++) {\n            digitWidth += this.arrayDigits[i].width + (this.textStyle.letterSpacing || 0);\n        }\n\n        if (this.currencyText) {\n            digitWidth += this.currencyText.width;\n        }\n\n        if (this.align === BangUpCurrencyText.RIGHT) {\n            return digitWidth;\n        }\n        return digitWidth / 2;\n    }\n\n    /**\n     * This method is used for formating the digits value For example after adding new digit or resize.\n     */\n    protected formatDigits(): void {\n        this.shouldFormatDigits = false;\n        const alignmentOffset: number = this.setAlignment();\n        const currentDigits: string = this.currentDigits();\n        for (let i: number = 0; i < currentDigits.length; i++) {\n            if (i !== 0) {\n                this.arrayDigits[i].x =\n                    this.arrayDigits[i - 1].x + this.arrayDigits[i - 1].width + (this.textStyle.letterSpacing || 0);\n            } else {\n                this.arrayDigits[i].x = alignmentOffset * -1;\n            }\n        }\n\n        let currencyOffset: number = 0;\n\n        if (this.verticalCurrency) {\n            this.currencyText.y = -2;\n            currencyOffset = 3;\n        } else {\n            const currencyAscent: number = TextMetrics.measureFont(this.currencyText.style.toFontString()).ascent;\n            this.currencyText.y =\n                this.arrayDigits[0].height - this.currencyText.height + (this.currencyText.height - currencyAscent) / 2;\n        }\n\n        this.currencyText.x =\n            this.arrayDigits[currentDigits.length - 1].x +\n            this.arrayDigits[currentDigits.length - 1].width +\n            currencyOffset;\n\n        this.digitsWidth = this.currencyText.x + this.currencyText.width + alignmentOffset;\n        this.digitsHeight = this.arrayDigits[0].height;\n    }\n\n    /**\n     * Adding currency sign at end of the digits\n     */\n    protected addCurrencySign(): void {\n        let currencyTextStyle: TextStyle = this.textStyle;\n        if (this.currencyTextStyle) {\n            currencyTextStyle = this.currencyTextStyle;\n        }\n        const currencyStyle: TextStyle = new TextStyle(currencyTextStyle);\n        currencyStyle.fontSize = Math.round(Number(currencyTextStyle.fontSize) / 2);\n        this.currencyText = new Text(this.moneyText.currency, currencyStyle);\n        this.currencyText.resolution = 2;\n        this.addChild(this.currencyText);\n    }\n\n    /**\n     * Adding currency sign at end of the digits\n     */\n    protected presetCurrencyStyle(): void {\n        if (!this.currencyTextStyle) {\n            const currencyStyle: TextStyle = new TextStyle(this.textStyle);\n            currencyStyle.fontSize = Math.round(Number(this.textStyle.fontSize) / 2);\n            this.currencyText.style = currencyStyle;\n        }\n    }\n}\n","import { Timers } from '@egt/core';\nimport { BitmapText, TextStyle } from 'pixi.js';\nimport ViewContainer from '../ViewContainer';\n\nexport default class BangUpText extends ViewContainer {\n    public static LEFT: string = 'Left';\n    public static RIGHT: string = 'Right';\n    public static CENTER: string = 'Center';\n    public addSpaceBetween = false;\n    public bangingUp: boolean;\n\n    protected digitsWidth: number;\n    protected digitsHeight: number;\n    public arrayDigits: BitmapText[];\n    protected shouldFormatDigits: boolean;\n    protected tickValue: number;\n    protected bangUpInterval: number;\n    protected numOfTicks: number;\n    protected minTickInterval: number = 50;\n    protected maxTickInterval: number = 1000;\n    protected bangUpTo: number;\n    protected startFrom: number = 0;\n    protected bangUpTime: number = 3000;\n    protected blinkingAnimationCounter: number = 0;\n    protected blinkingAnimationBlinks: number = 8; // should be an even number\n    protected bangDown: boolean = false;\n    public currentValue: number = 0;\n    /**\n     * Constructor\n     * @param textStyle\n     * @param align\n     */\n    constructor(\n        protected textStyle: TextStyle,\n        protected align: string,\n    ) {\n        super();\n        this.arrayDigits = [];\n    }\n\n    /**\n     * Use this getter to get current value\n     */\n    public get current(): number {\n        return this.startFrom;\n    }\n    public get widthDigits(): number {\n        return this.digitsWidth;\n    }\n    public destroy(): void {\n        if (this.arrayDigits) {\n            this.arrayDigits.forEach((digit) => {\n                digit.destroy();\n                // @ts-ignore\n                digit = null;\n            });\n            this.arrayDigits = [];\n            // @ts-ignore\n            this.arrayDigits = null;\n        }\n\n        super.destroy({ children: true, texture: true });\n    }\n\n    /**\n     *\n     * @param bangUpTo value where want bang up to finish in cents\n     * @param startFrom value for starting bang up in cents\n     * @param bangUpTime how many time want to banging up in milliseconds\n     * Use this method to start bang up animation.\n     */\n    public start(bangUpTo: number, startFrom: number, bangUpTime: number): void {\n        this.bangUpTo = bangUpTo;\n        this.startFrom = startFrom;\n        this.bangUpTime = bangUpTime;\n        this.currentValue = this.startFrom;\n        if (this.bangDown) {\n            this.bangUpInterval = this.bangUpTime / (this.startFrom - this.bangUpTo);\n        } else {\n            this.bangUpInterval = this.bangUpTime / (this.bangUpTo - this.startFrom);\n        }\n        if (this.bangUpInterval < this.minTickInterval) {\n            this.bangUpInterval = this.minTickInterval;\n        } else if (this.bangUpInterval > this.maxTickInterval) {\n            this.bangUpInterval = this.maxTickInterval;\n        }\n        this.numOfTicks = this.bangUpTime / this.bangUpInterval;\n        this.setBangUpTickValue();\n        this.shouldFormatDigits = false;\n        this.bangingUp = true;\n        this.addDigit(this.currentDigits().length - this.arrayDigits.length);\n        this.tick();\n    }\n\n    /**\n     * Use this method when want to stop banging up animation before complete.\n     */\n    public stop(): void {\n        this.bangingUp = false;\n        this.startFrom = this.bangUpTo;\n        const currentDigits: string = this.currentDigits();\n        if (this.arrayDigits.length < currentDigits.length) {\n            this.addDigit(currentDigits.length - this.arrayDigits.length);\n        } else if (this.arrayDigits.length > currentDigits.length) {\n            this.removeChildren(this.arrayDigits.length - currentDigits.length);\n        }\n        this.updateValue();\n        this.formatDigits();\n    }\n\n    /**\n     * Use when want to count down existing value in counter.\n     * @param bangDownValue where to stop banging down in cents\n     * @param time time in milliseconds\n     */\n    public bangDownTo(bangDownValue: number, time: number): void {\n        let startBangingDownAfter: number = 0;\n        if (this.bangingUp) {\n            startBangingDownAfter = this.bangUpInterval;\n            this.stop();\n        }\n        Timers.setTimeout(() => {\n            this.bangDown = true;\n            this.start(bangDownValue, this.startFrom, time);\n        }, startBangingDownAfter);\n    }\n\n    /**\n     * This method set the counter to exact value and stop on it.\n     * @param value\n     */\n    public goToValueAndStop(value: number): void {\n        this.bangUpTo = this.startFrom = value;\n        // currentValue must mirror what is displayed from the very first preset,\n        // otherwise callers reading it back as the next bang-up's starting point\n        // would start from 0 and the counter would jump down before banging up.\n        this.currentValue = value;\n        this.bangingUp = false;\n        const currentDigits = this.currentDigits();\n        if (this.arrayDigits.length < currentDigits.length) {\n            this.addDigit(currentDigits.length - this.arrayDigits.length);\n        } else if (this.arrayDigits.length > currentDigits.length) {\n            this.removeDigits(this.arrayDigits.length - currentDigits.length);\n        }\n        for (let i: number = 0; i < this.arrayDigits.length; i++) {\n            this.arrayDigits[i].text = currentDigits[i];\n        }\n        this.formatDigits();\n        this.stop();\n    }\n\n    /**\n     * show blinking animation\n     */\n    public blinkingAnimation(): void {\n        let timer: number = 400;\n        if (this.blinkingAnimationCounter % 2 === 1) {\n            timer = 300;\n        }\n        Timers.setTimeout(() => {\n            this.blinkingAnimationCounter++;\n            this.visible = !this.visible;\n            if (this.blinkingAnimationCounter < this.blinkingAnimationBlinks) {\n                this.blinkingAnimation();\n            }\n        }, timer);\n    }\n\n    public get getDigitsHeight(): number {\n        return this.digitsHeight;\n    }\n\n    public onUpdate(_val): void {\n        //\n    }\n\n    /**\n     * return all symbols for banging up\n     */\n    protected currentDigits(): string {\n        const startFrom = this.addSpaceBetween\n            ? this.startFrom.toLocaleString('en-US').replace(/,/g, ' ')\n            : this.startFrom.toString();\n\n        return startFrom;\n    }\n\n    /**\n     * Position digits left right or center based on x 0 point\n     */\n    protected setAlignment(): void {\n        this.arrayDigits.forEach((digit) => {\n            if (this.align === BangUpText.RIGHT) {\n                digit.x -= this.digitsWidth;\n            } else if (this.align === BangUpText.CENTER) {\n                digit.x -= this.digitsWidth / 2;\n            }\n        });\n    }\n\n    /**\n     * Adding new digits for example when value increase from 999 to 1000\n     */\n    protected addDigit(addNewDigits: number): void {\n        for (let i: number = 0; i < addNewDigits; i++) {\n            const newDigit: BitmapText = new BitmapText('0', {\n                fontName: 'jackpotsBitmapFont',\n                fontSize: Number(this.textStyle.fontSize),\n                align: 'center',\n            });\n            this.addChild(newDigit);\n            this.arrayDigits.push(newDigit);\n        }\n        this.shouldFormatDigits = true;\n    }\n\n    /**\n     * adding timer for every new tick\n     */\n    protected tickInterval(): void {\n        Timers.setTimeout(() => {\n            this.tick();\n        }, this.bangUpInterval);\n    }\n\n    /**\n     * this method trigger changes when is time for change\n     */\n    protected tick(): void {\n        if (!this.bangingUp) {\n            return;\n        }\n        this.startFrom += this.tickValue;\n        if (this.bangDown) {\n            if (this.startFrom < this.bangUpTo) {\n                this.startFrom = this.bangUpTo;\n            }\n        } else {\n            if (this.startFrom > this.bangUpTo) {\n                this.startFrom = this.bangUpTo;\n            }\n        }\n\n        const currentDigit: string = this.currentDigits();\n        if (this.arrayDigits.length < currentDigit.length) {\n            this.addDigit(currentDigit.length - this.arrayDigits.length);\n        } else if (this.arrayDigits.length > currentDigit.length) {\n            this.removeDigits(this.arrayDigits.length - currentDigit.length);\n        }\n\n        this.updateValue();\n\n        if ((this.startFrom < this.bangUpTo && !this.bangDown) || (this.startFrom > this.bangUpTo && this.bangUpTo)) {\n            this.tickInterval();\n        } else {\n            this.bangingUp = false;\n        }\n\n        if (this.shouldFormatDigits) {\n            this.formatDigits();\n        }\n    }\n\n    /**\n     * This method is used for formatting the digits value For example after adding new digit or resize.\n     */\n    protected formatDigits(): void {\n        this.shouldFormatDigits = false;\n        const currentText: string = this.currentDigits();\n        for (let i: number = 0; i < currentText.length; i++) {\n            if (i !== 0) {\n                this.arrayDigits[i].x =\n                    this.arrayDigits[i - 1].x + this.arrayDigits[i - 1].width + (this.textStyle.letterSpacing || 0);\n            } else {\n                this.arrayDigits[i].x = 0;\n            }\n        }\n        this.digitsWidth = this.arrayDigits[currentText.length - 1].x + this.arrayDigits[currentText.length - 1].width;\n        this.digitsHeight = this.arrayDigits[0].height;\n\n        this.setAlignment();\n    }\n\n    /**\n     * change the digits value after every tick\n     * @param digits already formatted digits for the current value - pass it when\n     * the caller has computed it, so it is not formatted a second time here.\n     */\n    protected updateValue(digits?: string): void {\n        const currentText: string = digits ?? this.currentDigits();\n        for (let i: number = 0; i < this.arrayDigits.length; i++) {\n            const digit: string = currentText[i];\n            // Assigning text always flags the BitmapText dirty and forces a\n            // re-layout on the next render, so skip the characters that did not\n            // change - on a long counter only the last one or two ever do.\n            if (this.arrayDigits[i].text !== digit) {\n                this.arrayDigits[i].text = digit;\n            }\n        }\n        this.onUpdate(this.startFrom);\n    }\n\n    /**\n     * create step for banging up for example if time for banging up is 1 sec. and different between start and and value is 100 banging up tick\n     * will be 10 and will have 10 iterations by 10 for 1 sec.\n     */\n    protected setBangUpTickValue(): void {\n        this.tickValue = Math.round(((this.bangUpTo - this.startFrom) / this.bangUpTime) * this.bangUpInterval);\n        let dontReplaceSymbol: number = 0;\n        if (this.bangDown) {\n            dontReplaceSymbol = 1;\n        }\n        let value: string = '';\n        for (let i: number = 0; i < this.tickValue.toString().length; i++) {\n            if (i <= dontReplaceSymbol) {\n                value = value + this.tickValue.toString()[i];\n            } else {\n                value = value + (this.tickValue.toString().length - i).toString();\n            }\n        }\n        this.tickValue = Number(value);\n        if (this.tickValue === 0) {\n            this.tickValue = 1;\n        }\n    }\n\n    /**\n     * Remove digits from component\n     * @param numOfDigits\n     */\n    protected removeDigits(numOfDigits: number): void {\n        this.shouldFormatDigits = true;\n        for (let i: number = 0; i < numOfDigits; i++) {\n            this.removeChild(this.arrayDigits[this.arrayDigits.length - 1]);\n            this.arrayDigits[this.arrayDigits.length - 1].destroy();\n            this.arrayDigits.pop();\n        }\n    }\n\n    public presetTextStyle(style: TextStyle) {\n        this.textStyle = style;\n        const digits = this.arrayDigits.length;\n\n        this.removeDigits(digits);\n        this.addDigit(digits);\n        this.shouldFormatDigits = true;\n        this.updateValue();\n        this.formatDigits();\n    }\n}\n","import { Rectangle } from 'pixi.js';\n// THIS CLASS CAN BE REMOVED AFTER THE RELEASE 1.36.0 AND THE LOGIC FOR Y TO BE TRANSFERED INTO BangUpBitMapText CLASS\nexport default class BangUpTextBounds extends Rectangle {\n    constructor(\n        x: number,\n        y: number,\n        width: number,\n        height: number,\n        public fontImageHeight: number = 0,\n        public fontImageEmpty: number = 0,\n        public yBounds: boolean = false,\n    ) {\n        super(x, y, width, height);\n    }\n\n    public getScaledPositionY(height, scale) {\n        if (this.fontImageHeight > 0) {\n            const bitmapFontHeightOffset = (height / this.fontImageHeight) * this.fontImageEmpty;\n            const realHeight = height - bitmapFontHeightOffset;\n            return this.y + (this.height - realHeight * scale) / 2;\n        } else {\n            const newHeight = this.yBounds ? this.height : height;\n            return (newHeight * (1 - scale)) / 2 + this.y;\n        }\n    }\n}\n","import Core from '@egt/core';\nimport { BlurFilter } from '@pixi/filter-blur';\nimport { ITextStyle, Text, TextStyle } from 'pixi.js';\n\nexport default class BluredText extends Text {\n    constructor(\n        text?: string | number,\n        style?: Partial<ITextStyle> | TextStyle,\n        canvas?: HTMLCanvasElement,\n        blur?: boolean,\n        light?: boolean,\n    ) {\n        super(text, style, canvas);\n        // ON-87343 - do not blur in special cases of replayer\n        if (Core.isReplayer && Core.gamePortalExchangeObject?.hideReplayerBanner) {\n            blur = false;\n        }\n        if (blur) {\n            const bf = new BlurFilter();\n            if (Core.isDesktopMode) {\n                if (light) {\n                    bf.blurY = 6;\n                    bf.blurX = 6;\n                } else {\n                    bf.blurY = 10;\n                    bf.blurX = 10;\n                }\n                const scaleFactor = window.devicePixelRatio || 1;\n                bf.blurX = bf.blurX * scaleFactor;\n                bf.blurY = bf.blurY * scaleFactor;\n                bf.quality = 4;\n            } else {\n                if (light) {\n                    bf.blurY = 4;\n                    bf.blurX = 4;\n                } else {\n                    bf.blurY = 10;\n                    bf.blurX = 10;\n                    bf.quality = 4;\n                }\n            }\n            this.filters = [bf];\n        }\n    }\n}\n","import { gsap } from 'gsap';\nimport { BitmapText, TextStyle } from 'pixi.js';\nimport { Subject } from 'rxjs';\nimport BangUpBitMapText from './BangUpBitMapText';\nimport BangUpTextBounds from './BangUpTextBounds';\nimport MoneyText from './MoneyText';\nimport MoneyTextConfig from './MoneyTextConfig';\n\nexport default class JackpotBangUpBitMapText extends BangUpBitMapText {\n    public RESCALE_JACKPOTS = new Subject();\n    /** Visible odometer steps per second - 225 steps over the legacy 15s duration. */\n    protected stepsPerSecond: number = 15;\n    /** Raw tween value of the last processed tick, used to skip no-op updates. */\n    protected lastTickedValue: number = NaN;\n    constructor(\n        textStyle: TextStyle,\n        align: string,\n        protected bitMapFontName: string,\n        public bounds: BangUpTextBounds,\n    ) {\n        super(textStyle, align, bitMapFontName, bounds);\n    }\n\n    public addDigit(addNewDigits: number): void {\n        if (addNewDigits != 0) {\n            this.shouldFormatDigits = true;\n        }\n        for (let i: number = 0; i < addNewDigits; i++) {\n            const newDigit: BitmapText = new BitmapText('0', {\n                fontName: this.bitMapFontName,\n                fontSize: Number(this.textStyle.fontSize),\n                align: 'center',\n            });\n            this.addChild(newDigit);\n            this.arrayDigits.push(newDigit);\n        }\n    }\n    /**\n     * Remove digits from component\n     * @param numOfDigits\n     */\n    protected removeDigits(numOfDigits: number): void {\n        if (numOfDigits != 0) {\n            this.shouldFormatDigits = true;\n        }\n        for (let i: number = 0; i < numOfDigits; i++) {\n            this.removeChild(this.arrayDigits[this.arrayDigits.length - 1]);\n            this.arrayDigits[this.arrayDigits.length - 1].destroy();\n            this.arrayDigits.pop();\n        }\n    }\n    /**\n     *\n     * @param value Use this method when want to visualize value without bang up for first time\n     */\n    public setValue(value: number): void {\n        if (this.moneyText === undefined) {\n            const moneyConfig: MoneyTextConfig = new MoneyTextConfig();\n            this.moneyText = new MoneyText(moneyConfig, this.bangUpTo, new TextStyle({}));\n        }\n        this.goToValueAndStop(value);\n    }\n\n    public setStyle(textStyle: TextStyle): void {\n        this.textStyle = textStyle;\n        this.children.forEach((digitText: BitmapText) => {\n            digitText.fontSize = Number(textStyle.fontSize);\n        });\n        this.formatDigits();\n    }\n\n    public formatDigits(): void {\n        super.formatDigits();\n\n        this.x = this.bounds.x;\n        this.y = this.bounds.y;\n        this.RESCALE_JACKPOTS.next();\n    }\n\n    public setBounds(bounds: BangUpTextBounds) {\n        this.bounds = bounds;\n        this.formatDigits();\n    }\n\n    public setGsapParams(): void {\n        this.timeline?.kill();\n        this.timeline = null;\n        this.tmpObj.val = this.startFrom;\n        // A preset via setValue/goToValueAndStop moves the display without going\n        // through tickGsap, so force the first tick of every bang-up to render.\n        this.lastTickedValue = NaN;\n        const duration: number = this.bangUpTime / 1000;\n        this.timeline = (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"gsap:packages/slot-features/ui-lib/src/egt/ui/texts/JackpotBangUpBitMapText.ts:93:25\",null]), gsap.to(this.tmpObj, {\n            duration,\n            val: this.bangUpTo,\n            // Keep the odometer ticking at a constant rate instead of a fixed\n            // number of steps - with a short duration a fixed 225 steps lands\n            // finer than the frame rate and the discrete ticking is lost.\n            ease: `steps(${Math.max(1, Math.round(duration * this.stepsPerSecond))})`,\n            snap: {\n                val: 1,\n            },\n            onUpdate: () => {\n                this.tickGsap(this.tmpObj.val);\n            },\n            onComplete: () => {\n                this.onComplete();\n            },\n        }));\n    }\n\n    public tickGsap(newValue: number): void {\n        if (!this.bangingUp) {\n            this.timeline?.kill();\n            this.timeline = null;\n            return;\n        }\n        // gsap fires onUpdate every frame while the stepped ease only advances the\n        // value a handful of times per second, so most ticks carry the value that\n        // is already on screen. Re-formatting and re-laying out the digits for\n        // those is pure waste. Compare against the raw tween value rather than\n        // startFrom, which may have been clamped below.\n        if (this.lastTickedValue === newValue) {\n            return;\n        }\n        this.lastTickedValue = newValue;\n        this.startFrom = newValue;\n\n        if (this.bangDown) {\n            if (this.startFrom < this.bangUpTo) {\n                this.startFrom = this.bangUpTo;\n            }\n        } else {\n            if (this.startFrom > this.bangUpTo) {\n                // The target is below the displayed value (jackpot was won and\n                // reset to its seed). The display snaps to the target, so stop\n                // the tween — letting it run keeps feeding stale values into\n                // currentValue for the whole bangUpTime, and the next stats\n                // updates would start from a value that is no longer on screen.\n                this.startFrom = this.bangUpTo;\n                this.timeline?.kill();\n                this.timeline = null;\n            }\n        }\n        // currentValue must mirror what is actually displayed (the clamped\n        // value), not the raw tween value — callers pass it back as the next\n        // bang-up's starting point.\n        this.currentValue = this.startFrom;\n\n        const currentDigit: string = this.currentDigits();\n        if (this.arrayDigits.length < currentDigit.length) {\n            this.addDigit(currentDigit.length - this.arrayDigits.length);\n        } else if (this.arrayDigits.length > currentDigit.length) {\n            this.removeDigits(this.arrayDigits.length - currentDigit.length);\n        }\n\n        this.updateValue(currentDigit);\n\n        if (this.shouldFormatDigits) {\n            this.formatDigits();\n        }\n    }\n    public currentDigits(): string {\n        this.moneyText.money = this.startFrom;\n        return this.moneyText.moneyText;\n    }\n}\n","import Core, { Money } from '@egt/core';\nimport { Graphics, Text, TextMetrics, TextStyle } from 'pixi.js';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport ViewContainer from '../ViewContainer';\nimport MoneyTextConfig from './MoneyTextConfig';\nimport TextAlign from './TextAlign';\n\nexport default class MoneyText extends ViewContainer {\n    public readonly CLICK = new Subject();\n    public number: Text;\n    public exponent: Text;\n    public _currency: Text;\n    public moneyValues: Money;\n\n    protected moneyTextParts: any = {};\n\n    protected initialMoneyFontSize: number;\n    protected initialCentsFontSize: number;\n    protected initialCurrencyFontSize: number;\n    protected bounds: Graphics;\n\n    protected _moneyText: string;\n\n    private _textBounds: any = { width: 0, height: 0 };\n\n    private isCredits: boolean;\n\n    constructor(\n        protected _config: MoneyTextConfig,\n        _money: number,\n        protected _style?: any,\n    ) {\n        super();\n\n        this.moneyValues = new Money(_money);\n\n        this.moneyValues.MONEY_UPDATED.pipe(takeUntil(this.DESTROY)).subscribe(this.onMoneyUpdated.bind(this));\n\n        this.initialMoneyFontSize = _config.moneyFontSize;\n        this.initialCentsFontSize = _config.centsFontSize;\n        this.initialCurrencyFontSize = _config.currencyFontSize;\n\n        this._textBounds.width = _config.bounds.width;\n        this._textBounds.height = _config.bounds.height;\n\n        this.bounds = new Graphics();\n        this.bounds.beginFill(0xff0000);\n        this.bounds.alpha = this._config.debug ? 0.3 : 0;\n        this.bounds.drawRect(0, 0, this._config.bounds.width, this._config.bounds.height);\n        this.bounds.endFill();\n\n        this.addChild(this.bounds);\n\n        this.createNumber();\n        this.createExponent();\n        this.createCurrency();\n\n        this.setText();\n\n        // fromEvent(this, 'pointertap')\n        //     .pipe(takeUntil(this.DESTROY))\n        //     .subscribe(() => {\n        //         this.CLICK.next();\n        //     });\n    }\n\n    get moneyText(): string {\n        return this._moneyText;\n    }\n\n    get config(): MoneyTextConfig {\n        return this._config;\n    }\n\n    set config(value: MoneyTextConfig) {\n        this._config = value;\n        this.setText();\n    }\n\n    get moneyWithoutCents(): number {\n        return parseInt(this.number.text.replace(/\\s+/g, ''), 10);\n    }\n\n    get money(): number {\n        return this.moneyValues.amountMoney;\n    }\n\n    set money(value: number) {\n        this.moneyValues.amountMoney = value;\n        // this._money = value;\n        // this.setText();\n    }\n\n    get denomination(): number {\n        return this._config.denomination;\n    }\n\n    set denomination(value: number) {\n        this._config.denomination = value;\n        // this.setText();\n    }\n\n    get currency(): string {\n        return this._config.currency;\n    }\n\n    set currency(value: string) {\n        this._config.currency = value;\n        this.setText();\n    }\n\n    get showCurrency(): boolean {\n        return this._config.showCurrency;\n    }\n\n    set showCurrency(value: boolean) {\n        this._config.showCurrency = value;\n        this.setText();\n    }\n\n    get showCredits(): boolean {\n        return this._config.showCredits;\n    }\n\n    set showCredits(value: boolean) {\n        this._config.showCredits = value;\n        this.setText();\n    }\n\n    get moneyFontSize(): number {\n        return this._config.moneyFontSize;\n    }\n\n    set moneyFontSize(value: number) {\n        this._config.moneyFontSize = value;\n        this.setText();\n    }\n\n    get centsFontSize(): number {\n        return this._config.centsFontSize;\n    }\n\n    set centsFontSize(value: number) {\n        this._config.centsFontSize = value;\n        this.setText();\n    }\n\n    get currencyFontSize(): number {\n        return this._config.currencyFontSize;\n    }\n\n    set currencyFontSize(value: number) {\n        this._config.currencyFontSize = value;\n        this.setText();\n    }\n\n    get spaceBetweenMoneyAndCents(): number {\n        return this._config.spaceBetweenMoneyAndCents;\n    }\n\n    set spaceBetweenMoneyAndCents(value: number) {\n        this._config.spaceBetweenMoneyAndCents = value;\n        this.setText();\n    }\n\n    get spaceBetweenMoneyAndCurrency(): number {\n        return this._config.spaceBetweenMoneyAndCurrency;\n    }\n\n    set spaceBetweenMoneyAndCurrency(value: number) {\n        this._config.spaceBetweenMoneyAndCurrency = value;\n        this.setText();\n    }\n\n    get centerAlignOnlyMoney(): boolean {\n        return this._config.centerAlignOnlyMoney;\n    }\n\n    set centerAlignOnlyMoney(value: boolean) {\n        this._config.centerAlignOnlyMoney = value;\n        this.setText();\n    }\n\n    get shouldHideWhenMoneyValueIsZero(): boolean {\n        return this._config.shouldHideWhenMoneyValueIsZero;\n    }\n\n    set shouldHideWhenMoneyValueIsZero(value: boolean) {\n        this._config.shouldHideWhenMoneyValueIsZero = value;\n        this.setText();\n    }\n\n    get textColor(): string | number {\n        let color: string = '';\n        if (this._style) {\n            color = this._style.fill;\n        }\n        return color;\n    }\n\n    set textColor(value: string | number) {\n        if (this._style) {\n            this._style.fill = value;\n            this.number.style.fill = value;\n            this.exponent.style.fill = value;\n            this._currency.style.fill = value;\n        }\n    }\n\n    get textBounds(): any {\n        return this._config.bounds;\n    }\n\n    set textBounds(values: any) {\n        this._config.bounds.width = values.width;\n        this._config.bounds.height = values.height;\n\n        this.fitToBounds();\n        this.positionTexts();\n    }\n\n    /**\n     * Position and align all inner text fields horizontally and vertically.\n     */\n    public positionTexts(): void {\n        // Align number horizontally.\n        if (this._config.align === TextAlign.LEFT) {\n            this.number.x = 0;\n        } else if (this._config.align === TextAlign.CENTER) {\n            let newX: number = this.getHorizontalFreeSpace() / 2;\n            const newXCenterAlignOnlyMoney: number = (this._config.bounds.width - this.number.width) / 2;\n            const newXCenterAlignOnlyMoneyWillFit: boolean =\n                this._config.bounds.width >= this.getTotalWidth() + newXCenterAlignOnlyMoney;\n            if (this._config.centerAlignOnlyMoney && newXCenterAlignOnlyMoneyWillFit) {\n                newX = newXCenterAlignOnlyMoney;\n            }\n            this.number.x = newX;\n        } else if (this._config.align === TextAlign.RIGHT) {\n            this.number.x = this.getHorizontalFreeSpace();\n        }\n\n        // Align number vertically.\n        this.number.y = (this.height - this.number.height) / 2;\n\n        const numberAscent: number = TextMetrics.measureFont((this.number.style as TextStyle).toFontString()).ascent;\n        const exponentAscent: number = TextMetrics.measureFont(\n            (this.exponent.style as TextStyle).toFontString(),\n        ).ascent;\n        const currencyAscent: number = TextMetrics.measureFont(\n            (this._currency.style as TextStyle).toFontString(),\n        ).ascent;\n\n        // Align exponent vertically and horizontally based on the number text field.\n        if (this.moneyTextParts.exponent) {\n            this.exponent.x = this.number.x + this.number.width + this._config.spaceBetweenMoneyAndCents;\n            this.exponent.y = this.number.y + numberAscent - exponentAscent;\n        }\n\n        // Align currency vertically and horizontally based on the number text field.\n        // console.log(this.name, this._config.spaceBetweenMoneyAndCents, this._config.spaceBetweenMoneyAndCurrency);\n        if (!this.isCredits && this.moneyTextParts.currency) {\n            this._currency.x =\n                this.number.x +\n                this.exponent.width +\n                this.number.width +\n                this._config.spaceBetweenMoneyAndCents +\n                this._config.spaceBetweenMoneyAndCurrency;\n            this._currency.y = this.number.y + numberAscent - currencyAscent;\n        }\n    }\n\n    public getMoneyTextValue(): string {\n        this.setMoneyText();\n        return this._moneyText;\n    }\n\n    public destroy(): void {\n        if (this.destroyed) {\n            return;\n        }\n        if (this._style) {\n            this._style = null;\n        }\n        this.removeChildren();\n        //* removeChildren() detaches the parts, so each one has to be destroyed explicitly - otherwise the canvas\n        //* texture PIXI generated for it stays uploaded. `number` was missing here, which leaked the biggest of the\n        //* three canvases on every MoneyText that gets thrown away (bang-up texts recreate them per round).\n        this.destroyPart(this.number);\n        this.destroyPart(this._currency);\n        this.destroyPart(this.exponent);\n        if (this.bounds && !this.bounds.destroyed) {\n            this.bounds.destroy();\n        }\n        this._textBounds = null;\n\n        // @ts-ignore\n        this._config = null;\n        super.destroy.apply(this, arguments);\n    }\n\n    /**\n     * PIXI Text destroys its own (canvas) texture and base texture by default, so a plain destroy() is enough -\n     * the guard is only there because a part may already be gone when destroy() is reached twice.\n     */\n    private destroyPart(part?: Text): void {\n        if (part && !part.destroyed) {\n            part.destroy();\n        }\n    }\n\n    /**\n     * Sets a display text based on the money and the configuration.\n     */\n    protected setText(): void {\n        // 1. Reset the text state.\n        this.resetText();\n\n        // 2. Sets the money text based on the money and the money config.\n        this.setMoneyText();\n\n        // 3. Set all inner text fields based on the money text parts.\n        this.number.text = this.moneyTextParts.number;\n        this.number.resolution = 2;\n\n        if (this.moneyTextParts.exponent) {\n            this.exponent.text = '.' + this.moneyTextParts.exponent;\n        }\n\n        if (this.moneyTextParts.currency) {\n            this._currency.text = this.moneyTextParts.currency;\n        }\n\n        // 4. Ensure texts fit to bounds.\n        this.fitToBounds();\n\n        // 5. Align and position.\n        this.positionTexts();\n\n        // 6. Set visibility.\n        if (this._config.shouldHideWhenMoneyValueIsZero && this.money === 0) {\n            this.visible = false;\n        } else {\n            this.visible = true;\n        }\n    }\n\n    /**\n     * Resets the text in the money field to empty string.\n     */\n    protected resetText(): void {\n        this._moneyText = '';\n        this.moneyTextParts = {};\n        this.number.text = '';\n        this.exponent.text = '';\n        this._currency.text = '';\n        this.number.style.fontSize = this.initialMoneyFontSize;\n        this.exponent.style.fontSize = this.initialCentsFontSize;\n        this._currency.style.fontSize = this.initialCurrencyFontSize;\n    }\n\n    /**\n     * Creates a formatted money text based on the money property.\n     * Separate parts are stored in _moneyTextParts.\n     *\n     * E.g.\n     * 107894 money with currency \"EUR\" will be formatted to: \"107 894.00 EUR\"\n     */\n    protected setMoneyText(): void {\n        const money: number = this.moneyValues.amountMoney || 0;\n        let formatted: string = money.toString();\n        // Convert credits to money\n        if (!this._config.showCredits) {\n            // formatted = (money / this._config.units).toFixed(2).toString();\n            // if selected mode is currency or we do not change value when mode is changed\n            if (!Core.MONEY_MODE_IN_CREDITS.value || !this._config.useMoneyMode) {\n                formatted = this.moneyValues.amountMoney.toFixed(2);\n                this.isCredits = false;\n            } else {\n                formatted = this.moneyValues.amountCredits.toString();\n                this.isCredits = true;\n            }\n        } else {\n            // credits are rounded down\n            // if selected mode is credit or we do not change value when mode is changed\n            if (!Core.MONEY_MODE_IN_CREDITS.value || !this._config.useMoneyMode) {\n                formatted = this.moneyValues.amountCredits.toString();\n                this.isCredits = true;\n            } else {\n                formatted = this.moneyValues.amountMoney.toFixed(2);\n                this.isCredits = false;\n            }\n            // formatted = Math.floor(money / this._config.denomination).toString();\n        }\n        // console.log(\"***\",this.name, this.moneyValues, this._config.showCredits, this.isCredits, formatted);\n\n        // if (!this._config.showCredits) {\n        //     formatted = this.moneyValues.amountMoney.toFixed(2).toString();\n        // } else {\n        //     formatted = this.moneyValues.amountCredits.toString();\n        //     // formatted = ((this.money || 0) / this._config.denomination).toString();\n        // }\n\n        // Split floating point numbers to avoid formatting of the numbers after the floating point.\n        const splitted: string[] = formatted.split('.');\n        formatted = splitted[0];\n        let exponent = '';\n        if (splitted[1]) {\n            exponent = this._config.showRoundedValue ? '00' : splitted[1];\n            this.moneyTextParts.exponent = exponent;\n        }\n\n        // Split value into chunks of 3 characters.\n        const matches: string[] | null = formatted.match(/(\\d+?)(?=(\\d{3})+(?!\\d)|$)/g);\n        if (matches) {\n            formatted = matches.join(' ');\n        }\n        this.moneyTextParts.number = formatted;\n        if (exponent) {\n            formatted += '.' + exponent;\n        }\n\n        if (!this.isCredits && this._config.showCurrency && this._config.currency) {\n            formatted += ' ' + this._config.currency;\n            this.moneyTextParts.currency = this._config.currency;\n            if (!this.find('currency')) {\n                this.createCurrency();\n            }\n        } else {\n            this.removeChild(this._currency);\n        }\n\n        this._moneyText = formatted;\n    }\n\n    /**\n     * Recursively change fontSize to enforce the text to fit to the bounds.\n     */\n    protected fitToBounds(): void {\n        if (!this._config.shouldFitInBounds) {\n            return;\n        }\n\n        const totalWidth: number = this.getTotalWidth();\n        const fontSize: number = this.number.style.fontSize as number;\n\n        if (totalWidth > this._config.bounds.width && fontSize > this._config.minFontSize) {\n            const newFontSize = Math.floor(fontSize * (this._config.bounds.width / totalWidth));\n            this.number.style.fontSize = newFontSize;\n\n            this._calculateNewFontSize(this.exponent, fontSize, newFontSize);\n            this._calculateNewFontSize(this._currency, fontSize, newFontSize);\n\n            this.fitToBounds();\n        }\n    }\n\n    /**\n     * If the font sizes of the exponent and currency are equal to the number font, then directly set them to the same number.\n     * Else calculate the difference.\n     */\n    protected _calculateNewFontSize(text: Text, baseFontSize: number, newFontSize: number): void {\n        if (text.style.fontSize === baseFontSize) {\n            text.style.fontSize = newFontSize;\n        } else {\n            const fontSize: number = text.style.fontSize as number;\n            text.style.fontSize = fontSize - Math.round((baseFontSize - newFontSize) / (baseFontSize / fontSize));\n        }\n    }\n\n    /**\n     * Returns the total width used by all text fields.\n     */\n    protected getTotalWidth(): number {\n        let width: number = this.number.width;\n\n        if (this.moneyTextParts.exponent) {\n            width += this.exponent.width + this._config.spaceBetweenMoneyAndCents;\n        }\n        if (!this.isCredits && this.moneyTextParts.currency) {\n            width += this._currency.width + this._config.spaceBetweenMoneyAndCurrency;\n        }\n\n        return width;\n    }\n\n    /**\n     * Returns the horizontal free space.\n     */\n    protected getHorizontalFreeSpace(): number {\n        let freeSpace: number = this._config.bounds.width - this.number.width;\n\n        if (this.moneyTextParts.exponent) {\n            freeSpace -= this.exponent.width;\n            freeSpace -= this._config.spaceBetweenMoneyAndCents;\n        }\n        if (!this.isCredits && this.moneyTextParts.currency) {\n            freeSpace -= this._currency.width;\n            freeSpace -= this._config.spaceBetweenMoneyAndCurrency;\n        }\n\n        return freeSpace;\n    }\n\n    protected createNumber(): void {\n        this.number = this._style ? new Text('', this._style.clone()) : new Text('');\n        this.number.style.fontSize = this.initialMoneyFontSize;\n\n        this.addChild(this.number);\n    }\n\n    protected createExponent(): void {\n        this.exponent = this._style ? new Text('', this._style.clone()) : new Text('');\n        this.exponent.style.fontSize = this.initialCentsFontSize;\n        this.exponent.resolution = 2;\n\n        this.addChild(this.exponent);\n    }\n\n    protected createCurrency(): void {\n        //* setMoneyText() only detaches the currency Text when switching to credits, so on the way back this\n        //* method is reached with the previous instance still referenced. Free it before reassigning, otherwise\n        //* every money-mode toggle orphans one canvas texture that destroy() can no longer reach.\n        this.destroyPart(this._currency);\n        this._currency = this._style ? new Text('', this._style.clone()) : new Text('');\n        this._currency.style.fontSize = this.initialCurrencyFontSize;\n        this._currency.resolution = 2;\n\n        this.addChild(this._currency);\n        this._currency.name = 'currency';\n    }\n\n    private onMoneyUpdated(): void {\n        // console.log(this.name, this.moneyValues);\n        this.setText();\n    }\n\n    // private setMoneyValue(): string {\n    //     const money: number = this.money || 0;\n    //     let formatted: string = money.toString();\n    //     // Convert credits to money\n    //     if (!this._config.showCredits) {\n    //         formatted = (money / this._config.units).toFixed(2).toString();\n    //     } else {\n    //         formatted = (money / this._config.denomination).toString();\n    //     }\n\n    //     // Split floating point numbers to avoid formatting of the numbers after the floating point.\n    //     const splitted: string[] = formatted.split('.');\n    //     formatted = splitted[0];\n    //     let exponent = '';\n    //     if (splitted[1]) {\n    //         this._config.showRoundedValue ? (exponent = '00') : (exponent = splitted[1]);\n    //         this.moneyTextParts.exponent = exponent;\n    //     }\n\n    //     // Split value into chunks of 3 characters.\n    //     const matches: string[] | null = formatted.match(/(\\d+?)(?=(\\d{3})+(?!\\d)|$)/g);\n    //     if (matches) {\n    //         formatted = matches.join(' ');\n    //     }\n    //     this.moneyTextParts.number = formatted;\n    //     if (exponent) {\n    //         formatted += '.' + exponent;\n    //     }\n    //     return formatted;\n    // }\n}\n","import TextConfig from './TextConfig';\n\nexport default class MoneyTextConfig extends TextConfig {\n    protected _moneyFontSize: number = 24;\n    protected _centsFontSize: number = 24;\n    protected _currencyFontSize: number = 12;\n    protected _spaceBetweenMoneyAndCents: number = -1;\n    protected _spaceBetweenMoneyAndCurrency: number = 2;\n    protected _shouldHideWhenMoneyValueIsZero: boolean = false;\n    protected _showCurrency: boolean = true;\n    protected _units: number = 100;\n    protected _showRoundedValue: boolean = false;\n    protected _shouldFitInBoundsBothDimensions?: boolean;\n    /**\n     * If true change mode affect this moneytext field and value is changed when\n     * MONEY_MODE_IN_CURRENCY mode is chganged\n     * If false allways use _showCredits setting and do not change on mode change\n     */\n    protected _useMoneyMode: boolean = false;\n\n    /**\n     * If true show the _money in unformatted string.\n     * E.g. 1000 _money should be visualized as \"1000\" when true\n     * If false show \"10 Eur\"\n     */\n    protected _showCredits: boolean = false;\n\n    /**\n     * The currency symbol to put at the end of the string.\n     */\n    protected _currency: string = '';\n\n    /**\n     * The real currency is calculated based on the money and denomination values.\n     * If denomination is 2 and money is 1000 the real currency value will be 500.\n     */\n    protected _denomination: number = 1;\n\n    /**\n     * Should the center alignement be based on the money only or both the money and currency.\n     */\n    protected _centerAlignOnlyMoney: boolean = false;\n\n    get denomination(): number {\n        return this._denomination;\n    }\n\n    set denomination(value: number) {\n        this._denomination = value;\n    }\n\n    get currency(): string {\n        return this._currency;\n    }\n\n    set currency(value: string) {\n        this._currency = value;\n    }\n\n    get showCurrency(): boolean {\n        return this._showCurrency;\n    }\n\n    set showCurrency(value: boolean) {\n        this._showCurrency = value;\n    }\n\n    get showCredits(): boolean {\n        return this._showCredits;\n    }\n\n    set showCredits(value: boolean) {\n        this._showCredits = value;\n    }\n\n    get useMoneyMode(): boolean {\n        return this._useMoneyMode;\n    }\n\n    set useMoneyMode(value: boolean) {\n        this._useMoneyMode = value;\n    }\n\n    get moneyFontSize(): number {\n        return this._moneyFontSize;\n    }\n\n    set moneyFontSize(value: number) {\n        this._moneyFontSize = value;\n    }\n\n    get centsFontSize(): number {\n        return this._centsFontSize;\n    }\n\n    set centsFontSize(value: number) {\n        this._centsFontSize = value;\n    }\n\n    get currencyFontSize(): number {\n        return this._currencyFontSize;\n    }\n\n    set currencyFontSize(value: number) {\n        this._currencyFontSize = value;\n    }\n\n    get spaceBetweenMoneyAndCents(): number {\n        return this._spaceBetweenMoneyAndCents;\n    }\n\n    set spaceBetweenMoneyAndCents(value: number) {\n        this._spaceBetweenMoneyAndCents = value;\n    }\n\n    get spaceBetweenMoneyAndCurrency(): number {\n        return this._spaceBetweenMoneyAndCurrency;\n    }\n\n    set spaceBetweenMoneyAndCurrency(value: number) {\n        this._spaceBetweenMoneyAndCurrency = value;\n    }\n\n    get centerAlignOnlyMoney(): boolean {\n        return this._centerAlignOnlyMoney;\n    }\n\n    set centerAlignOnlyMoney(value: boolean) {\n        this._centerAlignOnlyMoney = value;\n    }\n\n    get shouldHideWhenMoneyValueIsZero(): boolean {\n        return this._shouldHideWhenMoneyValueIsZero;\n    }\n\n    set shouldHideWhenMoneyValueIsZero(value: boolean) {\n        this._shouldHideWhenMoneyValueIsZero = value;\n    }\n\n    get units(): number {\n        return this._units;\n    }\n\n    set units(value: number) {\n        this._units = value;\n    }\n\n    get showRoundedValue(): boolean {\n        return this._showRoundedValue;\n    }\n\n    set showRoundedValue(value: boolean) {\n        this._showRoundedValue = value;\n    }\n\n    get shouldFitInBoundsBothDimensions(): boolean | undefined {\n        return this._shouldFitInBoundsBothDimensions;\n    }\n\n    set shouldFitInBoundsBothDimensions(value: boolean | undefined) {\n        this._shouldFitInBoundsBothDimensions = value;\n    }\n}\n","import { Graphics, Text as PIXIText, TextStyle, TextMetrics } from 'pixi.js';\nimport ViewContainer from '../ViewContainer';\nimport { ITextConfig } from './ITextConfig';\nimport TextAlign from './TextAlign';\nimport VerticalTextAlign from './VerticalTextAlign';\n\nexport default class Text extends ViewContainer {\n    // @ts-ignore\n    public x: number;\n    // @ts-ignore\n    public y: number;\n    // @ts-ignore\n    public width: number;\n    // @ts-ignore\n    public height: number;\n    private _textBounds: any = { width: 0, height: 0 };\n    private _text: PIXIText;\n    private _originalFontSize: number;\n    private _debugRectBounds;\n    constructor(\n        protected _config: ITextConfig,\n        text?: string,\n        style?: any,\n    ) {\n        super();\n\n        if (text === undefined) {\n            text = '';\n        }\n        this._text = new PIXIText(text, style);\n        this._originalFontSize = this._text.style.fontSize as number;\n        this._textBounds.width = _config.bounds.width;\n        this._textBounds.height = _config.bounds.height;\n        this._text.resolution = 2;\n\n        if (this._config.debug) {\n            this._debugRectBounds = new Graphics();\n            this._debugRectBounds.beginFill(0xff0000, 0.3);\n            this._debugRectBounds.drawRect(0, 0, this._config.bounds.width, this._config.bounds.height);\n            this._debugRectBounds.endFill();\n\n            this.addChild(this._debugRectBounds);\n        }\n\n        this.addChild(this._text);\n\n        this._fitToBounds();\n        this._alignText();\n    }\n\n    get textWidth(): number {\n        return this._text.width;\n    }\n\n    get text(): string {\n        return this._text.text;\n    }\n\n    set text(value: string) {\n        if (value !== this._text.text) {\n            this._text.text = value;\n\n            this._fitToBounds();\n            this._alignText();\n        }\n    }\n\n    get style(): TextStyle {\n        return this._text.style as TextStyle;\n    }\n\n    set style(value: TextStyle) {\n        this._text.style = new TextStyle(value);\n\n        this._originalFontSize = this._text.style.fontSize as number;\n\n        this._fitToBounds();\n        this._alignText();\n    }\n\n    get config(): ITextConfig {\n        return this._config;\n    }\n\n    set config(value: ITextConfig) {\n        this._config = value;\n        this._fitToBounds();\n        this._alignText();\n    }\n\n    get textBounds(): any {\n        return this._config.bounds;\n    }\n\n    set textBounds(values: any) {\n        this._config.bounds.width = values.width;\n        this._config.bounds.height = values.height;\n        if (this._config.debug) {\n            this.removeChild(this._debugRectBounds);\n            this._debugRectBounds = new Graphics();\n            this._debugRectBounds.beginFill(0xff0000, 0.3);\n            this._debugRectBounds.drawRect(0, 0, this._config.bounds.width, this._config.bounds.height);\n            this._debugRectBounds.endFill();\n            if (this._config.verticalAlign === VerticalTextAlign.ALIGN_BASELINE) {\n                this._debugRectBounds.y = this._debugRectBounds.y - this._config.bounds.height;\n            }\n            this.addChild(this._debugRectBounds);\n        }\n        this._fitToBounds();\n        this._alignText();\n    }\n\n    public tintText(tintColor: number) {\n        this._text.tint = tintColor;\n    }\n\n    public destroy(): void {\n        this._text.destroy({ children: true, texture: true, baseTexture: true });\n        this._textBounds = null;\n        // @ts-ignore\n        delete this._text;\n        super.destroy();\n    }\n    /**\n     * Fits text in to the bounds defined by TextConfiguration by decreasing text font size\n     * until it fits. This happens only when shouldFitInBounds  property from TextConfiguration is set to true.\n     * At the current implementation fitting is done only by width.\n     * @private\n     */\n    protected _fitToBounds(): void {\n        if (!this._config.shouldFitInBounds) {\n            return;\n        }\n\n        this._text.style.fontSize = this._originalFontSize;\n        let currentSize = this._originalFontSize;\n        this._text.style = this._text.style;\n\n        let fontSize: number = this._text.style.fontSize as number;\n\n        if (this._config.shouldFitInBoundsBothDimensions) {\n            while (this._text.width > this._config.bounds.width) {\n                currentSize -= 1;\n                this._text.style.fontSize = currentSize;\n                this._text.style.lineHeight = currentSize;\n                this._text.style = this._text.style;\n            }\n            while (this._text.height > this._config.bounds.height) {\n                currentSize -= 1;\n                this._text.style.fontSize = currentSize;\n                this._text.style.lineHeight = currentSize;\n                this._text.style = this._text.style;\n            }\n        } else if (this._text.width > this._config.bounds.width && fontSize > this._config.minFontSize) {\n            fontSize = Math.floor(fontSize * (this._config.bounds.width / this._text.width));\n            this._text.style.fontSize = fontSize;\n            this._text.style.lineHeight = fontSize;\n            this._text.style = this._text.style;\n        }\n    }\n\n    /**\n     * Aligns the text accordingly to the passed configuration.\n     * @private\n     */\n    protected _alignText(): void {\n        if (this._config.align === TextAlign.LEFT) {\n            this._text.x = 0;\n        } else if (this._config.align === TextAlign.CENTER) {\n            this._text.x = Math.round(this._config.bounds.width - this._text.width) / 2;\n        } else if (this._config.align === TextAlign.RIGHT) {\n            this._text.x = this._config.bounds.width - this._text.width;\n        }\n\n        if (this._config.verticalAlign === VerticalTextAlign.CENTER) {\n            this._text.y = Math.round(this._config.bounds.height - this._text.height) / 2;\n        } else if (this._config.verticalAlign === VerticalTextAlign.TOP) {\n            this._text.y = 0;\n        } else if (this._config.verticalAlign === VerticalTextAlign.BOTTOM) {\n            this._text.y = this._config.bounds.height - this._text.height;\n        } else if (this._config.verticalAlign === VerticalTextAlign.ALIGN_BASELINE) {\n            const metrics = TextMetrics.measureFont((this._text.style as any).toFontString());\n            this._text.anchor.set(0, metrics.ascent / metrics.fontSize);\n        }\n    }\n}\n","const enum TextAlign {\n    CENTER,\n    LEFT,\n    RIGHT,\n}\nexport default TextAlign;\n","import { Rectangle } from 'pixi.js';\nimport { ITextConfig } from './ITextConfig';\nimport TextAlign from './TextAlign';\nimport VerticalTextAlign from './VerticalTextAlign';\n\nexport default class TextConfig implements ITextConfig {\n    protected _bounds: Rectangle = new Rectangle(0, 0, 100, 50);\n    protected _align: TextAlign = TextAlign.LEFT;\n    protected _verticalAlign: VerticalTextAlign = VerticalTextAlign.CENTER;\n    protected _shouldFitInBounds: boolean = false;\n    protected _minFontSize: number = 4;\n    protected _debug: boolean = false;\n\n    get bounds(): Rectangle {\n        return this._bounds;\n    }\n\n    set bounds(value: Rectangle) {\n        this._bounds = value;\n    }\n\n    get align(): TextAlign {\n        return this._align;\n    }\n\n    set align(value: TextAlign) {\n        this._align = value;\n    }\n\n    get verticalAlign(): VerticalTextAlign {\n        return this._verticalAlign;\n    }\n\n    set verticalAlign(value: VerticalTextAlign) {\n        this._verticalAlign = value;\n    }\n    get shouldFitInBounds(): boolean {\n        return this._shouldFitInBounds;\n    }\n\n    set shouldFitInBounds(value: boolean) {\n        this._shouldFitInBounds = value;\n    }\n\n    get minFontSize(): number {\n        return this._minFontSize;\n    }\n\n    set minFontSize(value: number) {\n        this._minFontSize = value;\n    }\n\n    get debug(): boolean {\n        return this._debug;\n    }\n\n    set debug(value: boolean) {\n        this._debug = value;\n    }\n}\n","import { Text } from 'pixi.js';\n\n// alpha above which a pixel counts as ink\nconst INK_ALPHA_THRESHOLD = 8;\n\n/** Shrink a text that a translation made wider than the space it has, so it never hangs outside its frame. */\nexport function fitInWidth(text: Text, maxWidth: number): void {\n    text.scale.set(1);\n    if (text.width > maxWidth) {\n        text.scale.set(maxWidth / text.width);\n    }\n}\n\n/**\n * Where the glyphs actually put ink inside the text box, in unscaled local units. The box itself says\n * nothing about the room a line needs: CJK fills the whole em square while Latin caps leave a third of\n * it empty, and diacritics sit above cap height.\n */\nexport function inkBounds(text: Text): { top: number; bottom: number } {\n    const pixels = text.context.getImageData(0, 0, text.canvas.width, text.canvas.height).data;\n    let top = -1;\n    let bottom = -1;\n    for (let y = 0; y < text.canvas.height; y++) {\n        for (let x = 0; x < text.canvas.width; x++) {\n            if (pixels[(y * text.canvas.width + x) * 4 + 3] > INK_ALPHA_THRESHOLD) {\n                if (top < 0) {\n                    top = y;\n                }\n                bottom = y;\n                break;\n            }\n        }\n    }\n\n    if (top < 0) {\n        return { top: 0, bottom: 0 };\n    }\n\n    return { top: top / text.resolution, bottom: (bottom + 1) / text.resolution };\n}\n\n/**\n * Shrink a text until its ink ends above `limit`, leaving its position alone. For a block that grows\n * downwards from a fixed top - a wrapped paragraph that takes an extra line in longer languages.\n */\nexport function fitAbove(text: Text, limit: number): void {\n    const inkBottom = text.y + inkBounds(text).bottom * text.scale.y;\n    if (inkBottom > limit) {\n        text.scale.set((text.scale.x * (limit - text.y)) / (inkBottom - text.y));\n    }\n}\n\n/**\n * Centre a text in the vertical gap its neighbours leave, shrinking it when its ink does not fit.\n * A line placed by its font box overlaps the lines around it in zh-cn and sv.\n */\nexport function fitInBand(text: Text, top: number, bottom: number): void {\n    const ink = inkBounds(text);\n    const band = bottom - top;\n    if ((ink.bottom - ink.top) * text.scale.y > band) {\n        text.scale.set((text.scale.x * band) / ((ink.bottom - ink.top) * text.scale.y));\n    }\n    text.y = top + (band - (ink.bottom - ink.top) * text.scale.y) / 2 - ink.top * text.scale.y;\n}\n","const enum VerticalTextAlign {\n    CENTER,\n    TOP,\n    BOTTOM,\n    ALIGN_BASELINE,\n}\nexport default VerticalTextAlign;\n","import PriorityPositionObject from './slots/PriorityPositionObject';\nimport PriorityTextStyle from './slots/PriorityTextStyle';\nimport SlotGame from './slots/SlotGame';\n// import UIAutoPlayController from '../../../slot-components/ui-view/src/egt/controllers/UIAutoPlayController';\nimport CustomInfinityPlayController from './slots/components/custom-result/CustomInfinityPlayController';\nimport CustomResultSlotController from './slots/components/custom-result/CustomResultSlotController';\nimport CustomResultSlotView from './slots/components/custom-result/CustomResultSlotView';\nimport CustomResultStore from './slots/components/custom-result/CustomResultStore';\nimport CustomResultBotContentView from './slots/components/custom-result/views/CustomResultBotContentView';\nimport CustomResultCustomContentView from './slots/components/custom-result/views/CustomResultCustomContentView';\nimport CustomResultScenarioContentView from './slots/components/custom-result/views/CustomResultScenarioContentView';\nimport CustomResultSettingsContentView from './slots/components/custom-result/views/CustomResultSettingsContentView';\nimport ScenarioViewer from './slots/components/custom-result/ScenarioViewer';\nimport BaseResponse from './slots/components/data/BaseResponse';\nimport BetRequest from './slots/components/data/BetRequest';\nimport BetResponse from './slots/components/data/BetResponse';\nimport BonusTypes from './slots/components/data/BonusTypes';\nimport CollectRequest from './slots/components/data/CollectRequest';\nimport CollectResponse from './slots/components/data/CollectResponse';\nimport DomainStore from './slots/components/data/DomainStore';\nimport FreeSpinRestoreRequest from './slots/components/data/FreeSpinRestoreRequest';\nimport InitialSettings from './slots/components/data/InitialSettings';\nimport JackpotWin from './slots/components/data/JackpotWin';\nimport MessBarTypes from './slots/components/data/MessBarTypes';\nimport PriorityList from './slots/components/data/PriorityList';\nimport RestoreResponse from './slots/components/data/RestoreResponse';\nimport ServerState from './slots/components/data/ServerState';\nimport SpinAnalyzer from './slots/components/data/SpinAnalyzer';\nimport Subjects from './slots/components/data/Subjects';\n// import DemoModeController from '../../../slot-components/demo-mode/src/egt/controllers/DemoModeController';\n// import DemoModeView from './slots/components/demo/DemoModeView';\n// import DenominationController from './slots/components/denomination/DenominationController';\n// import DenominationView from './slots/components/denomination/DenominationView';\nimport AnalyticsState from './slots/components/enums/AnalyticsState';\nimport RootElementsAnimationTypes from './slots/components/enums/RootElementsAnimationTypes';\nimport SlotComponents from './slots/components/enums/SlotComponents';\nimport SlotGameLayouts from './slots/SlotGameLayouts';\nimport ZOrders from './slots/components/enums/ZOrders';\nimport FeatureController from './slots/components/feature/FeatureController';\nimport Features from './slots/components/feature/Features';\nimport CentralWinActions from './slots/components/enums/CentralWinActions';\nimport { IFeatureModule } from './slots/components/feature/IFeatureModule';\nimport { IBrandingConfiguration } from './slots/components/interfaces/IBrandingConfiguration';\nimport { IBrandlogoPosition } from './slots/components/interfaces/IBrandLogoPosition';\nimport { IDenomButtonStyle } from './slots/components/interfaces/IDenomButtonStyle';\nimport { IDenomOptionButtonConfig } from './slots/components/interfaces/IDenomOptionButtonConfig';\nimport { ISpin } from './slots/components/interfaces/ISpin';\nimport { ISpinBonus } from './slots/components/interfaces/ISpinBonus';\nimport { ISpinEntry } from './slots/components/interfaces/ISpinEntry';\nimport { ISpinMutation } from './slots/components/interfaces/ISpinMutation';\nimport Line from './slots/components/lines/Line';\nimport LineMode from './slots/components/lines/LineMode';\nimport LinesView from './slots/components/lines/LinesView';\nimport LinesViewDesktop from './slots/components/lines/LinesViewDesktop';\n// import UIMainPanelController from './slots/components/main-panel/UIMainPanelController';\n// import UIMainPanelControllerDesktop from './slots/components/main-panel/UIMainPanelControllerDesktop';\n// import UIMainView from './slots/components/main-panel/UIMainView';\n// import UIMainViewDesktop from './slots/components/main-panel/UIMainViewDesktop';\n// import MessageBarAlert from './slots/components/message-bar/MessageBarAlert';\n// import MessageBarView from '../../../slot-components/message-bar/src/egt/views/MessageBarView';\n// import ModalBackground from '../../../slot-components/clock copy/src/egt/views/ModalBackground';\n// import Popup from './slots/components/popup/Popup';\n// import PopupController from '../../../slot-components/popup-visualizer/src/egt/controllers/PopupController';\n// import PopupControllerDesktop from '../../../slot-components/popup-visualizer/src/egt/controllers/PopupControllerDesktop';\n// import PopupDesktop from './slots/components/popup/PopupDesktop';\n// import PopupPosition from '../../../slot-components/popup-visualizer/src/egt/enums/PopupPosition';\n// import SmallPopup from './slots/components/popup/SmallPopup';\n// import IReels from '../../../slot-components/reels/src/egt/interfaces/IReels';\n// import IReelsView from './slots/components/reels/IReelsView';\n// import Reel from './slots/components/reels/Reel';\n// import ReelsControllerDefault from './slots/components/reels/ReelsControllerDefault';\n// import ReelState from './slots/components/reels/ReelState';\n// import ReelsViewDefault from './slots/components/reels/ReelsViewDefault';\n// import ReelsViewDesktopDefault from './slots/components/reels/ReelsViewDesktopDefault';\nimport RestoreController from './slots/components/restore/RestoreController';\nimport RootController from './slots/components/root/RootController';\nimport RootStore from './slots/components/root/RootStore';\nimport RootView from './slots/components/root/RootView';\n// import RootViewDesktop from './slots/components/root/RootViewDesktop';\n// import BetSettingsView from './slots/components/settings/settings-views/bet/BetSettingsView';\n// import BetSettingsViewDesktop from './slots/components/settings/settings-views/bet/BetSettingsViewDesktop';\n// import GeneralSettingsView from './slots/components/settings/settings-views/general/GeneralSettingsView';\n// import HelpView from './slots/components/settings/settings-views/help/HelpView';\n// import HelpViewDesktop from './slots/components/settings/settings-views/help/HelpViewDesktop';\n// import PaytableHTMLView from './slots/components/settings/settings-views/paytableHTML/PaytableHTMLView';\n// import PaytableScript from './slots/components/settings/settings-views/paytableHTML/PaytableScript';\n// import SpinSettingsView from './slots/components/settings/settings-views/spin/SpinSettingsView';\n// import SpinSettingsViewDesktop from './slots/components/settings/settings-views/spin/SpinSettingsViewDesktop';\n// import SettingsController from './slots/components/settings/SettingsController';\n// import SettingsControllerDesktop from './slots/components/settings/SettingsControllerDesktop';\n// import SettingsTab from './slots/components/settings/SettingsTab';\n// import SettingsView from './slots/components/settings/SettingsView';\n// import SettingsViewDesktop from './slots/components/settings/SettingsViewDesktop';\nimport StopVideoView from './slots/components/stop-video/StopVideoView';\nimport { INonProportionalSymbol, ITexturesMapObject } from './slots/components/symbols/INonProportionalSymbol';\nimport { ISymbol } from './slots/components/symbols/ISymbol';\nimport { ISymbolPosition } from './slots/components/symbols/ISymbolPosition';\nimport NonProportionalSymbolBase from './slots/components/symbols/NonProportionalSymbolBase';\nimport SymbolBase from './slots/components/symbols/SymbolBase';\nimport BangupActionConsts from './slots/components/ui/BangupActionConsts';\nimport SpinSpeedIndicator from './slots/components/ui/SpinSpeedIndicator';\n// import UIManualController from './slots/components/ui/UIManualController';\n// import UIManualControllerDesktop from './slots/components/ui/UIManualControllerDesktop';\nimport UIState from './slots/components/ui/UIState';\nimport UIStore from './slots/components/ui/UIStore';\nimport { ISlotConfiguration } from './slots/slot-configuration/ISlotConfiguration';\nimport SlotConfiguration from './slots/slot-configuration/SlotConfiguration';\n// import CashHeatTemplate from './slots/templates/CashHeatTemplate';\n// import CascadeTemplate from './slots/templates/CascadeTemplate';\n// import HighCashTemplate from './slots/templates/HighCashTemplate';\nimport SingleProgressiveTemplate from './slots/templates/SingleProgressiveTemplate';\nimport SlotTemplate, {\n    getComponentModeByLayout,\n    getFeatureModeByLayout,\n    getSlotLayout,\n} from './slots/templates/SlotTemplate';\nimport { ITemplateSlotConfiguration } from './slots/templates/ITemplateSlotConfiguration';\nimport HistorySubject from './slots/components/data/HistorySubject';\n\nexport {\n    // IBackgroundAssets,\n    AnalyticsState,\n    // IBackgroundAssets,\n    BangupActionConsts,\n    BaseResponse,\n    // CascadeTemplate,\n    // HighCashTemplate,\n    BetRequest,\n    BetResponse,\n    BonusTypes,\n    // CashHeatTemplate,\n    // SettingsController,\n    // SettingsControllerDesktop,\n    CollectRequest,\n    CollectResponse,\n    // MessageBarView,\n    // MessageBarAlert,\n    CustomInfinityPlayController,\n    CustomResultBotContentView,\n    CustomResultCustomContentView,\n    CustomResultScenarioContentView,\n    CustomResultSettingsContentView,\n    CustomResultSlotController,\n    CustomResultSlotView,\n    CustomResultStore,\n    ScenarioViewer,\n    DomainStore,\n    // DemoModeController,\n    // DenominationController,\n    FeatureController,\n    Features,\n    CentralWinActions,\n    FreeSpinRestoreRequest,\n    ServerState as GameState,\n    IBrandingConfiguration,\n    IBrandlogoPosition,\n    IDenomButtonStyle,\n    IDenomOptionButtonConfig,\n    IFeatureModule,\n    INonProportionalSymbol,\n    // IReels,\n    // IReelsView,\n    ISlotConfiguration,\n    ISpin,\n    ISpinBonus,\n    ISpinEntry,\n    ISpinMutation,\n    ISymbol,\n    ISymbolPosition,\n    ITexturesMapObject,\n    InitialSettings,\n    JackpotWin,\n    Line,\n    LineMode,\n    // DemoModeView,\n    // DenominationView,\n    LinesView,\n    LinesViewDesktop,\n    MessBarTypes,\n    // Mouse configs for using\n    NonProportionalSymbolBase,\n    PriorityList,\n    PriorityPositionObject,\n    PriorityTextStyle,\n    RestoreController,\n    RestoreResponse,\n    // PopupController,\n    // PopupControllerDesktop,\n    // ReelsControllerDefault,\n    RootController,\n    RootElementsAnimationTypes,\n    RootStore,\n    // ModalBackground,\n    // PaytableScript,\n    // Popup,\n    // PopupDesktop,\n    // SmallPopup,\n    // Reel,\n    // ReelsViewDefault,\n    // ReelsViewDesktopDefault,\n    RootView,\n    // RootViewDesktop,\n    // HelpView,\n    // HelpViewDesktop,\n    // BetSettingsView,\n    // BetSettingsViewDesktop,\n    // GeneralSettingsView,\n    ServerState,\n    SingleProgressiveTemplate,\n    SlotComponents,\n    SlotConfiguration,\n    SlotGame,\n    SlotTemplate,\n    SlotGameLayouts,\n    SpinAnalyzer,\n    SpinSpeedIndicator,\n    // SettingsView,\n    // SettingsViewDesktop,\n    // SpinSettingsView,\n    // PaytableHTMLView,\n    // SpinSettingsViewDesktop,\n    StopVideoView,\n    Subjects,\n    SymbolBase,\n    // PopupPosition,\n    // ReelState,\n    // SettingsTab,\n    UIState,\n    UIStore,\n    ZOrders,\n    ITemplateSlotConfiguration,\n    HistorySubject,\n    getComponentModeByLayout,\n    getFeatureModeByLayout,\n    getSlotLayout,\n};\n","import Core, { PositionObject, IPosition } from '@egt/core';\nimport SlotComponents from './components/enums/SlotComponents';\nimport Features from './components/feature/Features';\n\nexport default class PriorityPositionObject extends PositionObject {\n    constructor(configs: Array<{ value: IPosition; priority: number; priorityType: { feature: any; mode?: any } }>) {\n        super(\n            configs.filter((componentConfigs) => componentConfigs.priorityType.feature === SlotComponents.DEFAULT)[0]\n                .value,\n        );\n        this.getConfigIndex(configs);\n        this.replacePositionData(\n            configs[this.getConfigIndex(configs)].value,\n            new PositionObject(\n                configs.filter(\n                    (componentConfigs) => componentConfigs.priorityType.feature === SlotComponents.DEFAULT,\n                )[0].value,\n            ),\n        );\n    }\n\n    public getConfigIndex(\n        configs: Array<{ value: IPosition; priority: number; priorityType: { feature: any; mode?: any } }>,\n    ): number {\n        let biggerPriority: number = -1;\n        let configIndex: number = 0;\n        for (let i: number = 0; i < configs.length; i++) {\n            const isComponent: boolean = this.hasComponent(configs[i].priorityType.feature as SlotComponents);\n            const isFeature: boolean = Core.hasFeature(configs[i].priorityType.feature as Features);\n\n            if (\n                (isComponent || isFeature || configs[i].priorityType.feature === SlotComponents.DEFAULT) &&\n                biggerPriority < configs[i].priority\n            ) {\n                biggerPriority = configs[i].priority;\n                configIndex = i;\n            }\n        }\n        return configIndex;\n    }\n\n    // private hasComponent(componentType: SlotComponents): boolean {\n    //     const components = Core.getGameComponents();\n    //     return components.filter(componentArr => componentArr.componentType === componentType).length > 0;\n    // }\n}\n","import Core from '@egt/core';\nimport { ITextStyle, TextStyle } from 'pixi.js';\nimport SlotComponents from './components/enums/SlotComponents';\nimport Features from './components/feature/Features';\n\nexport default class PriorityTextStyle extends TextStyle {\n    // constructor(style:  Partial<ITextStyle>) {\n    constructor(\n        configs: Array<{ value: Partial<ITextStyle>; priority: number; priorityType: { feature: any; mode?: any } }>,\n    ) {\n        super(\n            configs.filter((componentConfigs) => componentConfigs.priorityType.feature === SlotComponents.DEFAULT)[0]\n                .value,\n        );\n        this.replaceTextStyle(configs);\n    }\n\n    private hasComponent(componentType: SlotComponents): boolean {\n        const components = Core.getGameComponents();\n        return components.filter((componentArr) => componentArr.componentType === componentType).length > 0;\n    }\n\n    private getConfigIndex(\n        configs: Array<{ value: Partial<ITextStyle>; priority: number; priorityType: { feature: any; mode?: any } }>,\n    ): number {\n        let biggerPriority: number = -1;\n        let configIndex: number = 0;\n        for (let i: number = 0; i < configs.length; i++) {\n            const isComponent: boolean = this.hasComponent(configs[i].priorityType.feature as SlotComponents);\n            const isFeature: boolean = Core.hasFeature(configs[i].priorityType.feature as Features);\n\n            if (\n                (isComponent || isFeature || configs[i].priorityType.feature === SlotComponents.DEFAULT) &&\n                biggerPriority < configs[i].priority\n            ) {\n                biggerPriority = configs[i].priority;\n                configIndex = i;\n            }\n        }\n        return configIndex;\n    }\n\n    private replaceTextStyle(\n        configs: Array<{ value: Partial<ITextStyle>; priority: number; priorityType: { feature: any; mode?: any } }>,\n    ): void {\n        const style: Partial<ITextStyle> = configs[this.getConfigIndex(configs)].value;\n        for (const property in style) {\n            this[property] = style[property];\n        }\n    }\n}\n","import { FeatureFlagGroups, RestrictionType } from '@egt/core';\n// Type-only, so it is erased before emit: it adds no runtime edge to the barrel and cannot\n// participate in the evaluation-order hazard the leaf imports below work around.\nimport type { IFeatureFlag } from '@egt/core';\n// Leaf import, NOT the '@egt/core' barrel: the `SLOT_AFFECTED_FEATURES` computed keys below\n// dereference this enum during module evaluation rather than deferring it to a method body, so a\n// barrel import resolves to `undefined` while Core.ts is mid-evaluation and boot throws.\nimport { FeatureFlags } from 'core/src/egt/core/enums/FeatureFlags';\n// Import the base store from its LEAF module (NOT the '@egt/core' barrel). The `extends` clause\n// is evaluated at class-definition time, which happens while the barrel (Core.ts) is still\n// mid-evaluation (Core.ts imports `Features` from this slot package before it initializes its\n// `FeatureFlagsStore` re-export), so a barrel import resolves to `undefined` here.\nimport FeatureFlagsStore from 'core/src/egt/core/services/FeatureFlagsStore';\n// Same reason for the leaf import here: `requireFlagMetadata` is called from this class's\n// constructor path, so it must not be resolved through the mid-evaluation barrel.\nimport { requireFlagMetadata } from 'core/src/egt/core/data/FeatureFlagsData';\nimport SlotComponents from './components/enums/SlotComponents';\nimport Features from './components/feature/Features';\n\n/**\n * Slot feature identifiers each flag affects. These lived in the core flag catalog, which meant\n * `packages/core` imported `packages/slot`. They belong here: the values are slot's own, and\n * `HelpView` — the only reader — is registered by slot games and slot templates only.\n */\nconst SLOT_AFFECTED_FEATURES: Partial<Record<FeatureFlags, string[]>> = {\n    [FeatureFlags.HIDE_JACKPOT]: [\n        Features.BL_JACKPOT,\n        Features.HIGH_CASH_COUNTERS,\n        Features.GAKL_JACKPOT_V1,\n        Features.GAKL_JACKPOT_BASE,\n        Features.BL_BOOST_JACKPOT,\n    ],\n    [FeatureFlags.HIDE_BUY_BONUS]: [SlotComponents.BUY_BONUS],\n    [FeatureFlags.HIDE_DOUBLE_CHANCE]: [SlotComponents.BUY_BONUS],\n    [FeatureFlags.USE_SA_FEATURE]: [Features.BL_JACKPOT, Features.MYSTERY_JACKPOT],\n};\n\n/**\n * Per-game feature-flags store for Slot games. Extends the core base store so it inherits all\n * storage, the two-check getters, group queries, the URL override, and the `mergeFlags` seam,\n * contributing only the slot-specific `registerGameFlags`.\n *\n * The constructor seeds the core defaults, registers the game flags (which override the seeded\n * defaults for shared keys), then applies the URL override once at the end — exposing the merged\n * set only after all three steps complete. The registration logic is the verbatim slot\n * flag-building logic that previously lived in `SlotGameFeatureFlags`.\n */\nexport default class SlotFeatureFlagsStore extends FeatureFlagsStore {\n    constructor(loadGameResponse: any) {\n        super();\n        this.setBaseFlags(loadGameResponse);\n        this.registerGameFlags(loadGameResponse);\n        this.applyOverrides();\n        this.applyDerivedMetadata();\n    }\n\n    /**\n     * @name applyDerivedMetadata\n     * Runs the buy-bonus Tier-2 derivation against the FINAL flag states — see the base-store\n     * docstring for why this cannot live in `registerGameFlags`.\n     */\n    protected applyDerivedMetadata(): void {\n        this._applyBuyBonusComponentRemoval();\n    }\n\n    /**\n     * @name registerGameFlags\n     * Registers the slot game's own flags on top of the seeded core defaults. Runs the default\n     * flag builder then the jurisdiction-restriction processing, in the same order the old\n     * `SlotGameFeatureFlags` constructor did.\n     */\n    protected registerGameFlags(loadGameResponse: any): void {\n        this._setDefaultFeatureFlags(loadGameResponse);\n        this._setFlagStatusFromGameResponse(loadGameResponse);\n    }\n\n    /**\n     * @name _slotMetadata\n     * Catalog metadata plus slot's own `affectedFeatures`, for flags that have any. Every other\n     * flag resolves to the catalog entry unchanged, so this is safe to use at any registration site.\n     * @param flag\n     * @private\n     */\n    private _slotMetadata(flag: FeatureFlags): IFeatureFlag {\n        const affectedFeatures = SLOT_AFFECTED_FEATURES[flag];\n        const metadata = requireFlagMetadata(flag);\n        return affectedFeatures ? { ...metadata, affectedFeatures } : metadata;\n    }\n\n    /**\n     * Default flag builder for Slot games\n     *\n     * Every response access is optional-chained, matching the fully-guarded `setBaseFlags` in the\n     * base store. It was not: `gameResponse.settings.feature.includes(...)` and\n     * `gameResponse.settings.jurisdiction.restrictions.includes(...)` threw on a response missing\n     * either object, and because this runs inside the `importGame().then()` callback that throw\n     * surfaced as an unhandled rejection which took the whole game load down before `Core.flags`\n     * was ever assigned. A missing object now yields `isActive: false` for the flags that depend on\n     * it, which is the same answer as \"the server did not grant this\".\n     * @param gameResponse\n     * @private\n     */\n    private _setDefaultFeatureFlags(gameResponse: any): void {\n        const serverFeatures: string[] = gameResponse?.settings?.feature ?? [];\n        const jurisdictionRestrictions: string[] = gameResponse?.settings?.jurisdiction?.restrictions ?? [];\n\n        this._flags.set(FeatureFlags.ALLOW_GAMBLE, {\n            description: 'Allows the player to double or lose their win using the Gamble feature after a winning spin.',\n            group: FeatureFlagGroups.SERVER,\n            isActive: serverFeatures.includes(Features.GAMBLE),\n        });\n\n        this._flags.set(FeatureFlags.ALLOW_TOURNAMENTS, {\n            description: 'Enables the game to participate in tournaments with leaderboards, points, and rewards.',\n            group: FeatureFlagGroups.SERVER,\n            isActive: serverFeatures.includes(Features.TOURNAMENTS),\n        });\n\n        this._flags.set(FeatureFlags.ALLOW_PRIZE_POPS, {\n            description: 'Enables the game to participate in prize pop with leaderboards, points, and rewards.',\n            group: FeatureFlagGroups.SERVER,\n            isActive: serverFeatures.includes(Features.PRIZE_POPS),\n        });\n\n        this._flags.set(FeatureFlags.USE_DEFAULT_BET_ON_LOAD, {\n            description: 'Use Default bet when game is load even in live',\n            group: FeatureFlagGroups.JURISDICTION,\n            isActive: jurisdictionRestrictions.includes(RestrictionType.DEFAULT_BET_ON_LOAD),\n        });\n\n        this._flags.set(FeatureFlags.ALLOW_GIFT_SPINS, {\n            description: 'Enables the gifting of free spins to the player.',\n            group: FeatureFlagGroups.SERVER,\n            isActive: serverFeatures.includes(Features.GIFT_SPINS),\n        });\n\n        this._flags.set(FeatureFlags.ALLOW_BRANDING, {\n            description: 'Applies game branding with operator-specific logos, symbols, and visual elements.',\n            group: FeatureFlagGroups.SERVER,\n            isActive: serverFeatures.includes(Features.BRANDING),\n        });\n\n        this._flags.set(FeatureFlags.USE_PAYTABLE_ON_LOAD, {\n            ...requireFlagMetadata(FeatureFlags.USE_PAYTABLE_ON_LOAD),\n            isActive: jurisdictionRestrictions.includes(RestrictionType.PAYTABLE_ON_LOAD),\n        });\n\n        this._flags.set(FeatureFlags.ALLOW_AUTOPLAY_POPUP, {\n            ...requireFlagMetadata(FeatureFlags.ALLOW_AUTOPLAY_POPUP),\n            isActive: true,\n        });\n\n        this._flags.set(FeatureFlags.ALLOW_DENOMINATION_POPUP, {\n            ...requireFlagMetadata(FeatureFlags.ALLOW_DENOMINATION_POPUP),\n            isActive: true,\n        });\n\n        this._flags.set(FeatureFlags.USE_TONE_JS, {\n            ...requireFlagMetadata(FeatureFlags.USE_TONE_JS),\n            isActive: false,\n        });\n\n        this._flags.set(FeatureFlags.USE_ONE_DENOM, {\n            ...requireFlagMetadata(FeatureFlags.USE_ONE_DENOM),\n            isActive:\n                (gameResponse?.settings?.denominations?.length ?? 0) === 1 &&\n                (gameResponse?.settings?.bets?.length ?? 0) > 5,\n        });\n\n        this._flags.set(FeatureFlags.USE_NUMERIC_AUTOPLAY, {\n            ...requireFlagMetadata(FeatureFlags.USE_NUMERIC_AUTOPLAY),\n            isActive: !!gameResponse?.settings?.jurisdiction?.autoplayRestrictions?.maxLossAmount,\n        });\n    }\n\n    /**\n     * Determines whether the game response represents a legacy server game\n     * (single factor with multiple game modes).\n     * @param gameResponse\n     */\n    private _isLegacyServerGame(gameResponse: any): boolean {\n        return (\n            (gameResponse.settings?.factors?.length === 1 && gameResponse.settings?.gameModes?.length > 1) ||\n            gameResponse.settings?.gameModes?.length === 1\n        );\n    }\n\n    /**\n     * Legacy server compatibility: register HIDE_BUY_BONUS and NO_DOUBLE_CHANCE flags\n     * directly when the game is a legacy server game, without mutating the restrictions array.\n     * @param gameResponse\n     */\n    private _registerLegacyServerFlags(gameResponse: any): void {\n        if (this._isLegacyServerGame(gameResponse)) {\n            this._flags.set(FeatureFlags.HIDE_BUY_BONUS, {\n                ...this._slotMetadata(FeatureFlags.HIDE_BUY_BONUS),\n                isActive: true,\n            });\n            this._flags.set(FeatureFlags.HIDE_DOUBLE_CHANCE, {\n                ...this._slotMetadata(FeatureFlags.HIDE_DOUBLE_CHANCE),\n                isActive: true,\n            });\n        }\n    }\n\n    /**\n     * Parses jurisdictions.restrictions in the game-response and builds feature flags from them.\n     * Also checks for legacy games to set specific flags for them.\n     * @param gameResponse\n     * @protected\n     */\n    protected _setFlagStatusFromGameResponse(gameResponse: any): void {\n        this._registerLegacyServerFlags(gameResponse);\n\n        const jurisdictionRestrictions: string[] = gameResponse?.settings?.jurisdiction?.restrictions ?? [];\n\n        jurisdictionRestrictions.forEach((restrictionFromResponse: string) => {\n            switch (restrictionFromResponse) {\n                case RestrictionType.NO_JACKPOT:\n                    this._flags.set(FeatureFlags.HIDE_JACKPOT, {\n                        ...this._slotMetadata(FeatureFlags.HIDE_JACKPOT),\n                        isActive: true,\n                    });\n                    break;\n                case RestrictionType.HIDE_BUY_BONUS:\n                    this._flags.set(FeatureFlags.HIDE_BUY_BONUS, {\n                        ...this._slotMetadata(FeatureFlags.HIDE_BUY_BONUS),\n                        isActive: true,\n                    });\n                    break;\n                case RestrictionType.NO_DOUBLE_CHANCE:\n                    this._flags.set(FeatureFlags.HIDE_DOUBLE_CHANCE, {\n                        ...this._slotMetadata(FeatureFlags.HIDE_DOUBLE_CHANCE),\n                        isActive: true,\n                    });\n                    break;\n                case RestrictionType.SA_FEATURE:\n                    this._flags.set(FeatureFlags.USE_SA_FEATURE, {\n                        ...this._slotMetadata(FeatureFlags.USE_SA_FEATURE),\n                        isActive: true,\n                    });\n                    break;\n            }\n        });\n    }\n\n    /**\n     * Tier 2 of the buy-bonus restriction model: attach `removeComponents` so the whole BUY_BONUS\n     * component is dropped, but ONLY when both restrictions are active. With one active, Tier 1\n     * applies instead — the component stays mounted and `BuyBonusComponent.resolveParts` skips just\n     * the restricted part, so the sibling part keeps working.\n     *\n     * The pairwise AND is the invariant: since PR #11998 folded double chance into BUY_BONUS as a\n     * part, removing the component on a single restriction would destroy the sibling part. The\n     * catalog therefore carries no `removeComponents` for either flag and this is the only place\n     * that adds it. See docs/buy-bonus-restriction-coordination-pre-release.drawio.\n     *\n     * Called from `applyDerivedMetadata`, i.e. AFTER `applyOverrides`, so the pairwise AND is\n     * evaluated against post-override state. That is what lets a developer pin both flags in the\n     * Feature Flags panel on a game the server does not restrict and get the real Tier-2 behaviour.\n     * While this ran inside `registerGameFlags` it saw only the response, returned early on the\n     * guard below because neither flag was registered, and the pinned pair left BUY_BONUS mounted.\n     * @private\n     */\n    private _applyBuyBonusComponentRemoval(): void {\n        const hideBuyBonus = this._flags.get(FeatureFlags.HIDE_BUY_BONUS);\n        const hideDoubleChance = this._flags.get(FeatureFlags.HIDE_DOUBLE_CHANCE);\n        if (!hideBuyBonus?.isActive || !hideDoubleChance?.isActive) return;\n\n        this._flags.set(FeatureFlags.HIDE_BUY_BONUS, {\n            ...hideBuyBonus,\n            removeComponents: [SlotComponents.BUY_BONUS],\n        });\n        this._flags.set(FeatureFlags.HIDE_DOUBLE_CHANCE, {\n            ...hideDoubleChance,\n            removeComponents: [SlotComponents.BUY_BONUS],\n        });\n    }\n}\n","import Core, {\n    AssetPriority,\n    BaseFeatures,\n    BaseGame,\n    GameTypes,\n    ISlotTemplateConstructorProps,\n    ISoundAsset,\n    Language,\n    LifeCycle,\n    Log,\n} from '@egt/core';\nimport SlotTemplate from './templates/SlotTemplate';\nimport { DenominationPopupModes } from '@egt/denomination-popup';\nimport { IToneSoundAsset } from 'core/src/egt/core/interfaces/IToneSoundAsset';\nimport 'pixi-spine';\nimport { Container } from 'pixi.js';\nimport { DependencyContainer, Lifecycle, injectable } from 'tsyringe';\nimport {\n    CustomResultSlotController,\n    CustomResultSlotView,\n    LinesViewDesktop,\n    SlotComponents,\n    SlotGameLayouts,\n} from '..';\nimport CustomInfinityPlayController from './components/custom-result/CustomInfinityPlayController';\nimport ScenarioViewer from './components/custom-result/ScenarioViewer';\nimport InitialSettings from './components/data/InitialSettings';\nimport ServerState from './components/data/ServerState';\nimport SpinAnalyzer from './components/data/SpinAnalyzer';\nimport Subjects from './components/data/Subjects';\nimport FeatureController from './components/feature/FeatureController';\nimport Features from './components/feature/Features';\nimport RestoreController from './components/restore/RestoreController';\nimport RootController from './components/root/RootController';\nimport RootStore from './components/root/RootStore';\nimport RootView from './components/root/RootView';\nimport UIStore from './components/ui/UIStore';\nimport SlotConfiguration from './slot-configuration/SlotConfiguration';\nimport SlotFeatureFlagsStore from './SlotFeatureFlagsStore';\nimport { ITemplateSlotConfiguration } from './templates/ITemplateSlotConfiguration';\n\n@injectable()\nexport default class SlotGame extends BaseGame {\n    public importConfiguration: (featureName: string) => Promise<any>;\n    public supportedLayouts: string[] = [SlotGameLayouts.CLASSIC, SlotGameLayouts.EXTENDED];\n    protected configuration: SlotConfiguration;\n    protected initialSettings: InitialSettings;\n    protected rs: RootStore;\n    protected defaultLayout: SlotGameLayouts = SlotGameLayouts.EXTENDED;\n    protected _gameSettings: any;\n\n    // protected forcedFeatureModesByGame: Map<string, string> = new Map();\n    // protected forcedComponentsModesByGame: Map<string, string> = new Map();\n\n    private rc: RootController;\n    private rv: RootView;\n    // private uiMainView: UIMainView;\n\n    public getExternalFeatures(): any[] {\n        return super.getExternalFeatures().concat(this.gameTemplate.getTemplateExternalFeatures());\n    }\n\n    public getGameFeatures(): any[] {\n        // Here must list features line Lines Videos etc.\n        const gameFeatures = this.gameTemplate.getTemplateGameFeatures();\n        // Campaign infrastructure, no assets - loaded for every game so the CampaignManager has\n        // one owner regardless of which campaigns the backend serves.\n        gameFeatures.push([Features.CAMPAIGN_MANAGER]);\n        if (Core.configuration.devTools) {\n            gameFeatures.push([BaseFeatures.CUSTOM_REACT]);\n            gameFeatures.push([BaseFeatures.CUSTOM_SCALER]);\n            gameFeatures.push([Features.WIN_ANIMATIONS_PREVIEW]);\n        }\n        return super.getGameFeatures().concat(gameFeatures);\n    }\n\n    public hasFeature(featureType: Features, _mode?: any): boolean {\n        return this.features.filter((featureArr) => featureArr.featureType === featureType).length > 0;\n    }\n\n    public hasComponent(componentType: SlotComponents, mode?: any): boolean {\n        if (mode) {\n            return this.gameTemplate.hasComponentWithActiveModeType(componentType, mode);\n        } else {\n            return this.components.filter((componentArr) => componentArr.componentType === componentType).length > 0;\n        }\n    }\n\n    public getGameComponents(response: any): any[] {\n        // Here must list features line Lines Videos etc.\n        // const gameComponents = [[SlotComponents.MAIN_PANEL_BASE], [SlotComponents.UI_VIEW]];\n        const gameComponents = this.gameTemplate.getTemplateComponents();\n        // gameComponents = this.filterGameComponents(response, gameComponents);\n        return super.getGameComponents(response).concat(gameComponents);\n    }\n\n    public onCreateGameTemplate(\n        _loadGameResponse: any,\n        templateOverrides: ISlotTemplateConstructorProps,\n        layout: SlotGameLayouts = SlotGameLayouts.EXTENDED,\n    ): void {\n        this.gameTemplate = new SlotTemplate(templateOverrides, layout);\n    }\n\n    // public onSetModes(loadGameResponse: any) {\n    // if (loadGameResponse.settings?.jurisdiction?.newPopupsStyle) {\n    // this.componentModes.set(SlotComponents.DENOMINATION_POPUP, DenominationPopupModes.EXTENDED);\n    // if (loadGameResponse.settings?.jurisdiction?.autoplayRestrictions?.maxLossAmount) {\n    //     this.componentModes.set(SlotComponents.AUTOPLAY_POPUP, AutoplayPopupModes.NUMERIC);\n    // } else {\n    //     this.componentModes.set(SlotComponents.AUTOPLAY_POPUP, AutoplayPopupModes.EXTENDED);\n    // }\n    // } else {\n    // this.componentModes.set(SlotComponents.DENOMINATION_POPUP, DenominationPopupModes.DEFAULT);\n    // this.componentModes.set(SlotComponents.AUTOPLAY_POPUP, AutoplayPopupModes.DEFAULT);\n    // }\n    // }\n\n    /**\n     * Hook to trigger the slot games restrictive feature flags assembly.\n     * Add new slot restrictive feature flags in SlotFeatureFlagsStore and new all-games restrictions in the Core.\n     * @param response\n     */\n    public onCreateFeatureFlags(_loadGameResponse: any): void {\n        Core.flags = new SlotFeatureFlagsStore(_loadGameResponse);\n        super.onCreateFeatureFlags(_loadGameResponse);\n    }\n\n    // public filterGameComponents(response: any, gameComponents?: any): any {\n    // const newPopupsStyle = response.settings?.jurisdiction?.newPopupsStyle ?? false;\n    // const componentsToRemove = newPopupsStyle\n    //     ? [SlotComponents.DENOMINATION_POPUP, SlotComponents.AUTOPLAY_POPUP]\n    //     : [SlotComponents.EXTENDED_DENOMINATION_POPUP, SlotComponents.EXTENDED_AUTOPLAY_POPUP];\n    //     return gameComponents.filter((comp) => !componentsToRemove.includes(comp[0]));\n    // }\n\n    public externalFeaturesAdded(): void {\n        super.externalFeaturesAdded();\n    }\n\n    public onBeforeInit(): void {\n        super.onBeforeInit();\n        this.gameType = GameTypes.STANDARD_SLOT;\n\n        this.featuresPriority.REELS_STOPPED = [\n            Features.LINES,\n            Features.VIDEOS,\n            // Features.DEMO,\n            Features.GIFT_SPINS,\n        ];\n        this.featuresPriority.RESTORE = [Features.LINES, Features.VIDEOS, Features.RESTORE];\n        this.featuresPriority.PROCESS_CURRENT_SPIN_RESULT = [];\n        this.featuresPriority.COLLECT_CLICKED = [];\n    }\n\n    public onGameSettings(gameSettings: any): void {\n        this._gameSettings = gameSettings;\n        Core.translator.moduleAssets = [];\n        const lang = Core.configuration.language;\n        const pathToCommon: string = '../assets/' + Core.configuration.gameKey + '/translations/' + lang + '.json';\n        Core.translator.addModuleAsset('_' + lang, pathToCommon);\n        if (lang !== Core.translator.defaultLanguage) {\n            const defaultPathToCommon =\n                '../assets/' +\n                Core.configuration.gameKey +\n                '/translations/' +\n                Core.translator.defaultLanguage +\n                '.json';\n            Core.translator.addModuleAsset('_' + Core.translator.defaultLanguage, defaultPathToCommon);\n        }\n        this.applyRequestedDenomination(gameSettings, this.getRequestedDenomination(gameSettings));\n        this.applySelectedBet(gameSettings);\n\n        super.onGameSettings(gameSettings);\n    }\n\n    public onBeforeDestroy(): void {\n        super.onBeforeDestroy();\n        // if exchange object is empty we store the entry language\n        if (Object.keys(Core.gamePortalExchangeObject).length === 0) {\n            Core.gamePortalExchangeObject.entryLanguage = Core.translator.currentLanguage;\n        }\n        // Store current indexes of Bet and Denomination\n        Core.gamePortalExchangeObject.denominationIndex = this._gameSettings.settings.denominations.indexOf(\n            Core.SELECTED_DENOMINATION.value,\n        );\n        Core.gamePortalExchangeObject.betIndex = this._gameSettings.settings.bets.indexOf(\n            this.rs.uiStore.SELECTED_BET.value,\n        );\n        // this.rs.destroy();\n    }\n\n    public destroy(): void {\n        this.rc.destroy();\n        // @ts-ignore\n        this.configuration.componentsConfiguration = null;\n        // @ts-ignore\n        this.configuration = null;\n        // @ts-ignore\n        this.rv = null;\n        // @ts-ignore\n        this.rc = null;\n        // @ts-ignore\n        this.rs = null;\n        // @ts-ignore\n        this.gameContainer = null;\n\n        super.destroy();\n    }\n\n    public onRegisterDependencies(dependencyContainer: DependencyContainer): void {\n        super.onRegisterDependencies(dependencyContainer);\n\n        this.initialSettings = new InitialSettings(this.gameSettings);\n\n        this.dependencyContainer.registerInstance('InitialSettings', this.initialSettings);\n        this.dependencyContainer.registerInstance('PriorityMap', this.featuresPriority);\n        // this.dependencyContainer.registerInstance('NoSleep', new NoSleep());\n        this.dependencyContainer.register('RootStore', { useClass: RootStore }, { lifecycle: Lifecycle.Singleton });\n        this.dependencyContainer.register('RootView', { useClass: RootView }, { lifecycle: Lifecycle.Singleton });\n\n        this.dependencyContainer.register(\n            'ISlotConfiguration',\n            { useClass: SlotConfiguration },\n            { lifecycle: Lifecycle.Singleton },\n        );\n        this.dependencyContainer.register(\n            'CustomResultView',\n            { useClass: CustomResultSlotView },\n            { lifecycle: Lifecycle.Singleton },\n        );\n        this.dependencyContainer.register(\n            'CustomResultController',\n            { useClass: CustomResultSlotController },\n            { lifecycle: Lifecycle.Singleton },\n        );\n        this.dependencyContainer.register(\n            'FeatureController',\n            { useClass: FeatureController },\n            { lifecycle: Lifecycle.Singleton },\n        );\n        this.dependencyContainer.register(\n            'RestoreController',\n            { useClass: RestoreController },\n            { lifecycle: Lifecycle.Singleton },\n        );\n\n        this.dependencyContainer.register('UIStore', { useClass: UIStore }, { lifecycle: Lifecycle.Singleton });\n        this.dependencyContainer.register(\n            'RootController',\n            { useClass: RootController },\n            { lifecycle: Lifecycle.Singleton },\n        );\n        this.dependencyContainer.register('SlotSubjects', { useClass: Subjects }, { lifecycle: Lifecycle.Singleton });\n        this.dependencyContainer.register(\n            'SpinAnalyzer',\n            { useClass: SpinAnalyzer },\n            { lifecycle: Lifecycle.Singleton },\n        );\n\n        this.dependencyContainer.register(\n            'ScenarioViewer',\n            { useClass: ScenarioViewer },\n            { lifecycle: Lifecycle.Singleton },\n        );\n        this.dependencyContainer.register(\n            'CustomInfinityPlayController',\n            { useClass: CustomInfinityPlayController },\n            { lifecycle: Lifecycle.Singleton },\n        );\n        this.gameTemplate.registerTemplateConfiguration(this.dependencyContainer);\n    }\n\n    public onRegisterDesktopDependencies(): void {\n        this.dependencyContainer.register(\n            'ILinesView',\n            { useClass: LinesViewDesktop },\n            { lifecycle: Lifecycle.Singleton },\n        );\n    }\n\n    public onGameConfigurationCreated(): void {\n        this.configuration = this.dependencyContainer.resolve('ISlotConfiguration');\n        const templateConfiguration: ITemplateSlotConfiguration =\n            this.dependencyContainer.resolve('ITemplateSlotConfiguration');\n        super.onGameConfigurationCreated();\n        // console.log('------configuration created');\n        if (Core.devTools) {\n            this.checkForDuplicateSVGs(templateConfiguration.templateOverrideSvgs, 'Template');\n        }\n\n        if (this.configuration.supportedLanguages.indexOf(Core.configuration.language as Language) === -1) {\n            Core.configuration.language = Language.EN;\n            Core.translator.currentLanguage = Core.configuration.language;\n            const pathToCommon: string =\n                '../assets/' + Core.configuration.gameKey + '/translations/' + Core.configuration.language + '.json';\n            Core.translator.addModuleAsset('_' + Core.configuration.language, pathToCommon);\n            Core.translator.loadErrorAsset();\n        }\n\n        if (this.initialSettings.gameName) {\n            this.configuration.gameTitle = this.initialSettings.gameName;\n            this.configuration.gameTitleShort = this.initialSettings.gameName;\n        }\n\n        if (this.initialSettings.enableVipUi && this.configuration.vipGameTitle) {\n            this.configuration.gameTitle = this.configuration.vipGameTitle;\n            this.configuration.gameTitleShort = this.configuration.vipGameTitleShort ?? this.configuration.vipGameTitle;\n        }\n\n        if (Core.devTools) {\n            this.checkForDuplicateSVGs(this.configuration.overrideSvgs, 'Game');\n        }\n\n        const svgAssets: Map<string, any> = new Map();\n        for (const svgAsset of this.configuration.uiSvgs) {\n            svgAssets.set(svgAsset.id, { ...svgAsset });\n        }\n        // let marker: boolean = true;\n        for (const svgAsset of templateConfiguration.templateOverrideSvgs) {\n            if (Core.devTools) {\n                this.checkForSvgDuplication(svgAssets, svgAsset, svgAsset.id, 'Template');\n                //DO NOT REMOVE NEXT COMMENTED LINES\n                // const existing = svgAssets.get(svgAsset.id);\n                // if (existing) {\n                //     if (this.objComparing(existing, svgAsset)) {\n                //         console.log('*** ID за премахване в теплета:', svgAsset.id);\n                //         marker = true;\n                //     } else {\n                //         if (marker) {\n                //             console.log('------- in template:');\n                //             marker = false;\n                //         }\n                //     }\n                // } else {\n                //     console.log('-------in template: not exist');\n                // }\n            }\n\n            // svgAssets.set(svgAsset.id, { ...svgAssets.get(svgAsset.id), ...svgAsset });\n            svgAssets.set(svgAsset.id, { ...svgAsset });\n        }\n\n        for (const svgAsset of this.configuration.overrideSvgs) {\n            if (Core.devTools) {\n                this.checkForSvgDuplication(svgAssets, svgAsset, svgAsset.id, 'Game');\n                // DO NOT REMOVE NEXT COMMENTED LINES\n                // const existing = svgAssets.get(svgAsset.id);\n                // if (existing) {\n                //     if (this.objComparing(existing, svgAsset)) {\n                //         console.log('*** ID за премахване в играта:', svgAsset.id);\n                //         marker = true;\n                //     } else {\n                //         if (marker) {\n                //             console.log('-------in game');\n                //             marker = false;\n                //         }\n                //     }\n                // } else {\n                //     console.log('------- in game: not exist');\n                // }\n            }\n\n            // svgAssets.set(svgAsset.id, { ...svgAssets.get(svgAsset.id), ...svgAsset });\n            svgAssets.set(svgAsset.id, { ...svgAsset });\n        }\n\n        this.configuration.uiSvgs = Array.from(svgAssets.values());\n    }\n\n    private checkForSvgDuplication(\n        svgAssets: Map<string, any>,\n        currentAsset: any,\n        assetID: string,\n        checkType: 'Template' | 'Game',\n    ): void {\n        if (Core.devTools) {\n            const existing = svgAssets.get(assetID);\n            if (existing) {\n                if (this.objComparing(existing, currentAsset)) {\n                    Log.error(\n                        'svg asset for remove in ' + checkType + ' configuration: ' + assetID,\n                        this.constructor.name,\n                    );\n                }\n            }\n        }\n    }\n\n    private objComparing(obj1: any, obj2: any): boolean {\n        if (obj1 === obj2) return true;\n\n        if (typeof obj1 !== 'object' || obj1 === null || typeof obj2 !== 'object' || obj2 === null) {\n            return false;\n        }\n\n        const keys1 = Object.keys(obj1);\n        const keys2 = Object.keys(obj2);\n\n        if (keys1.length !== keys2.length) return false;\n\n        for (const key of keys1) {\n            if (!keys2.includes(key)) return false;\n            if (!this.objComparing(obj1[key], obj2[key])) return false;\n        }\n\n        return true;\n    }\n\n    private checkForDuplicateSVGs(arr: any, whereCheck: 'Game' | 'Template'): void {\n        const seen = new Set();\n        const duplicates = new Set();\n\n        for (const item of arr) {\n            if (seen.has(item.id)) {\n                duplicates.add(item.id);\n            } else {\n                seen.add(item.id);\n            }\n        }\n\n        for (const id of Array.from(duplicates)) {\n            Log.error('Duplicate SVG in ' + whereCheck + ' configuration: ' + id, this.constructor.name);\n            // console.log('Duplicate SVG in Game or Template configuration: ' + id, this.constructor.name);\n        }\n    }\n\n    public onAfterGameConfigurationCreated(): void {\n        super.onAfterGameConfigurationCreated();\n        Core.spineAnimations.onGameLoaded();\n        if (Core.configuration.devTools) {\n            const versionOverwrite = Core.localStorage.readSetting('overwriteSounds' + Core.configuration.gameKey);\n            if (versionOverwrite) {\n                this.replaceResource(this.configuration.assets, 'overrideSounds', {\n                    id: 'overrideSounds',\n                    url: versionOverwrite.path,\n                    priority: AssetPriority.HIGHEST,\n                    type: 'sound',\n                    sprite: versionOverwrite.sprite,\n                });\n                Object.keys(versionOverwrite.sprite).forEach((soundId) => {\n                    Log.debug(\n                        `[SOUND]: replaced sound with ID: ${soundId} from ${versionOverwrite.path}`,\n                        this.constructor.name,\n                    );\n                });\n            }\n        }\n    }\n\n    public onResolveDependencies(dependencyContainer: DependencyContainer): void {\n        super.onResolveDependencies(dependencyContainer);\n        this.rs = this.dependencyContainer.resolve('RootStore');\n        this.rc = this.dependencyContainer.resolve('RootController');\n        this.rv = this.dependencyContainer.resolve('RootView');\n    }\n\n    public onHighestPriorityGroupLoaded(group: any): void {\n        super.onHighestPriorityGroupLoaded(group);\n    }\n\n    public onIndividualAssetLoaded(e: any): void {\n        super.onIndividualAssetLoaded(e);\n        if (\n            e.asset.type === 'sound' &&\n            e.asset.id === 'backgroundSounds' &&\n            (this.gameSettings.state === ServerState.IDLE || this.gameSettings.state === ServerState.BONUS_IDLE)\n        ) {\n            this.rs.uiStore.BACKGROUND_SOUND_PLAY.next({ sound: 'backgroundMusic', ms: 0 });\n        }\n    }\n\n    public startGame(): void {\n        Log.debug('START GAME', this.constructor.name);\n        this.gameContainer.addChild(this.rv);\n        Core.emit(LifeCycle.ON_INIT, this.rv);\n        Core.emit(LifeCycle.ON_INIT_COMPLETE, this.rv);\n        Core.emit(LifeCycle.ON_INITIAL_RENDER, this.rv);\n        Core.emit(LifeCycle.ON_AFTER_INITIAL_RENDER, this.rv);\n    }\n\n    public onPrepareResources(rootView: Container): void {\n        super.onPrepareResources(rootView);\n        // this._assetsLoader.reset();\n        Core.fonts.addAssets(this.configuration.fontAssets);\n        Core.assets.addAsset(Core.translator.getAssetFor(Core.configuration.language.toLowerCase()));\n        if (Core.configuration.language !== Core.translator.defaultLanguage) {\n            Core.assets.addAsset(Core.translator.getAssetFor(Core.translator.defaultLanguage));\n        }\n        Core.assets.addAssets(this.configuration.commonAssets);\n        Core.assets.addAssets(this.configuration.assets);\n    }\n\n    public onAfterInitialRender(view: any): void {\n        super.onAfterInitialRender(view);\n        let soundAsset: ISoundAsset | IToneSoundAsset;\n\n        if (Core.audioEngineType === 'Howler') {\n            soundAsset = //! lemmy old\n                (this.configuration.assets.filter((e) => e.id === 'overrideSounds')[0] as ISoundAsset)?.howl;\n        } else {\n            soundAsset = this.configuration.assets.filter((e) => e.id === 'overrideSounds')[0] as IToneSoundAsset;\n        }\n\n        if (soundAsset) {\n            //! lemmy\n            const targetedSprite =\n                Core.audioEngineType === 'Howler'\n                    ? (soundAsset as any)._sprite\n                    : (soundAsset as IToneSoundAsset).sprite;\n            // @ts-ignore\n            // Object.keys(soundAsset._sprite).forEach((soundId) => { //! lemmy old\n            //     Core.sounds.replaceSound(soundId, soundAsset as IToneSoundAsset);\n            // });\n            Object.keys(targetedSprite).forEach((soundId) => {\n                Core.sounds.replaceSound(soundId, soundAsset);\n            });\n        }\n    }\n\n    public replaceResource(source: any, resourceID: string, obj: any): void {\n        const resource = source.filter((asset) => asset.id === resourceID)[0];\n        if (resource) {\n            source.splice(source.indexOf(resource), 1, obj);\n        } else {\n            source.push(obj);\n        }\n    }\n\n    public removeResource(source: any, resourceID: string): void {\n        const resource = source.filter((asset) => asset.id === resourceID)[0];\n        if (resource) {\n            source.splice(source.indexOf(resource), 1);\n        }\n    }\n\n    protected registerBetSettingsView(view: any, oneDenomView: any): void {\n        if (Core.gameDependencyContainer.isRegistered('InitialSettings')) {\n            const initialSettings: InitialSettings = this.dependencyContainer.resolve('InitialSettings');\n            const configuration: any = this.dependencyContainer.resolve('SettingsPopupComponentConfiguration');\n            const condition =\n                initialSettings.allBets.length > configuration.betCalculatorProps.betPerRow ||\n                Core.hasComponent(SlotComponents.DENOMINATION_POPUP, DenominationPopupModes.EXTENDED);\n\n            this.dependencyContainer.register(\n                'BetSettingsView',\n                { useClass: condition ? oneDenomView : view },\n                { lifecycle: Lifecycle.Singleton },\n            );\n        }\n    }\n\n    private applySelectedBet(gameSettings: any): void {\n        const betIndex = gameSettings.game?.state ? undefined : Core.gamePortalExchangeObject.betIndex;\n        if (betIndex === undefined || betIndex === -1 || gameSettings.state !== ServerState.IDLE) {\n            return;\n        }\n        const requestedBet =\n            betIndex > gameSettings.settings.bets.length - 1\n                ? gameSettings.settings.bets[gameSettings.settings.bets.lenght - 1]\n                : gameSettings.settings.bets[betIndex];\n\n        // Check if bet there is bet level from latest paid game and overwrite it\n        if (gameSettings?.game?.state?.bet?.level) {\n            gameSettings.game.state.bet.level = requestedBet;\n            return;\n        }\n\n        gameSettings.settings.bet = requestedBet;\n    }\n\n    private applyRequestedDenomination(gameSettings: any, requestedDenomination: number | null): void {\n        // Check if requested denomination is present in the list of available denominations\n        if (\n            gameSettings.settings.denominations.indexOf(requestedDenomination) === -1 ||\n            gameSettings.state !== ServerState.IDLE\n        ) {\n            return;\n        }\n\n        if (gameSettings?.game?.state?.bet?.denomination) {\n            gameSettings.game.state.bet.denomination = requestedDenomination;\n            return;\n        }\n\n        gameSettings.settings.denomination = requestedDenomination;\n    }\n\n    private getRequestedDenomination(gameSettings: any): number | null {\n        // if we have state object then restore to it not to last used index in other game\n        // ON-10492\n        if (gameSettings.game?.state) {\n            return null;\n        }\n        let requestedDenomination = null;\n        const denomination = Core.gamePortalExchangeObject.denomination;\n        const denominationIndex = Core.gamePortalExchangeObject.denominationIndex;\n        if (denomination) {\n            requestedDenomination = denomination;\n            Core.gamePortalExchangeObject.denomination = null;\n        } else if (denominationIndex !== undefined && denominationIndex !== -1) {\n            // Check if denominationIndex is not out of bounds and if it's the last available denominationIndex is applied\n            requestedDenomination =\n                denominationIndex > gameSettings.settings.denominations.length - 1\n                    ? gameSettings.settings.denominations[gameSettings.settings.denominations.length - 1]\n                    : gameSettings.settings.denominations[denominationIndex];\n        }\n        return requestedDenomination;\n    }\n}\n","const enum SlotGameLayouts {\n    CLASSIC = 'CLASSIC',\n    TURTLE = 'TURTLE',\n    EXTENDED = 'EXTENDED',\n}\nexport default SlotGameLayouts;\n","import Core, { BaseController, ErrorTypes, IErrorData, Timers } from '@egt/core';\nimport { Sprite } from 'pixi.js';\nimport { filter, takeUntil } from 'rxjs/operators';\nimport Button from 'slot-features/ui-lib/src/egt/ui/buttons/Button';\nimport { inject, injectable } from 'tsyringe';\nimport ServerState from '../data/ServerState';\nimport RootStore from '../root/RootStore';\nimport RootView from '../root/RootView';\nimport UIState from '../ui/UIState';\n\n@injectable()\nexport default class CustomInfinityPlayController extends BaseController {\n    private spinButton: Button;\n    private stopButton: Button;\n    private currentBetIndex: number = 1;\n    private mysteryIndexes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];\n    // private view;\n    private activeButton: any;\n    // biome-ignore lint/correctness/noUndeclaredVariables: <explanation>\n    private timer: gsap.core.Tween;\n    // private waitingResponse: boolean;\n\n    constructor(\n        @inject('RootStore') private rootStore: RootStore,\n        @inject('RootView') protected view: RootView,\n    ) {\n        super(undefined);\n        this.spinButton = view.find('spinButton') as Button;\n        this.stopButton = view.find('autoPlayStopButton') as Button;\n        Core.ON_SERVER_MESSAGE.pipe(\n            filter(() => this.rootStore.customResultStore.isInfinityPlayButtonActive.value),\n            takeUntil(this.DESTROY),\n        ).subscribe(this.onMessageReceived.bind(this));\n\n        Core.SHOW_ERROR.pipe(\n            filter(() => this.rootStore.customResultStore.isInfinityPlayButtonActive.value),\n            takeUntil(this.DESTROY),\n        ).subscribe(this.onError.bind(this));\n\n        this.rootStore.uiStore.STATE.pipe(\n            filter(() => this.rootStore.customResultStore.isInfinityPlayButtonActive.value),\n            takeUntil(this.DESTROY),\n        ).subscribe(this.onStateChanged.bind(this));\n\n        this.rootStore.customResultStore.isInfinityPlayButtonActive\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.onInfinityPlayChanged.bind(this));\n    }\n    public destroy(): void {\n        if (this.rootStore) {\n            // @ts-ignore\n            this.rootStore = null;\n        }\n        if (this.view) {\n            // @ts-ignore\n            this.view = null;\n        }\n        if (this.rootStore) {\n            // @ts-ignore\n            this.rootStore = null;\n        }\n        if (this.spinButton) {\n            // @ts-ignore\n            this.spinButton = null;\n        }\n        if (this.stopButton) {\n            // @ts-ignore\n            this.stopButton = null;\n        }\n        this.mysteryIndexes.length = 0;\n        if (this.activeButton) {\n            this.activeButton = null;\n        }\n        super.destroy();\n    }\n\n    private onError(e: IErrorData): void {\n        if (e.type !== ErrorTypes.CONNECTION_ERROR) {\n            this.rootStore.customResultStore.isInfinityPlayButtonActive.next(false);\n        }\n    }\n\n    private onStateChanged(): void {\n        this.executeButtonFakeClick();\n    }\n\n    private onInfinityPlayChanged(): void {\n        this.executeButtonFakeClick();\n    }\n\n    private onMessageReceived(response: any): void {\n        this.executeButtonFakeClick(response);\n    }\n\n    private randomInterval(min: number, max: number): number {\n        return Math.floor(Math.random() * max) + min;\n    }\n\n    private executeButtonFakeClick(response: any = null): void {\n        Timers.clearTimeout(this.timer);\n        if (!this.rootStore.customResultStore.isInfinityPlayButtonActive.value) {\n            return;\n        }\n\n        if (this.rootStore.uiStore.STATE.value !== UIState.MYSTERY) {\n            this.mysteryIndexes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];\n        }\n\n        // console.log(\"*** setButtonFakeClick\", this.rootStore.uiStore.STATE.value);\n        this.activeButton = this.spinButton;\n        switch (this.rootStore.uiStore.STATE.value) {\n            case UIState.MYSTERY:\n                const chestHolder = this.view.find('chestHolder');\n                if (chestHolder) {\n                    if ((response && response.event === 'spin') || this.mysteryIndexes.length === 15) {\n                        const random = Math.floor(Math.random() * this.mysteryIndexes.length);\n                        const lastSelected = this.mysteryIndexes[random];\n                        this.mysteryIndexes.splice(random, 1);\n                        Timers.setTimeout(() => {\n                            const chest = this.view.find('chest' + lastSelected);\n                            chest.openChest();\n                        }, 2000);\n                    } else {\n                        const backToGameBut = this.view.find('backToGameBut') as Sprite;\n                        if (backToGameBut) {\n                            backToGameBut.emit('pointerup');\n                        }\n                    }\n                }\n                break;\n            case UIState.PICK_ME_BONUS:\n                if (this.rootStore.domainStore.SERVER_STATE.value !== ServerState.PICK) {\n                    return;\n                }\n                this.activeButton = this.stopButton;\n                const scatterButton = this.view.find('scatter0');\n                if (scatterButton && scatterButton.visible) {\n                    scatterButton.emit('pointerdown');\n                }\n                break;\n            case UIState.WAITING_FOR_STATE_CHANGE:\n                return;\n            case UIState.WAITING_FOR_RESPONSE:\n                const fastStop = this.randomInterval(1, 100) < this.rootStore.customResultStore.fastStop ? true : false;\n                if (!fastStop) {\n                    return;\n                }\n                this.activeButton = this.stopButton;\n                break;\n            case UIState.FREESPIN:\n                const startFreeSpinButton = this.view.find('freeSpinStartBtnClickableArea');\n                // executed only once at begining if there is startbutton waiting\n                if (startFreeSpinButton && startFreeSpinButton.visible) {\n                    startFreeSpinButton.emit('pointerup');\n                    return;\n                }\n                this.activeButton = this.stopButton;\n                break;\n            case UIState.GAMBLE:\n                if (this.rootStore.uiStore.gamblesLeft === 0) {\n                    return;\n                }\n                const chooseCollect =\n                    this.randomInterval(1, 100) < this.rootStore.customResultStore.gambleCollect ? true : false;\n                if (chooseCollect) {\n                    this.activeButton = this.view.find('collectButton');\n                } else {\n                    const chooseBlack =\n                        this.randomInterval(1, 100) < this.rootStore.customResultStore.gambleRedBlack ? true : false;\n                    this.activeButton = chooseBlack\n                        ? this.view.find('gambleBlackButton')\n                        : this.view.find('gambleRedButton');\n                }\n                break;\n            case UIState.WAITING_FOR_RESPONSE_IN_FREESPIN:\n                this.activeButton = this.stopButton;\n                break;\n            case UIState.WAITING_FOR_COLLECT:\n                let playGamble = false;\n                if (this.rootStore.uiStore.gamblesLeft > 0) {\n                    playGamble =\n                        this.randomInterval(1, 100) < this.rootStore.customResultStore.playGamble ? true : false;\n                }\n                if (playGamble) {\n                    this.activeButton = this.view.find('gambleButton');\n                } else {\n                    this.activeButton = this.spinButton;\n                }\n                break;\n            case UIState.IDLE:\n                const changeBet =\n                    this.randomInterval(1, 100) < this.rootStore.customResultStore.changeBet ? true : false;\n                if (changeBet) {\n                    const betOptions = [1, 2, 3, 4, 5].filter((b) => b !== this.currentBetIndex);\n                    this.currentBetIndex = betOptions[this.randomInterval(1, betOptions.length)];\n                    this.activeButton = this.view.find('bet' + this.currentBetIndex);\n                } else {\n                    this.activeButton = this.spinButton;\n                }\n                break;\n            default:\n                this.activeButton = this.spinButton;\n        }\n        this.doClick();\n    }\n\n    private doClick(): void {\n        Timers.clearTimeout(this.timer);\n        if (!this.rootStore.customResultStore.isInfinityPlayButtonActive.value) {\n            return;\n        }\n        let interval: number = 500;\n        if (this.rootStore.uiStore.turboModeEnabled) {\n            interval = this.randomInterval(200, 500);\n        } else if (this.rootStore.uiStore.quickSpinEnabled) {\n            interval = this.randomInterval(400, 800);\n        } else {\n            interval = 600 + 800 / this.rootStore.customResultStore.betSpeed;\n        }\n        this.timer = Timers.setTimeout(() => {\n            // console.log(\n            //     '*** doClick',\n            //     this.activeButton.name,\n            //     this.activeButton.visible,\n            //     this.activeButton.enabled,\n            //     this.rootStore.uiStore.STATE.value,\n            // );\n            if (this.activeButton && this.activeButton.visible && this.activeButton.enabled) {\n                this.activeButton.fakeClick();\n            } else {\n                this.doClick();\n            }\n        }, interval);\n    }\n}\n","import Core from '@egt/core';\nimport { CustomResultController } from '@egt/custom-result';\nimport { Subject, fromEvent, merge } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\n\nimport { ISlotConfiguration } from '../../slot-configuration/ISlotConfiguration';\nimport RootStore from '../root/RootStore';\nimport CustomInfinityPlayController from './CustomInfinityPlayController';\nimport CustomResultSlotView from './CustomResultSlotView';\nimport ScenarioViewer from './ScenarioViewer';\nimport CustomResultBotContentView from './views/CustomResultBotContentView';\nimport CustomResultCustomContentView from './views/CustomResultCustomContentView';\nimport CustomResultScenarioContentView from './views/CustomResultScenarioContentView';\nimport CustomResultSettingsContentView from './views/CustomResultSettingsContentView';\nimport CustomResultSoundContentView from './views/CustomResultSoundContentView';\nimport CustomResultVideoContentView from './views/CustomResultVideoContentView';\n\n@injectable()\nexport default class CustomResultSlotController extends CustomResultController {\n    private tabChanged = new Subject();\n    private activeTabIndex = 0;\n    constructor(\n        @inject('CustomResultView') protected view: CustomResultSlotView,\n        @inject('ScenarioViewer') protected scenarioView: ScenarioViewer,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('CustomInfinityPlayController') protected infinityPlayController: CustomInfinityPlayController,\n    ) {\n        super(view);\n    }\n\n    public destroy(): void {\n        if (this.infinityPlayController) {\n            this.infinityPlayController.destroy();\n            // @ts-ignore\n            this.infinityPlayController = null;\n        }\n        if (this.scenarioView) {\n            this.scenarioView.destroy();\n            // @ts-ignore\n            this.scenarioView = null;\n        }\n        if (this.tabChanged) {\n            this.tabChanged.complete();\n            // @ts-ignore\n            this.tabChanged = null;\n        }\n\n        super.destroy();\n    }\n    public startFeature(): void {\n        super.startFeature();\n        this.rootStore.customResultStore.setStartCustom();\n        this.toggleTabs(0);\n    }\n\n    public toggleTabs(index): void {\n        this.view.clearContent();\n        this.tabChanged.next();\n        this.activeTabIndex = index;\n        const sub = merge(this.DESTROY, this.tabChanged);\n        switch (this.view.tabsArray[index].type) {\n            case 'Custom': {\n                const content: CustomResultCustomContentView = new CustomResultCustomContentView(\n                    this.view.contentHolder,\n                    this.rootStore,\n                    this.slotConfiguration,\n                    this.tabChanged,\n                );\n                this.view.contentView = content;\n                content.autoPlayFeatureButton.checked = this.rootStore.customResultStore.isAutoPlayFeatures.value;\n                content.autoPlayFeatureButton.onclick = () => {\n                    this.onActivateAutoPlayFeatureClick();\n                };\n                for (const selected of content.selectImages) {\n                    (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/slot/src/egt/slots/components/custom-result/CustomResultSlotController.ts:77:21\",(selected),\"click\"]), fromEvent(selected, 'click')).pipe(takeUntil(sub)).subscribe(this.onSelectImageClick.bind(this));\n                }\n                this.rootStore.customResultStore.reelImageIndexes\n                    .pipe(takeUntil(sub))\n                    .subscribe(this.renderReelImages.bind(this));\n\n                content.activateButton.onclick = () => {\n                    this.onActivateButtonClick();\n                };\n                content.activateButton.checked = this.rootStore.customResultStore.isActive.value;\n\n                content.activateRngButton.onclick = () => {\n                    this.onActivateRngButtonClick();\n                };\n\n                content.customGambleButton.onclick = () => {\n                    this.onActivateGambleButtonClick();\n                };\n\n                content.resetButton.onclick = () => this.rootStore.customResultStore.setStartCustom();\n                content.customGambleButton.checked = this.rootStore.customResultStore.isCustomGamble.value;\n                fromEvent(content.rngInput, 'change').pipe(takeUntil(sub)).subscribe(this.onRngInputUpdate.bind(this));\n                fromEvent(content.rngInput, 'keydown')\n                    .pipe(takeUntil(sub))\n                    .subscribe((event) => {\n                        event.stopImmediatePropagation();\n                    });\n                fromEvent(content.rngInput, 'keyup')\n                    .pipe(takeUntil(sub))\n                    .subscribe((event) => {\n                        event.stopImmediatePropagation();\n                    });\n                // content.rngInput.addEventListener('change', this.onRngInputUpdate.bind(this), false);\n                // content.rngInput.addEventListener('keydown',;\n                // content.rngInput.addEventListener('keyup',event => {\n                //     event.stopImmediatePropagation();\n                // });\n                content.activateRngButton.checked = this.rootStore.customResultStore.isRngActive.value;\n\n                break;\n            }\n\n            case 'Settings':\n                {\n                    const content: CustomResultSettingsContentView = new CustomResultSettingsContentView(\n                        this.view.contentHolder,\n                    );\n                    this.view.contentView = content;\n\n                    content.mediaButton.onclick = () => {\n                        this.onMediaInfoButtonClick();\n                    };\n                    content.mediaButton.selected = this.rootStore.customResultStore.isMediaInfoShown.value;\n\n                    content.disconnectButton.onclick = () => {\n                        this.onActivateDisconnectButtonClick();\n                    };\n                    content.disconnectButton.selected = this.rootStore.customResultStore.isDisconnectButtonAdded.value;\n                    content.consoleButton.onclick = () => {\n                        this.onActivateConsoleButtonClick();\n                    };\n                    content.consoleButton.checked = this.rootStore.customResultStore.isConsoleButtonAdded.value;\n\n                    content.fpsMeterButton.selected = this.rootStore.customResultStore.isFpsShown.value;\n                    content.fpsMeterButton.onclick = () => {\n                        this.onFpsButtonClick();\n                    };\n                    content.animSpeedButton.selected = this.rootStore.customResultStore.isFpsShown.value;\n                    content.animSpeedButton.onclick = () => {\n                        this.onAnimSpeedButtonClick();\n                    };\n                    content.downloadPaytableButton.selected =\n                        this.rootStore.customResultStore.isDownloadPaytableButtonShown.value;\n                    content.downloadPaytableButton.onclick = () => {\n                        this.onDownloadPaytableButtonClick();\n                    };\n                }\n                break;\n            case 'Bot':\n                {\n                    const content: CustomResultBotContentView = new CustomResultBotContentView(\n                        this.view.contentHolder,\n                        this.rootStore,\n                    );\n                    this.view.contentView = content;\n                    content.gambleRedBlack.onchange = () => {\n                        this.rootStore.customResultStore.gambleRedBlack = content.gambleRedBlack.valueAsNumber;\n                    };\n\n                    content.gambleCollect.onchange = () => {\n                        this.rootStore.customResultStore.gambleCollect = content.gambleCollect.valueAsNumber;\n                    };\n                    content.playGamble.onchange = () => {\n                        this.rootStore.customResultStore.playGamble = content.playGamble.valueAsNumber;\n                    };\n                    content.fastStop.onchange = () => {\n                        this.rootStore.customResultStore.fastStop = content.fastStop.valueAsNumber;\n                    };\n                    content.changeBet.onchange = () => {\n                        this.rootStore.customResultStore.changeBet = content.changeBet.valueAsNumber;\n                    };\n                    content.betSpeed.onchange = () => {\n                        this.rootStore.customResultStore.betSpeed = content.betSpeed.valueAsNumber;\n                    };\n                    content.activateButton.onclick = () => {\n                        this.onInfinityPlayButtonClick();\n                    };\n\n                    content.activateButton.checked = this.rootStore.customResultStore.isInfinityPlayButtonActive.value;\n                }\n                break;\n            case 'Scenario': {\n                const content: CustomResultScenarioContentView = new CustomResultScenarioContentView(\n                    this.view.contentHolder,\n                    this.rootStore,\n                    this.slotConfiguration,\n                    this.tabChanged,\n                );\n                this.view.contentView = content;\n\n                content.activateButton.onclick = () => {\n                    this.onActivateScenarioButtonClick();\n                };\n                content.activateButton.checked = this.rootStore.customResultStore.isScenarioButtonActive.value;\n\n                content.butLoad.onclick = () => {\n                    content.activeContent = 'Load';\n                    this.rootStore.customResultStore.setStartCustom();\n                    this.loadScenarios();\n                };\n\n                content.butNew.onclick = () => {\n                    content.newScenario();\n                    this.rootStore.customResultStore.setStartCustom();\n                    this.rootStore.customResultStore.newScenario();\n                    this.addScenarioActions();\n                };\n\n                content.butMulitple.onclick = () => {\n                    this.rootStore.customResultStore.setStartCustom();\n                    content.activeContent = 'Multi';\n                    content.newMultiple();\n                    this.loadScenarios();\n                };\n                this.rootStore.customResultStore.scenarioNextPage\n                    .pipe(takeUntil(sub))\n                    .subscribe(this.scenarioViewProgress.bind(this));\n\n                break;\n            }\n            case 'Sound':\n                {\n                    const content: CustomResultSoundContentView = new CustomResultSoundContentView(\n                        this.view.contentHolder,\n                        this.slotConfiguration,\n                    );\n                    this.view.contentView = content;\n\n                    content.soundsButton.onclick = () => {\n                        this.onActivateSoundDebugButtonClick();\n                    };\n                    // Set the cached value\n                    content.soundsButton.checked = this.rootStore.customResultStore.isDebugSounds.value;\n                    Core.sounds.debug = this.rootStore.customResultStore.isDebugSounds.value;\n                }\n                break;\n            case 'Video':\n                {\n                    const content: CustomResultVideoContentView = new CustomResultVideoContentView(\n                        this.view.contentHolder,\n                        this.slotConfiguration,\n                    );\n                    this.view.contentView = content;\n\n                    // content.soundsButton.onclick = () => {\n                    //     this.onActivateSoundDebugButtonClick();\n                    // };\n                    // // Set the cached value\n                    // content.soundsButton.checked = this.rootStore.customResultStore.isDebugSounds.value;\n                    // Core.sounds.debug = this.rootStore.customResultStore.isDebugSounds.value;\n                }\n                break;\n        }\n        super.toggleTabs(index);\n    }\n    public openHolder(): void {\n        super.openHolder();\n        if (this.activeTabIndex === 1 && !this.view.closed) {\n            this.toggleTabs(1);\n        }\n    }\n\n    protected renderReelImages(arr: number[]): void {\n        const length = arr.length;\n        const content = this.view.contentView as CustomResultCustomContentView;\n        content.setReels(arr);\n        if (this.rootStore.subjects.NUMBER_OF_GUARD_SYMBOLS.value > 0) {\n            content.addGuardBlockers();\n        }\n\n        for (let i = 0; i < length; i++) {\n            (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/slot/src/egt/slots/components/custom-result/CustomResultSlotController.ts:278:13\",(content.reelImages[i]),\"click\"]), fromEvent(content.reelImages[i], 'click'))\n                .pipe(takeUntil(this.DESTROY))\n                .subscribe(this.onReelImageClick.bind(this));\n        }\n    }\n\n    protected onReelImageClick(event: any): void {\n        const selectedId = Number(event.target.id.split('_')[1]);\n        this.rootStore.customResultStore.selectImageIndex(selectedId);\n    }\n\n    private loadScenarios(): void {\n        const xhr = new XMLHttpRequest();\n        xhr.open(\n            'GET',\n            Core.configuration.scenarioHost +\n                'casinos/' +\n                Core.configuration.casinoId +\n                '/games/' +\n                Core.configuration.gameKey +\n                '/scenarios',\n            true,\n        );\n\n        xhr.setRequestHeader('Content-Type', 'text/json');\n        xhr.onreadystatechange = (e: any) => {\n            if (e.target.readyState === XMLHttpRequest.DONE && e.target.status === 200) {\n                const content = this.view.contentView as CustomResultScenarioContentView;\n                const selectOptions = JSON.parse(e.target.response);\n                content.scenariosLoaded(selectOptions);\n                content.selectScenario.onchange = () => {\n                    if (content.activeContent === 'Load') {\n                        content.newScenario();\n                        this.rootStore.customResultStore.loadTextScenario(content.selectScenario.value);\n                        this.addScenarioActions();\n                    } else {\n                        const but = content.addScenario(\n                            content.selectScenario.value,\n                            selectOptions[content.selectScenario.selectedIndex - 1].name,\n                        );\n                        this.rootStore.customResultStore.addScenarioToList(content.selectScenario.value);\n\n                        but.onclick = () => {\n                            const id = but.id.split('_')[1];\n                            this.rootStore.customResultStore.removeScenarioFromList(id);\n                            content.removeScenarioFromList(but.id);\n                        };\n                    }\n                };\n            }\n        };\n        xhr.onloadend = (e: any) => {\n            if (e.target.status === 404) {\n                alert('No available scenarios for this game.');\n            }\n        };\n        xhr.send();\n    }\n\n    private addScenarioActions(): void {\n        const sub = merge(this.DESTROY, this.tabChanged);\n        const content = this.view.contentView as CustomResultScenarioContentView;\n\n        this.rootStore.customResultStore.isScenarioButtonActive.pipe(takeUntil(sub)).subscribe(() => {\n            content.activateButton.checked = this.rootStore.customResultStore.isScenarioButtonActive.value;\n        });\n        content.butPrev.onclick = () => {\n            this.rootStore.customResultStore.scenarioPrev();\n            content.updateRound();\n        };\n\n        content.butNext.onclick = () => {\n            this.rootStore.customResultStore.scenarioNext();\n            content.updateRound();\n        };\n\n        content.selectSymbols.onchange = () => {\n            if (content.selectSymbols.value === 'Symbols') {\n                this.rootStore.customResultStore.setScenarioSymbolsPerPage(\n                    this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value,\n                );\n            } else {\n                this.rootStore.customResultStore.setScenarioSymbolsPerPage(Number(content.selectSymbols.value));\n            }\n        };\n\n        for (const selected of content.selectImages) {\n            (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/slot/src/egt/slots/components/custom-result/CustomResultSlotController.ts:365:13\",(selected),\"click\"]), fromEvent(selected, 'click')).pipe(takeUntil(sub)).subscribe(this.onSelectImageClick.bind(this));\n        }\n        this.rootStore.customResultStore.reelImageIndexes\n            .pipe(takeUntil(sub))\n            .subscribe(this.renderScenarioReelImages.bind(this));\n\n        content.butCopy.onclick = () => {\n            this.rootStore.customResultStore.copyStep();\n            content.updateRound();\n        };\n\n        content.butDeleleStep.onclick = () => {\n            this.rootStore.customResultStore.deleteStep();\n            // content.updateRound();\n        };\n    }\n\n    private onActivateAutoPlayFeatureClick(): void {\n        const content = this.view.contentView as CustomResultCustomContentView;\n        this.rootStore.customResultStore.isAutoPlayFeatures.next(\n            !this.rootStore.customResultStore.isAutoPlayFeatures.value,\n        );\n        content.autoPlayFeatureButton.checked = this.rootStore.customResultStore.isAutoPlayFeatures.value;\n    }\n\n    private onActivateGambleButtonClick(): void {\n        const content = this.view.contentView as CustomResultCustomContentView;\n        this.rootStore.customResultStore.isCustomGamble.next(!this.rootStore.customResultStore.isCustomGamble.value);\n        content.customGambleButton.checked = this.rootStore.customResultStore.isCustomGamble.value;\n    }\n\n    private scenarioViewProgress(): void {\n        this.scenarioView.update();\n        if (\n            this.rootStore.customResultStore.isActive.value &&\n            this.rootStore.customResultStore.scenarioNextPage.value >\n                this.rootStore.customResultStore.scenarioAllPage &&\n            this.rootStore.customResultStore.scenarioList.length === 0\n        ) {\n            this.scenarioView.toggle(false);\n        }\n    }\n    private renderScenarioReelImages(arr: number[]): void {\n        this.renderReelImages(arr);\n        const content = this.view.contentView as CustomResultScenarioContentView;\n        content.updateRound();\n    }\n\n    private onSelectImageClick(event: any): void {\n        const selectedId = Number(event.target.id.split('_')[1]);\n        this.rootStore.customResultStore.selectedImageIndex.next(selectedId);\n        const content = this.view.contentView as CustomResultCustomContentView;\n        content.setSelectedSymbol(selectedId);\n    }\n\n    private onActivateButtonClick(): void {\n        const content = this.view.contentView as CustomResultCustomContentView;\n        this.rootStore.customResultStore.isActive.next(!this.rootStore.customResultStore.isActive.value);\n        content.activateButton.checked = this.rootStore.customResultStore.isActive.value;\n    }\n\n    private onActivateRngButtonClick(): void {\n        const content = this.view.contentView as CustomResultCustomContentView;\n        this.rootStore.customResultStore.isRngActive.next(!this.rootStore.customResultStore.isRngActive.value);\n        content.activateRngButton.checked = this.rootStore.customResultStore.isRngActive.value;\n    }\n\n    private onRngInputUpdate(e): void {\n        // check if has any valid values\n        if (e.target.value.match(/(\\d)+/g)) {\n            this.rootStore.customResultStore.rngValues.next(e.target.value.match(/(\\d)+/g).map(Number));\n        } else {\n            this.rootStore.customResultStore.rngValues.next([]);\n        }\n    }\n\n    private onActivateScenarioButtonClick(): void {\n        const content = this.view.contentView as CustomResultScenarioContentView;\n        this.rootStore.customResultStore.isScenarioButtonActive.next(\n            !this.rootStore.customResultStore.isScenarioButtonActive.value,\n        );\n        this.rootStore.customResultStore.isActive.next(this.rootStore.customResultStore.isScenarioButtonActive.value);\n        this.scenarioView.toggle(this.rootStore.customResultStore.isScenarioButtonActive.value);\n        content.activateButton.checked = this.rootStore.customResultStore.isScenarioButtonActive.value;\n    }\n\n    private onActivateSoundDebugButtonClick(): void {\n        const content = this.view.contentView as CustomResultSoundContentView;\n        this.rootStore.customResultStore.isDebugSounds.next(!this.rootStore.customResultStore.isDebugSounds.value);\n        Core.sounds.debug = this.rootStore.customResultStore.isDebugSounds.value;\n        content.soundsButton.checked = this.rootStore.customResultStore.isDebugSounds.value;\n    }\n\n    private onMediaInfoButtonClick(): void {\n        const content = this.view.contentView as CustomResultSettingsContentView;\n\n        this.rootStore.customResultStore.isMediaInfoShown.next(\n            !this.rootStore.customResultStore.isMediaInfoShown.value,\n        );\n        if (Core.devTools) {\n            Core.devTools.toggleMediaInfo(this.rootStore.customResultStore.isMediaInfoShown.value);\n        }\n        content.mediaButton.selected = this.rootStore.customResultStore.isMediaInfoShown.value;\n    }\n\n    private onInfinityPlayButtonClick(): void {\n        const content = this.view.contentView as CustomResultBotContentView;\n        this.rootStore.customResultStore.isInfinityPlayButtonActive.next(\n            !this.rootStore.customResultStore.isInfinityPlayButtonActive.value,\n        );\n        content.activateButton.checked = this.rootStore.customResultStore.isInfinityPlayButtonActive.value;\n    }\n\n    private onActivateDisconnectButtonClick(): void {\n        const content = this.view.contentView as CustomResultSettingsContentView;\n\n        this.rootStore.customResultStore.isDisconnectButtonAdded.next(\n            !this.rootStore.customResultStore.isDisconnectButtonAdded.value,\n        );\n        content.disconnectButton.selected = this.rootStore.customResultStore.isDisconnectButtonAdded.value;\n    }\n    private onFpsButtonClick(): void {\n        const content = this.view.contentView as CustomResultSettingsContentView;\n\n        this.rootStore.customResultStore.isFpsShown.next(!this.rootStore.customResultStore.isFpsShown.value);\n        if (Core.devTools) {\n            Core.devTools.toggleFpsInfo(this.rootStore.customResultStore.isFpsShown.value);\n        }\n        content.fpsMeterButton.selected = this.rootStore.customResultStore.isFpsShown.value;\n    }\n\n    private onAnimSpeedButtonClick(): void {\n        const content = this.view.contentView as CustomResultSettingsContentView;\n\n        this.rootStore.customResultStore.isSpeedButtonShown.next(\n            !this.rootStore.customResultStore.isSpeedButtonShown.value,\n        );\n        if (Core.devTools) {\n            Core.devTools.toggleAnimSpeedButton(this.rootStore.customResultStore.isSpeedButtonShown.value);\n        }\n        content.animSpeedButton.selected = this.rootStore.customResultStore.isSpeedButtonShown.value;\n    }\n    private onDownloadPaytableButtonClick(): void {\n        const content = this.view.contentView as CustomResultSettingsContentView;\n\n        this.rootStore.customResultStore.isDownloadPaytableButtonShown.next(\n            !this.rootStore.customResultStore.isDownloadPaytableButtonShown.value,\n        );\n        content.downloadPaytableButton.selected = this.rootStore.customResultStore.isDownloadPaytableButtonShown.value;\n    }\n\n    private onActivateConsoleButtonClick(): void {\n        const content = this.view.contentView as CustomResultSettingsContentView;\n        this.rootStore.customResultStore.isConsoleButtonAdded.next(\n            !this.rootStore.customResultStore.isConsoleButtonAdded.value,\n        );\n        if (Core.devTools) {\n            Core.devTools.toggleConsole(this.rootStore.customResultStore.isConsoleButtonAdded.value);\n        }\n\n        content.consoleButton.selected = this.rootStore.customResultStore.isConsoleButtonAdded.value;\n    }\n}\n","import Core from '@egt/core';\nimport { CustomResultView } from '@egt/custom-result';\nimport { takeUntil } from 'rxjs/operators';\nimport SockJS from 'sockjs-client';\nimport { inject, injectable } from 'tsyringe';\nimport { ISlotConfiguration } from '../../slot-configuration/ISlotConfiguration';\nimport RootStore from '../root/RootStore';\n\n@injectable()\nexport default class CustomResultSlotView extends CustomResultView {\n    public title = 'Custom result Slot view';\n\n    constructor(\n        @inject('ISlotConfiguration') public slotConfiguration: ISlotConfiguration,\n        @inject('RootStore') public rootStore: RootStore,\n    ) {\n        super();\n    }\n\n    public destroy(): void {\n        super.destroy();\n        if (this.rootStore) {\n            // @ts-ignore\n            this.rootStore = null;\n        }\n        if (this.slotConfiguration) {\n            // @ts-ignore\n            this.slotConfiguration = null;\n        }\n        const sHolder = document.getElementById('soundsHolder');\n        if (sHolder) {\n            sHolder.remove();\n        }\n\n        const s = document.getElementById('reasonDisconnect');\n        if (s) {\n            s.remove();\n        }\n        const b = document.getElementById('btnDisconnect');\n        if (b) {\n            b.remove();\n        }\n    }\n\n    public init(): void {\n        super.init();\n        this.generateTabs();\n        this.rootStore.customResultStore.isDisconnectButtonAdded\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe(this.isDisconnectButtonActive.bind(this));\n    }\n\n    public generateTabs(): void {\n        const resultSettings = document.createElement('span') as HTMLDivElement;\n        resultSettings.innerText = 'Custom Result';\n        resultSettings.className = 'tab active';\n        this.tabsHolder.appendChild(resultSettings);\n        this.tabsArray.push({ action: this.setContentCustom.bind(this), button: resultSettings, type: 'Custom' });\n\n        const scenarioSettings = document.createElement('span') as HTMLDivElement;\n        scenarioSettings.innerText = 'Scenarios';\n        scenarioSettings.className = 'tab';\n        this.tabsHolder.appendChild(scenarioSettings);\n        this.tabsArray.push({ action: this.setContentScenario.bind(this), button: scenarioSettings, type: 'Scenario' });\n\n        const botSettings = document.createElement('span') as HTMLDivElement;\n        botSettings.innerText = 'Bot';\n        botSettings.className = 'tab';\n        this.tabsHolder.appendChild(botSettings);\n        this.tabsArray.push({ action: this.setContentScenario.bind(this), button: botSettings, type: 'Bot' });\n\n        const soundSettings = document.createElement('span') as HTMLDivElement;\n        soundSettings.innerText = 'Sound';\n        soundSettings.className = 'tab';\n        this.tabsHolder.appendChild(soundSettings);\n        this.tabsArray.push({ action: this.setContentScenario.bind(this), button: soundSettings, type: 'Sound' });\n\n        const videoSettings = document.createElement('span') as HTMLDivElement;\n        videoSettings.innerText = 'Video';\n        videoSettings.className = 'tab';\n        this.tabsHolder.appendChild(videoSettings);\n        this.tabsArray.push({ action: this.setContentScenario.bind(this), button: videoSettings, type: 'Video' });\n\n        super.generateTabs();\n    }\n\n    public setContentCustom(): void {\n        this.resizeView();\n        //  this.initialRenderrer()\n    }\n\n    public setContentScenario(): void {\n        //\n    }\n\n    // ******* START DISCONNECTION TESTING FUNCTIONALITY ********\n    private isDisconnectButtonActive(value): void {\n        if (value) {\n            if (!document.getElementById('btnDisconnect')) {\n                const appDiv = document.getElementById('app-root');\n\n                const s: HTMLInputElement = document.createElement('input');\n                s.style.position = 'absolute';\n                s.style.top = '0';\n                s.style.right = '80px';\n                s.style.zIndex = '100';\n                s.style.width = '120px';\n                s.placeholder = '1000 or 3000-4999';\n                s.id = 'reasonDisconnect';\n                appDiv?.appendChild(s);\n                // document.body.insertAdjacentElement('afterbegin', s);\n                const b: HTMLButtonElement = document.createElement('button');\n                b.innerText = 'Disconnect';\n                b.style.position = 'absolute';\n                b.style.top = '0';\n                b.style.right = '0';\n                b.style.zIndex = '100';\n                b.id = 'btnDisconnect';\n                b.onclick = () => {\n                    const reason = (document.getElementById('reasonDisconnect') as HTMLInputElement).value.trim();\n                    if (reason !== '') {\n                        let errorMessage = Core.translator.translate('unhandledError');\n                        if (Core.translator.hasTranslateFor(reason)) {\n                            errorMessage = Core.translator.translate(reason);\n                        }\n                        errorMessage = errorMessage.replace('##ERROR_CODE##', reason);\n                        (Core.connection as SockJS)._transport.ws.close(\n                            Number(reason),\n                            'Test error code ' + Number(reason),\n                        );\n                    } else {\n                        (Core.connection as SockJS)._transport.ws.close(3000, 'Test disconnection');\n                    }\n                };\n                appDiv?.appendChild(b);\n            }\n        } else {\n            const s = document.getElementById('reasonDisconnect');\n            if (s) {\n                s.remove();\n            }\n            const b = document.getElementById('btnDisconnect');\n            if (b) {\n                b.remove();\n            }\n        }\n    }\n    // =========== DISCONNECTION TESTING FUNCTIONALITY =============\n}\n","import Core, { BaseStore } from '@egt/core';\nimport { BehaviorSubject } from 'rxjs';\nimport { ISlotConfiguration } from '../../slot-configuration/ISlotConfiguration';\nimport SlotComponents from '../enums/SlotComponents';\nimport RootStore from '../root/RootStore';\nimport { Logger } from 'unicorn.console-logger';\n\nexport default class CustomResultStore extends BaseStore {\n    public readonly isActive: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly copyLastResponseActive: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly isRngActive: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly rngValues: BehaviorSubject<number[]> = new BehaviorSubject<number[]>([]);\n    public readonly areShieldValuesActive: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly shieldValues: BehaviorSubject<number[]> = new BehaviorSubject<number[]>([]);\n    public readonly selectedImageIndex: BehaviorSubject<number> = new BehaviorSubject<number>(0);\n    public readonly isFakeAnticipationActived: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly isOldRespinActived: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly isNewRespinActived: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly isDrag: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly isGuardSymbolsAvailableForChange: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly reelImageIndexes: BehaviorSubject<number[][]> = new BehaviorSubject<number[][]>([]);\n    public readonly horizontalReelImageIndex: BehaviorSubject<number[]> = new BehaviorSubject<number[]>([]);\n    public readonly isViewOpened: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly isInfinityPlayButtonActive: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly isDisconnectButtonAdded: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly isConsoleButtonAdded: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly isFpsToggled: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly isSoundReplaceAdded: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly isDebugSounds: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly isMultilayeredBackgroundSoundsPanelEnabled: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(\n        false,\n    );\n    public readonly isMediaInfoShown: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly isBonusButtonActive: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly isScenarioButtonActive: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly isFpsShown: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly isSpeedButtonShown: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly isMystery: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly isDRGRespin: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly isDRGPick: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly isHighCashFreespinsChoice: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly isHighCashWheelChoice: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly isDownloadPaytableButtonShown: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly highCashRespinWheelValue: BehaviorSubject<number> = new BehaviorSubject<number>(-1);\n    public readonly isHighCashRespinWheelRetrigger: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly multislamValue: BehaviorSubject<number> = new BehaviorSubject<number>(-1);\n    public readonly isCustomGamble: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly scenarioImageIndexes: BehaviorSubject<number[][][]> = new BehaviorSubject<number[][][]>([]); // pages of reels\n    public readonly scenarioNextPage: BehaviorSubject<number> = new BehaviorSubject<number>(0); // current page index in request\n    public readonly isAutoPlayFeatures: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);\n    public readonly isFreeSpinsChoiceResult: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);\n    public readonly isGAKLJackpotFeatureResult: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly isBLBoostJackpotTrigger: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly isCustomDemoFeatureResult: BehaviorSubject<{ feature: string; customValue: boolean }> =\n        new BehaviorSubject<{ feature: string; customValue: boolean }>({ feature: '', customValue: false });\n    public readonly symbolsPerReel: BehaviorSubject<number[]> = new BehaviorSubject<number[]>([]);\n    public readonly scenarioSymbolsPerReel: BehaviorSubject<number[][]> = new BehaviorSubject<number[][]>([]);\n    public readonly leprechaunWheelFeatures: BehaviorSubject<any[]> = new BehaviorSubject<any[]>([false, false]);\n\n    public readonly pearlyBeachFeatures: BehaviorSubject<{\n        activator?: boolean;\n        wildReplace?: boolean;\n        potSymbol?: boolean;\n        coolerSymbol?: boolean;\n        characterMarks?: boolean;\n        maxWin?: boolean;\n    }> = new BehaviorSubject<{\n        activator?: boolean;\n        wildReplace?: boolean;\n        potSymbol?: boolean;\n        coolerSymbol?: boolean;\n        characterMarks?: boolean;\n        maxWin?: boolean;\n    }>({\n        activator: false,\n        wildReplace: false,\n        potSymbol: false,\n        coolerSymbol: false,\n        characterMarks: false,\n        maxWin: false,\n    });\n    public readonly advancedLogging: BehaviorSubject<boolean>;\n    // ===== Win Animations Preview (dev tool) START =====\n    public readonly WIN_ANIMATIONS_PREVIEW_ACTIVE: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly WIN_ANIMATIONS_EXPAND_PREVIEW_ACTIVE: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(\n        false,\n    );\n    // ===== Win Animations Preview (dev tool) END =====\n    public scenarioAllPage = 0; // page count\n    public scenarioIndexPage = 0; // current page index in custom\n    public scenarioName: string = '';\n    public scenarioPageSymbols: number[] = []; // symbols per reel\n    public scenarioID = -1;\n    public mysteryType = 'MINI';\n    public scenarioList: any[] = [];\n    public scenarioListIndex: number = -1;\n\n    // BOT SETTINGS/////\n    public playGamble: number = 50;\n    public gambleRedBlack: number = 50;\n    public gambleCollect: number = 50;\n    public changeBet: number = 50;\n    public fastStop: number = 50;\n    public betSpeed: number = 50;\n\n    //////////////////////\n\n    constructor(\n        private rootStore: RootStore,\n        private slotConfiguration: ISlotConfiguration,\n    ) {\n        super();\n        const urlParams = new URLSearchParams(window.location.href);\n        const enableAdvancedLog = urlParams.get('advancedLog') === 'true';\n        this.advancedLogging = new BehaviorSubject<boolean>(enableAdvancedLog);\n        this.enableLogging();\n        const reelImageIndexes: number[][] = [[]];\n        const symbolsPerReel: number[] = [];\n        let horizontalReelImageIndex: number[] = [];\n        const length: number =\n            rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value + this.rootStore.subjects.NUMBER_OF_GUARD_SYMBOLS.value;\n\n        for (let reel = 0; reel < this.rootStore.subjects.NUMBER_OF_REELS.value; reel++) {\n            reelImageIndexes.push([]);\n            for (let i = 0; i < length; i++) {\n                reelImageIndexes[reel].push(0);\n                symbolsPerReel.push(0);\n            }\n        }\n\n        this.scenarioPageSymbols[0] =\n            rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value + this.rootStore.subjects.NUMBER_OF_GUARD_SYMBOLS.value;\n        this.reelImageIndexes.next(reelImageIndexes);\n        this.symbolsPerReel.next(symbolsPerReel);\n        if (Core.hasComponent(SlotComponents.HORIZONTAL_REEL)) {\n            horizontalReelImageIndex = [0, 0, 0, 0, 0, 0];\n        }\n        this.horizontalReelImageIndex.next(horizontalReelImageIndex);\n    }\n\n    get rngRequest(): any {\n        if (!this.isRngActive.value) {\n            return null;\n        }\n        return this.rngValues.value;\n    }\n\n    get request(): any {\n        if (!this.isActive.value) {\n            return null;\n        }\n        this.scenarioNextPage.next(this.scenarioNextPage.value + 1);\n\n        if (this.scenarioListIndex > -1 && this.scenarioList.length > 0) {\n            if (this.scenarioID === -1) {\n                this.loadScenarioFromList(this.scenarioListIndex);\n            } else if (\n                this.scenarioListIndex < this.scenarioList.length - 1 &&\n                this.scenarioNextPage.value > this.scenarioAllPage\n            ) {\n                this.scenarioListIndex++;\n                this.loadScenarioFromList(this.scenarioListIndex);\n            } else if (this.scenarioListIndex === this.scenarioList.length - 1) {\n                this.scenarioListIndex = -1;\n                this.scenarioList = [];\n                this.scenarioID = -1;\n            }\n        }\n        // If all pages passed return custom result\n        if (this.isScenarioButtonActive.value && this.scenarioNextPage.value > this.scenarioAllPage) {\n            this.isActive.next(false);\n            this.isScenarioButtonActive.next(false);\n            this.isFpsShown.next(false);\n\n            return null;\n        }\n\n        // Fill scenario data\n        if (this.isScenarioButtonActive.value && this.scenarioImageIndexes.value.length > 0) {\n            this.symbolsPerReel.next(this.scenarioSymbolsPerReel.value[this.scenarioNextPage.value - 1]);\n            const result = this.enforceLengthConstraints(\n                this.scenarioImageIndexes.value[this.scenarioNextPage.value - 1],\n                this.symbolsPerReel.value,\n            );\n            this.reelImageIndexes.next(result);\n        }\n        const sendArr: number[][] = JSON.parse(JSON.stringify(this.reelImageIndexes.value));\n\n        if (!this.slotConfiguration.customSendGuards) {\n            sendArr.forEach((arr) => {\n                arr.shift();\n                arr.pop();\n            });\n        }\n        return sendArr;\n    }\n\n    public enforceLengthConstraints(arrayOfIndexes, lengthConstraints) {\n        // Ensure both arrays are of the same length\n        if (arrayOfIndexes.length !== lengthConstraints.length) {\n            throw new Error('Both input arrays must have the same length.');\n        }\n\n        // Iterate through each subarray in arrayOfIndexes\n        for (let i = 0; i < arrayOfIndexes.length; i++) {\n            const maxLength = lengthConstraints[i]; // Get the max length for the current subarray\n\n            if (Array.isArray(arrayOfIndexes[i])) {\n                // Truncate the subarray to the maximum length\n                arrayOfIndexes[i] = arrayOfIndexes[i].slice(0, maxLength);\n\n                // Optionally, pad with a default value if the subarray is shorter than the maxLength\n                while (arrayOfIndexes[i].length < maxLength) {\n                    arrayOfIndexes[i].push(null); // You can change `null` to any other default value\n                }\n            }\n        }\n\n        return arrayOfIndexes;\n    }\n\n    //this is necessary for uneven reels cases - e.g. 3x4x3 matrix and using the universal reels component so that the custom symbols are displayed properly\n    private getNumberOfSymbols(reelIndex: number): number {\n        let res = 0;\n        if (Core.hasComponent(SlotComponents.UNIVERSAL_REELS)) {\n            res = this.rootStore.subjects.UNIVERSAL_SYMBOLS_PER_REEL.value[reelIndex];\n        } else {\n            res = this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value;\n        }\n        return res + this.rootStore.subjects.NUMBER_OF_GUARD_SYMBOLS.value;\n    }\n\n    // Restore default reels\n    public restoreReels(): void {\n        const reelImageIndexes: number[][] = [];\n        const horizontalReelImageIndex: number[] = [];\n        const symbolsPerReel: number[] = [];\n        this.scenarioPageSymbols[this.scenarioIndexPage] =\n            this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value +\n            this.rootStore.subjects.NUMBER_OF_GUARD_SYMBOLS.value;\n\n        for (let reel = 0; reel < this.rootStore.subjects.NUMBER_OF_REELS.value; reel++) {\n            reelImageIndexes[reel] = [];\n            symbolsPerReel.push(this.getNumberOfSymbols(reel));\n\n            for (let i = 0; i < this.getNumberOfSymbols(reel); i++) {\n                reelImageIndexes[reel][i] = 0;\n            }\n        }\n        if (Core.hasComponent(SlotComponents.HORIZONTAL_REEL)) {\n            for (let i = 0; i < this.horizontalReelImageIndex.value.length; i++) {\n                horizontalReelImageIndex.push(0);\n            }\n\n            reelImageIndexes.push(horizontalReelImageIndex);\n        }\n        this.reelImageIndexes.next(reelImageIndexes);\n        this.symbolsPerReel.next(symbolsPerReel);\n    }\n\n    public setStartCustom(): void {\n        this.scenarioAllPage = 1;\n        this.scenarioIndexPage = 0;\n        this.scenarioName = '';\n        this.scenarioPageSymbols = [];\n        this.scenarioID = -1;\n        this.scenarioList = [];\n        this.scenarioListIndex = -1;\n        this.scenarioPageSymbols[0] =\n            this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value +\n            this.rootStore.subjects.NUMBER_OF_GUARD_SYMBOLS.value;\n        this.restoreReels();\n    }\n\n    // Set custom number of reels per page - In case of BellLink for example\n    public setScenarioSymbolsPerPage(val: number): void {\n        this.scenarioPageSymbols[this.scenarioIndexPage] = val + this.rootStore.subjects.NUMBER_OF_GUARD_SYMBOLS.value;\n\n        const newReelImages: number[][] = [];\n        const symbolsPerReel: number[] = [];\n\n        for (let i = 0; i < this.rootStore.subjects.NUMBER_OF_REELS.value; i++) {\n            newReelImages[i] = [];\n            for (let j = 0; j < this.scenarioPageSymbols[this.scenarioIndexPage]; j++) {\n                newReelImages[i][j] = 0;\n            }\n            symbolsPerReel.push(this.scenarioPageSymbols[this.scenarioIndexPage]);\n        }\n        const scenario = this.scenarioImageIndexes.value;\n        scenario[this.scenarioIndexPage] = newReelImages;\n        this.scenarioImageIndexes.next(scenario);\n        const scenarioSymbolsPerReel = this.scenarioSymbolsPerReel.value;\n        scenarioSymbolsPerReel[this.scenarioIndexPage] = newReelImages[this.scenarioIndexPage];\n        this.scenarioSymbolsPerReel.next(scenarioSymbolsPerReel);\n\n        this.reelImageIndexes.next(newReelImages);\n    }\n\n    // Scenario next page\n    public scenarioNext(): void {\n        this.scenarioIndexPage += 1;\n\n        if (this.scenarioImageIndexes.value.length > this.scenarioIndexPage) {\n            this.reelImageIndexes.next(this.scenarioImageIndexes.value[this.scenarioIndexPage]);\n            this.symbolsPerReel.next(this.scenarioSymbolsPerReel.value[this.scenarioIndexPage]);\n        } else {\n            this.scenarioPageSymbols[this.scenarioIndexPage] =\n                this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value +\n                this.rootStore.subjects.NUMBER_OF_GUARD_SYMBOLS.value;\n            this.restoreReels();\n            const scenario = this.scenarioImageIndexes.value;\n            scenario[this.scenarioIndexPage] = this.reelImageIndexes.value;\n            this.scenarioImageIndexes.next(scenario);\n\n            const scenarioSymbolsPerReel = this.scenarioSymbolsPerReel.value;\n            scenarioSymbolsPerReel[this.scenarioIndexPage] = this.symbolsPerReel.value;\n            this.scenarioSymbolsPerReel.next(scenarioSymbolsPerReel);\n            this.scenarioAllPage += 1;\n        }\n    }\n\n    // Scenario prev page\n    public scenarioPrev(): void {\n        if (this.scenarioIndexPage > 0) {\n            this.scenarioIndexPage -= 1;\n            this.reelImageIndexes.next(this.scenarioImageIndexes.value[this.scenarioIndexPage]);\n\n            this.symbolsPerReel.next(this.scenarioSymbolsPerReel.value[this.scenarioIndexPage]);\n        }\n    }\n    public copyStep(): void {\n        this.scenarioIndexPage += 1;\n\n        const currStep = this.scenarioImageIndexes.value[this.scenarioIndexPage - 1];\n        const scenario = this.scenarioImageIndexes.value;\n        scenario.splice(this.scenarioIndexPage + 1, 0, currStep);\n        this.scenarioImageIndexes.next(scenario);\n\n        const currScenarioStep = this.scenarioSymbolsPerReel.value[this.scenarioIndexPage - 1];\n        const scenarioSymbolsPerReel = this.scenarioSymbolsPerReel.value;\n        scenarioSymbolsPerReel.splice(this.scenarioIndexPage + 1, 0, currScenarioStep);\n        this.scenarioAllPage += 1;\n\n        this.scenarioPageSymbols.splice(\n            this.scenarioIndexPage + 1,\n            0,\n            this.scenarioPageSymbols[this.scenarioIndexPage],\n        );\n\n        this.symbolsPerReel.next(this.symbolsPerReel.value);\n    }\n\n    public deleteStep(): void {\n        if (this.scenarioAllPage === 1) {\n            return;\n        }\n        this.scenarioAllPage -= 1;\n        if (this.scenarioIndexPage > -1) {\n            this.scenarioPageSymbols.splice(this.scenarioIndexPage, 1);\n\n            const scenario = this.scenarioImageIndexes.value;\n            scenario.splice(this.scenarioIndexPage, 1);\n\n            this.scenarioImageIndexes.next(scenario);\n            this.reelImageIndexes.next(this.scenarioImageIndexes.value[this.scenarioIndexPage]);\n            this.symbolsPerReel.next(this.scenarioSymbolsPerReel.value[this.scenarioIndexPage]);\n        } else {\n            this.newScenario();\n        }\n    }\n\n    // Set custom Symbol on place //TODO\n    public selectImageIndex(index: number): void {\n        const newReelImages = this.reelImageIndexes.value.slice();\n        newReelImages[index] = this.slotConfiguration.symbolsConfig[this.selectedImageIndex.value].index;\n        this.reelImageIndexes.next(newReelImages);\n\n        let numSymbol = 0;\n        for (let i = 0; i < this.scenarioIndexPage; i++) {\n            numSymbol += this.scenarioPageSymbols[i] * this.rootStore.subjects.NUMBER_OF_REELS.value;\n        }\n        const newReelScenarioImages = this.rootStore.customResultStore.scenarioImageIndexes.value.slice();\n        newReelScenarioImages[numSymbol + index] =\n            this.slotConfiguration.symbolsConfig[this.selectedImageIndex.value].index;\n        this.scenarioImageIndexes.next(newReelScenarioImages);\n    }\n\n    // Set new scenario\n    public newScenario(): void {\n        this.restoreReels();\n        this.scenarioPageSymbols = [\n            this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value +\n                this.rootStore.subjects.NUMBER_OF_GUARD_SYMBOLS.value,\n        ];\n        this.scenarioImageIndexes.next([this.reelImageIndexes.value]);\n        this.scenarioSymbolsPerReel.next([this.symbolsPerReel.value]);\n        this.scenarioName = 'Custom';\n        this.scenarioIndexPage = 0;\n        this.scenarioAllPage = 1;\n        this.scenarioNextPage.next(0);\n        this.scenarioID = -1;\n        this.isActive.next(true);\n    }\n\n    // Save scenario\n    public saveToServer(): void {\n        // Scenario exists - loaded from server\n        if (this.scenarioID > -1) {\n            const replace = confirm('Override scenario?');\n\n            if (replace) {\n                const scenarioObject = {\n                    scenarioName: this.scenarioName,\n                    scenarioAllPage: this.scenarioAllPage,\n                    scenarioImageIndexes: this.scenarioImageIndexes.value,\n                    scenarioSymbolsPerReel: this.scenarioSymbolsPerReel.value,\n                    scenarioPageSymbols: this.scenarioPageSymbols,\n                };\n                const data = JSON.stringify(scenarioObject);\n\n                const xhr = new XMLHttpRequest();\n                xhr.open(\n                    'PUT',\n                    Core.configuration.scenarioHost +\n                        'casinos/' +\n                        Core.configuration.casinoId +\n                        '/games/' +\n                        Core.configuration.gameKey +\n                        '/scenarios/' +\n                        this.scenarioID,\n                    true,\n                );\n\n                xhr.setRequestHeader('Content-Type', 'application/json');\n\n                xhr.onreadystatechange = (e: any) => {\n                    if (e.target.readyState === XMLHttpRequest.DONE && e.target.status === 200) {\n                        alert('Scenario Replaced');\n                    }\n                };\n                const sendParams =\n                    '{\"name\":\"' +\n                    this.scenarioName +\n                    '\",\"data\":\"' +\n                    this.escape(data) +\n                    '\",\"casino\":\"' +\n                    Core.configuration.casinoId +\n                    '\",\"game\":\"' +\n                    Core.configuration.gameKey +\n                    '\",\"player\":\"' +\n                    Core.configuration.playerId +\n                    '\"}';\n                xhr.send(sendParams);\n            }\n            // New scenario - input name\n        } else {\n            const scenarioNameIn = prompt('Please enter name for this Scenario', 'Scenario');\n            if (scenarioNameIn != null) {\n                const scenarioObject = {\n                    scenarioName: scenarioNameIn,\n                    scenarioAllPage: this.scenarioAllPage,\n                    scenarioImageIndexes: this.scenarioImageIndexes.value,\n                    scenarioSymbolsPerReel: this.scenarioSymbolsPerReel.value,\n                    scenarioPageSymbols: this.scenarioPageSymbols,\n                };\n                const data = JSON.stringify(scenarioObject);\n\n                const xhr = new XMLHttpRequest();\n                xhr.open('POST', Core.configuration.scenarioHost + 'scenarios', true);\n\n                // Send the proper header information along with the request\n                xhr.setRequestHeader('Content-Type', 'application/json');\n\n                xhr.onreadystatechange = (e: any) => {\n                    // Call a function when the state changes.\n\n                    if (e.target.readyState === XMLHttpRequest.DONE && e.target.status === 200) {\n                        // Request finished. Do processing here.\n                        const jsonResponse = JSON.parse(e.target.response);\n                        this.scenarioID = jsonResponse.id;\n                        this.scenarioIndexPage = 1;\n                        this.scenarioPrev();\n                        alert('Scenario Saved');\n                    }\n                };\n                const sendParams =\n                    '{\"name\":\"' +\n                    scenarioNameIn +\n                    '\",\"data\":\"' +\n                    this.escape(data) +\n                    '\",\"casino\":\"' +\n                    Core.configuration.casinoId +\n                    '\",\"game\":\"' +\n                    Core.configuration.gameKey +\n                    '\",\"player\":\"' +\n                    Core.configuration.playerId +\n                    '\"}';\n                xhr.send(sendParams);\n            }\n        }\n    }\n\n    public escape(val): string {\n        return val.replace(/[\\\"]/g, '/\"').replace(/[\\/]/g, '\\\\');\n    }\n\n    public unescape(val): string {\n        return val.replace(/[\\\\]/g, '');\n    }\n\n    // Load scenario to edit\n    public loadTextScenario(file): void {\n        const rawFile = new XMLHttpRequest();\n        rawFile.overrideMimeType('application/json');\n        rawFile.open(\n            'GET',\n            Core.configuration.scenarioHost +\n                'casinos/' +\n                Core.configuration.casinoId +\n                '/games/' +\n                Core.configuration.gameKey +\n                '/scenarios/' +\n                file,\n            true,\n        );\n        rawFile.onreadystatechange = (e: any) => {\n            if (e.target.readyState === 4 && e.target.status === 200) {\n                // this.isScenarioButtonActive.next(true);\n                const responseStr = unescape(e.target.responseText);\n                const jsonData = JSON.parse(responseStr);\n                const scenarioData = JSON.parse(jsonData.data.replace('/\\\\', ''));\n                this.scenarioImageIndexes.next(scenarioData.scenarioImageIndexes);\n                this.scenarioSymbolsPerReel.next(scenarioData.scenarioSymbolsPerReel);\n\n                this.scenarioAllPage = scenarioData.scenarioAllPage;\n                this.scenarioPageSymbols = scenarioData.scenarioPageSymbols;\n                this.scenarioName = scenarioData.scenarioName;\n                this.isActive.next(true);\n                this.scenarioNextPage.next(0);\n                this.scenarioID = file;\n                this.reelImageIndexes.next(this.scenarioImageIndexes.value[0]);\n                this.symbolsPerReel.next(this.scenarioSymbolsPerReel.value[0]);\n            }\n        };\n        rawFile.send();\n    }\n\n    // Load scenario to edit\n    public addScenarioToList(file): void {\n        const rawFile = new XMLHttpRequest();\n        rawFile.overrideMimeType('application/json');\n        rawFile.open(\n            'GET',\n            Core.configuration.scenarioHost +\n                'casinos/' +\n                Core.configuration.casinoId +\n                '/games/' +\n                Core.configuration.gameKey +\n                '/scenarios/' +\n                file,\n            true,\n        );\n        rawFile.onreadystatechange = (e: any) => {\n            if (e.target.readyState === 4 && e.target.status === 200) {\n                // this.isScenarioButtonActive.next(true);\n                const responseStr = unescape(e.target.responseText);\n                const jsonData = JSON.parse(responseStr);\n                const scenarioData = JSON.parse(jsonData.data.replace('/\\\\', ''));\n                scenarioData.id = file;\n\n                this.scenarioList.push(scenarioData);\n                this.isActive.next(true);\n                this.scenarioListIndex = 0;\n            }\n        };\n        rawFile.send();\n    }\n\n    public removeScenarioFromList(id): void {\n        this.scenarioList.forEach((scenario, index) => {\n            if (scenario.id === id) {\n                this.scenarioList.splice(index, 1);\n            }\n        });\n        if (this.scenarioList.length === 0) {\n            this.scenarioListIndex = -1;\n        }\n    }\n\n    public loadScenarioFromList(index): void {\n        const scenarioData = this.scenarioList[index];\n        this.scenarioImageIndexes.next(scenarioData.scenarioImageIndexes);\n        this.scenarioSymbolsPerReel.next(scenarioData.scenarioSymbolsPerReel);\n        this.scenarioAllPage = scenarioData.scenarioAllPage;\n        this.scenarioPageSymbols = scenarioData.scenarioPageSymbols;\n        this.scenarioName = scenarioData.scenarioName;\n        this.isActive.next(true);\n        this.scenarioNextPage.next(1);\n        this.scenarioID = scenarioData.id;\n        this.scenarioIndexPage = 0;\n        this.reelImageIndexes.next(this.scenarioImageIndexes.value[0]);\n        this.symbolsPerReel.next(this.scenarioSymbolsPerReel.value[0]);\n    }\n\n    // Delete scenario\n    public deleteScenario(): void {\n        if (this.scenarioID > -1) {\n            const remove = confirm('Delete scenario?');\n\n            if (remove) {\n                const rawFile = new XMLHttpRequest();\n                rawFile.overrideMimeType('application/json');\n                rawFile.open(\n                    'DELETE',\n                    Core.configuration.scenarioHost +\n                        'casinos/' +\n                        Core.configuration.casinoId +\n                        '/games/' +\n                        Core.configuration.gameKey +\n                        '/scenarios/' +\n                        this.scenarioID,\n                    true,\n                );\n                rawFile.onreadystatechange = (e: any) => {\n                    if (e.target.readyState === 4 && e.target.status === 200) {\n                        alert('Scenario Removed from the server!!');\n                        this.scenarioID = -1;\n                        this.scenarioIndexPage++;\n                        this.scenarioPrev();\n                    }\n                };\n\n                rawFile.send();\n            }\n        }\n    }\n\n    public destroy(): void {\n        // @ts-ignore\n        delete this.rootStore;\n    }\n\n    public updateAdvancedLogging(enable: boolean): void {\n        Logger.logServiceMessage([`Advanced logging ${enable ? 'enabled' : 'disabled'}`], this.constructor.name);\n        if (!enable) {\n            // we need to close all existing log groups before disabling advanced loggig\n            Logger.closeAllGroups();\n        }\n        Logger.init({ allowLogs: enable });\n        this.advancedLogging.next(enable);\n    }\n}\n","import { DomHelpers } from '@egt/core';\nimport { inject, injectable } from 'tsyringe';\nimport RootStore from '../root/RootStore';\n\n@injectable()\nexport default class ScenarioViewer {\n    private _rootContainer: HTMLElement;\n    private _textContainer: HTMLDivElement;\n\n    constructor(@inject('RootStore') private rootStore: RootStore) {\n        this._createContainer();\n    }\n\n    public destroy(): void {\n        if (this._rootContainer) {\n            this._rootContainer.remove();\n            // @ts-ignore\n            this._rootContainer = null;\n        }\n        if (this._textContainer) {\n            this._textContainer.remove();\n            // @ts-ignore\n            this._textContainer = null;\n        }\n    }\n\n    public update(): void {\n        if (this._rootContainer) {\n            this._textContainer.innerHTML =\n                this.rootStore.customResultStore.scenarioName +\n                ':' +\n                this.rootStore.customResultStore.scenarioNextPage.value +\n                '/ ' +\n                this.rootStore.customResultStore.scenarioAllPage;\n        }\n    }\n    public toggle(val: boolean): void {\n        if (this._rootContainer) {\n            if (val) {\n                this._rootContainer.className = 'scenario-info';\n            } else {\n                this._rootContainer.className = 'scenario-info hidden';\n            }\n        }\n    }\n\n    private _createContainer(): void {\n        // root container\n        this._rootContainer = DomHelpers.getElementOrCreateNew('scenario-info', 'div');\n        this._rootContainer.className = 'scenario-info';\n\n        // info text\n        this._textContainer = document.createElement('div');\n        this._rootContainer.appendChild(this._textContainer);\n        this.toggle(false);\n    }\n}\n","import { CustomResultContentView } from '@egt/custom-result';\nimport RootStore from '../../root/RootStore';\n\nexport default class CustomResultBotContentView extends CustomResultContentView {\n    public activateButton: HTMLInputElement;\n    public activateButHolder: HTMLDivElement;\n    public gambleRedBlack: HTMLInputElement;\n    public gambleCollect: HTMLInputElement;\n    public playGamble: HTMLInputElement;\n    public changeBet: HTMLInputElement;\n    public fastStop: HTMLInputElement;\n    public betSpeed: HTMLInputElement;\n\n    private optionsHolder: HTMLDivElement;\n    constructor(\n        public view: HTMLDivElement,\n        protected rootStore: RootStore,\n    ) {\n        super(view);\n\n        this.optionsHolder = document.createElement('div') as HTMLDivElement;\n\n        this.optionsHolder.className = 'botOptionsHolder';\n\n        this.view.appendChild(this.optionsHolder);\n\n        const sliderGamble = document.createElement('div') as HTMLDivElement;\n        sliderGamble.className = 'slidecontainer';\n        const title = document.createElement('span') as HTMLSpanElement;\n        title.className = 'sliderTitle';\n        title.innerText = 'Gamble Red Black:';\n        sliderGamble.appendChild(title);\n        this.gambleRedBlack = document.createElement('input') as HTMLInputElement;\n        this.gambleRedBlack.type = 'range';\n        this.gambleRedBlack.min = '1';\n        this.gambleRedBlack.max = '100';\n        this.gambleRedBlack.value = this.rootStore.customResultStore.gambleRedBlack.toString();\n        this.gambleRedBlack.className = 'slider';\n        sliderGamble.appendChild(this.gambleRedBlack);\n        this.optionsHolder.appendChild(sliderGamble);\n\n        const sliderGambleCollect = document.createElement('div') as HTMLDivElement;\n        sliderGambleCollect.className = 'slidecontainer';\n        const title2 = document.createElement('span') as HTMLSpanElement;\n        title2.className = 'sliderTitle';\n        title2.innerText = 'Gamble Collect:';\n        sliderGambleCollect.appendChild(title2);\n        this.gambleCollect = document.createElement('input') as HTMLInputElement;\n        this.gambleCollect.type = 'range';\n        this.gambleCollect.min = '1';\n        this.gambleCollect.max = '100';\n        this.gambleCollect.value = this.rootStore.customResultStore.gambleCollect.toString();\n        this.gambleCollect.className = 'slider';\n        sliderGambleCollect.appendChild(this.gambleCollect);\n        this.optionsHolder.appendChild(sliderGambleCollect);\n\n        const playGamble = document.createElement('div') as HTMLDivElement;\n        playGamble.className = 'slidecontainer';\n        const title3 = document.createElement('span') as HTMLSpanElement;\n        title3.className = 'sliderTitle';\n        title3.innerText = 'Play Gamble:';\n        playGamble.appendChild(title3);\n        this.playGamble = document.createElement('input') as HTMLInputElement;\n        this.playGamble.type = 'range';\n        this.playGamble.min = '1';\n        this.playGamble.max = '100';\n        this.playGamble.value = this.rootStore.customResultStore.playGamble.toString();\n        this.playGamble.className = 'slider';\n        playGamble.appendChild(this.playGamble);\n        this.optionsHolder.appendChild(playGamble);\n\n        const changeBet = document.createElement('div') as HTMLDivElement;\n        changeBet.className = 'slidecontainer';\n        const title4 = document.createElement('span') as HTMLSpanElement;\n        title4.className = 'sliderTitle';\n        title4.innerText = 'Change Bet:';\n        changeBet.appendChild(title4);\n        this.changeBet = document.createElement('input') as HTMLInputElement;\n        this.changeBet.type = 'range';\n        this.changeBet.min = '1';\n        this.changeBet.max = '100';\n        this.changeBet.value = this.rootStore.customResultStore.changeBet.toString();\n        this.changeBet.className = 'slider';\n        changeBet.appendChild(this.changeBet);\n        this.optionsHolder.appendChild(changeBet);\n\n        const fastStop = document.createElement('div') as HTMLDivElement;\n        fastStop.className = 'slidecontainer';\n        const title5 = document.createElement('span') as HTMLSpanElement;\n        title5.className = 'sliderTitle';\n        title5.innerText = 'Fast Stop:';\n        fastStop.appendChild(title5);\n        this.fastStop = document.createElement('input') as HTMLInputElement;\n        this.fastStop.type = 'range';\n        this.fastStop.min = '1';\n        this.fastStop.max = '100';\n        this.fastStop.value = this.rootStore.customResultStore.fastStop.toString();\n        this.fastStop.className = 'slider';\n        fastStop.appendChild(this.fastStop);\n        this.optionsHolder.appendChild(fastStop);\n\n        const betSpeed = document.createElement('div') as HTMLDivElement;\n        betSpeed.className = 'slidecontainer';\n        const title6 = document.createElement('span') as HTMLSpanElement;\n        title6.className = 'sliderTitle';\n        title6.innerText = 'Bet Speed:';\n        betSpeed.appendChild(title6);\n        this.betSpeed = document.createElement('input') as HTMLInputElement;\n        this.betSpeed.type = 'range';\n        this.betSpeed.min = '1';\n        this.betSpeed.max = '100';\n        this.betSpeed.value = this.rootStore.customResultStore.betSpeed.toString();\n        this.betSpeed.className = 'slider';\n        betSpeed.appendChild(this.betSpeed);\n        this.optionsHolder.appendChild(betSpeed);\n\n        /////////////////////// Infinity but/////////////////////\n\n        this.activateButHolder = document.createElement('div') as HTMLDivElement;\n        this.activateButHolder.className = 'switch_box box_1';\n        this.activateButton = document.createElement('input') as HTMLInputElement;\n\n        this.activateButton.setAttribute('type', 'checkbox');\n        this.activateButton.className = 'switch_1';\n        this.activateButHolder.appendChild(this.activateButton);\n        this.view.appendChild(this.activateButHolder);\n\n        /////////////////////// Infinity but/////////////////////\n    }\n    public destroy(): void {\n        if (this.activateButton) {\n            this.activateButton.onclick = null;\n            // @ts-ignore\n            this.activateButton = null;\n        }\n        if (this.activateButHolder) {\n            // @ts-ignore\n            this.activateButHolder = null;\n        }\n        if (this.gambleRedBlack) {\n            this.gambleRedBlack.onchange = null;\n            // @ts-ignore\n            this.gambleRedBlack = null;\n        }\n        if (this.gambleCollect) {\n            this.gambleCollect.onchange = null;\n            // @ts-ignore\n            this.gambleCollect = null;\n        }\n        if (this.playGamble) {\n            this.playGamble.onchange = null;\n            // @ts-ignore\n            this.playGamble = null;\n        }\n        if (this.changeBet) {\n            this.changeBet.onchange = null;\n            // @ts-ignore\n            this.changeBet = null;\n        }\n        if (this.fastStop) {\n            this.fastStop.onchange = null;\n            // @ts-ignore\n            this.fastStop = null;\n        }\n        if (this.betSpeed) {\n            this.betSpeed.onchange = null;\n            // @ts-ignore\n            this.betSpeed = null;\n        }\n\n        if (this.optionsHolder) {\n            // @ts-ignore\n            this.optionsHolder = null;\n        }\n        if (this.rootStore) {\n            // @ts-ignore\n            this.rootStore = null;\n        }\n        super.destroy();\n    }\n}\n","import Core from '@egt/core';\nimport { CustomResultContentView } from '@egt/custom-result';\nimport { Observable, Subject, merge } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { ISlotConfiguration } from '../../../slot-configuration/ISlotConfiguration';\nimport RootStore from '../../root/RootStore';\n\nexport default class CustomResultCustomContentView extends CustomResultContentView {\n    public selectImages: any[] = [];\n    public reelImages: any[] = [];\n    public symbolsHolder: HTMLDivElement;\n    public reelSymbolsHolder: HTMLDivElement;\n    public activateButton: HTMLInputElement;\n    public autoPlayFeatureButton: HTMLInputElement;\n    public customGambleButton: HTMLInputElement;\n    public activateRngButton: HTMLInputElement;\n    public rngInput: HTMLInputElement;\n    public resetButton: HTMLButtonElement;\n\n    public scaleSymbols = 0.6;\n    public scaleReels = 0.9;\n    public scaleFactor = 1.5;\n\n    public activateButHolder: HTMLDivElement;\n    public autoPlayFeatureHolder: HTMLDivElement;\n    public customGambleHolder: HTMLDivElement;\n    public activateRngHolder: HTMLDivElement;\n    public elementsAdded: boolean = false;\n    public upReel;\n    public downReel;\n\n    private localMergedDestroy: Observable<unknown>;\n    constructor(\n        public view: HTMLDivElement,\n        protected rootStore: RootStore,\n        protected slotConfiguration: ISlotConfiguration,\n        protected tabChanged: Subject<unknown>,\n    ) {\n        super(view);\n        this.initialRenderrer();\n        this.localMergedDestroy = merge(this.DESTROY, this.tabChanged);\n        Core.ORIENTATION.pipe(takeUntil(this.localMergedDestroy)).subscribe(this.setOrientation.bind(this));\n        Core.MEDIA_INFO_UPDATED.pipe(takeUntil(this.localMergedDestroy)).subscribe(this.resizeView.bind(this));\n    }\n\n    public destroy(): void {\n        if (this.symbolsHolder) {\n            this.symbolsHolder.remove();\n            this.symbolsHolder.innerHTML = '';\n            // @ts-ignore\n            this.symbolsHolder = null;\n        }\n        if (this.localMergedDestroy) {\n            // @ts-ignore\n            this.localMergedDestroy = null;\n        }\n        if (this.reelSymbolsHolder) {\n            this.reelSymbolsHolder.remove();\n            this.reelSymbolsHolder.innerHTML = '';\n            // @ts-ignore\n            this.reelSymbolsHolder = null;\n        }\n        if (this.activateButton) {\n            this.activateButton.remove();\n            this.activateButton.innerHTML = '';\n            // @ts-ignore\n            this.activateButton = null;\n        }\n\n        if (this.autoPlayFeatureButton) {\n            this.autoPlayFeatureButton.remove();\n            this.autoPlayFeatureButton.innerHTML = '';\n            // @ts-ignore\n            this.autoPlayFeatureButton = null;\n        }\n\n        if (this.view) {\n            this.view.remove();\n            this.view.innerHTML = '';\n            // @ts-ignore\n            this.view = null;\n        }\n\n        for (let reelImage of this.reelImages) {\n            reelImage.remove();\n            reelImage.innerHTML = '';\n            // @ts-ignore\n            reelImage = null;\n        }\n        this.reelImages = [];\n        for (let selectedImage of this.selectImages) {\n            selectedImage.remove();\n            selectedImage.innerHTML = '';\n            // @ts-ignore\n            selectedImage = null;\n        }\n        this.selectImages = [];\n\n        super.destroy();\n    }\n\n    public initialRenderrer(): void {\n        this.selectImages = [];\n        this.reelImages = [];\n\n        this.symbolsHolder = document.createElement('div') as HTMLDivElement;\n        this.symbolsHolder.className = 'symbolsHolder';\n\n        this.view.appendChild(this.symbolsHolder);\n\n        this.reelSymbolsHolder = document.createElement('div') as HTMLDivElement;\n        this.reelSymbolsHolder.className = 'reelSymbolsHolder';\n\n        this.view.appendChild(this.reelSymbolsHolder);\n\n        // this.topReelImages = [];\n        // this.valueReelImages = [];\n\n        let symbolNumber = 0;\n        let line = 0;\n        let index = 0;\n\n        const isDesktopVersion =\n            this.slotConfiguration.assets.filter((e) => e.id === 'symbols')[0]?.hasDesktopVersion === true &&\n            Core.isDesktopMode;\n\n        for (const symbol of this.slotConfiguration.symbolsConfig) {\n            if (!symbol.hiddenForCustom) {\n                const holderImageSprite = this.generateSymbolDiv(symbol, index, isDesktopVersion);\n                holderImageSprite.style.left =\n                    symbolNumber * this.rootStore.subjects.REELS_POSITION.value.symbolWidth + 'px';\n                holderImageSprite.style.top = line * this.rootStore.subjects.REELS_POSITION.value.symbolHeight + 'px';\n\n                symbolNumber++;\n                if (symbolNumber === 5) {\n                    line++;\n                    symbolNumber = 0;\n                }\n                index++;\n                this.symbolsHolder.appendChild(holderImageSprite);\n            }\n        }\n\n        this.activateButHolder = document.createElement('div') as HTMLDivElement;\n        this.activateButHolder.className = 'switch_box box_1';\n        this.activateButHolder.style.height = '70px';\n        this.activateButton = document.createElement('input') as HTMLInputElement;\n        this.activateButton.setAttribute('type', 'checkbox');\n        this.activateButton.className = 'switch_1';\n        const titActivate = document.createElement('span') as HTMLSpanElement;\n        titActivate.innerHTML = 'Custom';\n        titActivate.className = 'butTitle';\n        this.activateButHolder.appendChild(titActivate);\n        this.activateButHolder.appendChild(this.activateButton);\n\n        this.autoPlayFeatureHolder = document.createElement('div') as HTMLDivElement;\n        this.autoPlayFeatureHolder.className = 'switch_box box_1';\n        this.autoPlayFeatureHolder.style.height = '70px';\n        this.autoPlayFeatureButton = document.createElement('input') as HTMLInputElement;\n        this.autoPlayFeatureHolder.style.right = '110px';\n        this.autoPlayFeatureButton.setAttribute('type', 'checkbox');\n        this.autoPlayFeatureButton.className = 'switch_1';\n        const titAuto = document.createElement('span') as HTMLSpanElement;\n        titAuto.innerHTML = 'AutoFeatures';\n        titAuto.className = 'butTitle';\n        this.autoPlayFeatureHolder.appendChild(titAuto);\n        this.autoPlayFeatureHolder.appendChild(this.autoPlayFeatureButton);\n\n        this.customGambleHolder = document.createElement('div') as HTMLDivElement;\n        this.customGambleHolder.className = 'switch_box box_1';\n        this.customGambleHolder.style.height = '70px';\n        this.customGambleButton = document.createElement('input') as HTMLInputElement;\n        this.customGambleHolder.style.right = '200px';\n        this.customGambleButton.setAttribute('type', 'checkbox');\n        this.customGambleButton.className = 'switch_1';\n        const titgamble = document.createElement('span') as HTMLSpanElement;\n        titgamble.innerHTML = 'Gamble';\n        titgamble.className = 'butTitle';\n        this.customGambleHolder.appendChild(titgamble);\n        this.customGambleHolder.appendChild(this.customGambleButton);\n\n        this.activateRngHolder = document.createElement('div') as HTMLDivElement;\n        this.activateRngHolder.className = 'switch_box box_1';\n        this.activateRngHolder.style.height = '70px';\n        this.activateRngButton = document.createElement('input') as HTMLInputElement;\n\n        this.rngInput = document.createElement('input') as HTMLInputElement;\n        this.rngInput.className = 'rng_input';\n        this.rngInput.style.bottom = 'calc(10% + 4px)';\n        this.rngInput.setAttribute('id', 'rngInput');\n        this.rngInput.setAttribute('placeholder', 'Enter RNG Values');\n\n        this.activateRngButton.setAttribute('type', 'checkbox');\n        this.activateRngButton.className = 'switch_1';\n        const titleRNG = document.createElement('span') as HTMLSpanElement;\n        titleRNG.innerHTML = 'Apply RNG';\n        titleRNG.className = 'butTitle';\n\n        this.activateRngHolder.appendChild(titleRNG);\n        this.activateRngHolder.appendChild(this.activateRngButton);\n        this.activateRngHolder.appendChild(this.rngInput);\n\n        // Reset symbols button\n        this.resetButton = document.createElement('button') as HTMLButtonElement;\n        this.resetButton.innerHTML = 'Reset Reels';\n        this.resetButton.style.position = 'absolute';\n        this.resetButton.style.height = '20px';\n        this.resetButton.style.width = 'auto';\n        this.resetButton.style.bottom = 'calc(30% + 29px)';\n        this.resetButton.style.right = '2%';\n\n        this.view.appendChild(this.activateButHolder);\n        this.view.appendChild(this.activateRngHolder);\n        this.view.appendChild(this.autoPlayFeatureHolder);\n        this.view.appendChild(this.customGambleHolder);\n        this.view.appendChild(this.resetButton);\n        this.elementsAdded = true;\n        // this.resizeView()\n        this.setSelectedSymbol(0);\n    }\n\n    public setReels(arr): void {\n        this.reelSymbolsHolder.innerHTML = '';\n        this.reelImages = [];\n        const numberOfSymbols = arr.length / this.rootStore.subjects.NUMBER_OF_REELS.value;\n        for (let i = 0; i < arr.length; i++) {\n            const col = Math.floor(i / numberOfSymbols);\n            const row = i % numberOfSymbols;\n\n            const sprite = this.selectImages[this.getSymbolArrayIndex(arr[i])].cloneNode(true);\n            sprite.classList.remove('selected');\n            sprite.classList.remove('unselected');\n            sprite.removeAttribute('id');\n            sprite.style.left = col * this.rootStore.subjects.REELS_POSITION.value.symbolWidth + 'px';\n            sprite.style.top = row * this.rootStore.subjects.REELS_POSITION.value.symbolHeight + 'px';\n            sprite.children[0].id = 'symbol_' + i;\n            // sprite.alpha = row === 0 || row === this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value + 2 - 1 ? 0.4 : 1;\n            this.reelSymbolsHolder.appendChild(sprite);\n\n            this.reelImages.push(sprite);\n        }\n\n        // this.updateRound();\n        this.resizeView();\n    }\n\n    public addGuardBlockers(): void {\n        this.upReel = document.createElement('div') as HTMLDivElement;\n        this.upReel.className = 'reelCover';\n\n        this.reelSymbolsHolder.appendChild(this.upReel);\n\n        this.downReel = document.createElement('div') as HTMLDivElement;\n        this.downReel.className = 'reelCover';\n        this.downReel.style.top =\n            (this.rootStore.customResultStore.scenarioPageSymbols[0] - 1) *\n                this.rootStore.subjects.REELS_POSITION.value.symbolHeight +\n            'px';\n        // this.downReel.style.top =  (this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value + this.slotConfiguration.numberOfGuardSymbols/2) * this.rootStore.subjects.REELS_POSITION.value.symbolHeight + 'px'\n        this.reelSymbolsHolder.appendChild(this.downReel);\n\n        this.upReel.style.width = this.downReel.style.width =\n            this.rootStore.subjects.NUMBER_OF_REELS.value * this.rootStore.subjects.REELS_POSITION.value.symbolWidth +\n            'px';\n        this.upReel.style.height = this.downReel.style.height =\n            this.rootStore.subjects.REELS_POSITION.value.symbolHeight + 'px';\n    }\n\n    public setSelectedSymbol(selectedId): void {\n        for (const select of this.selectImages) {\n            // select.style.backgroundColor  = 'black';\n            // select.style.opacity  = '.5'\n            select.classList.remove('selected');\n            select.classList.add('unselected');\n        }\n        // this.selectImages[selectedId].style.backgroundColor  = 'red';\n        // this.selectImages[selectedId].style.opacity = '1'\n        this.selectImages[selectedId].classList.remove('unselected');\n        this.selectImages[selectedId].classList.add('selected');\n    }\n\n    public resizeView(_orientation = Core.ORIENTATION.value): void {\n        if (Core.ORIENTATION.value.isLandscape) {\n            if (this.rootStore.subjects.REELS_POSITION.value.symbolWidth > 300) {\n                this.scaleFactor = 1.9;\n            }\n            let scaleSymbols = document.body.clientWidth / 1360 / this.scaleFactor;\n\n            scaleSymbols = scaleSymbols > 0.75 ? 0.75 : scaleSymbols;\n            this.symbolsHolder.style.transform = 'scale(' + scaleSymbols * this.scaleSymbols + ')';\n\n            this.reelSymbolsHolder.style.transform = 'scale(' + scaleSymbols * this.scaleReels + ')';\n            const right = 6 * this.rootStore.subjects.REELS_POSITION.value.symbolWidth;\n            this.symbolsHolder.style.left = 'unset';\n            this.reelSymbolsHolder.style.top = '2.5%';\n            this.symbolsHolder.style.right = right * scaleSymbols * this.scaleSymbols + 'px';\n            this.reelSymbolsHolder.style.left =\n                this.rootStore.subjects.REELS_POSITION.value.symbolWidth * scaleSymbols * this.scaleSymbols + 'px';\n            this.activateButton.style.width = '80px';\n            this.activateButton.style.right = '0';\n            this.activateButHolder.style.width = '80px';\n            this.activateButHolder.style.top = 'unset';\n            this.activateRngHolder.style.bottom = 'calc(10% + 29px)';\n\n            this.activateRngButton.style.width = '80px';\n            this.activateRngButton.style.right = '0';\n            this.activateRngHolder.style.width = '80px';\n            this.activateRngHolder.style.top = 'unset';\n            this.customGambleHolder.style.right = '190px';\n            this.autoPlayFeatureHolder.style.right = '98px';\n\n            // this.rngInput.style.bottom ='11.5%';\n            // this.rngInput.style.right ='120%';\n        } else {\n            const height =\n                (this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value +\n                    this.rootStore.subjects.NUMBER_OF_GUARD_SYMBOLS.value) *\n                this.rootStore.subjects.REELS_POSITION.value.symbolHeight;\n            this.activateButton.style.width = '60px';\n            this.activateButHolder.style.top = '10%';\n            this.activateButHolder.style.width = '60px';\n            this.activateRngHolder.style.bottom = 'calc(10% + 20px)';\n            this.autoPlayFeatureHolder.style.right = '2.5%';\n            this.customGambleHolder.style.right = 'calc(90px + 2.5%)';\n            const scaleSymbols = (document.body.clientHeight / height / 2) * this.scaleSymbols;\n\n            this.symbolsHolder.style.right = 'unset';\n            this.symbolsHolder.style.left = this.reelSymbolsHolder.style.left = '2.5%';\n            const top =\n                (Math.ceil(this.slotConfiguration.symbols.length / 5) + 0.5) *\n                this.rootStore.subjects.REELS_POSITION.value.symbolHeight;\n            this.reelSymbolsHolder.style.top = top * scaleSymbols + 'px';\n            this.symbolsHolder.style.transform = 'scale(' + scaleSymbols + ')';\n            this.reelSymbolsHolder.style.transform = 'scale(' + scaleSymbols + ')';\n        }\n    }\n\n    public setOrientation(): void {\n        if (this.elementsAdded) {\n            this.resizeView();\n        }\n    }\n\n    public getRotationDegrees(x: number): string {\n        if (x === 1) {\n            return '90deg';\n        } else if (x === 2) {\n            return '270deg';\n        }\n        return '0';\n    }\n    private generateSymbolDiv(symbol: any, index, _desktop = false): HTMLDivElement {\n        const holderImageSprite = document.createElement('div') as HTMLDivElement;\n        holderImageSprite.className = 'symbol';\n\n        const imgSprite = document.createElement('div') as HTMLDivElement;\n        const scale =\n            this.rootStore.subjects.REELS_POSITION.value.symbolScale /\n            this.rootStore.subjects.REELS_POSITION.value.symbolResolution;\n        holderImageSprite.style.width = this.rootStore.subjects.REELS_POSITION.value.symbolWidth + 'px';\n        holderImageSprite.style.height = this.rootStore.subjects.REELS_POSITION.value.symbolHeight + 'px';\n        holderImageSprite.id = 'symbol_' + index;\n        imgSprite.id = 'symbol_' + index;\n        const spriteID = symbol.spriteID !== undefined ? symbol.spriteID : 'symbols';\n        const bckgrUrl = \"url('\" + Core.assets.getAsset(spriteID).children[0].url + \"')\";\n        let rotateDegrees = '0';\n        if (symbol.texture) {\n            imgSprite.style.backgroundImage = bckgrUrl;\n            const spriteFrame = Core.assets.getHTMLSpriteImage(spriteID, symbol.texture);\n            if (spriteFrame) {\n                rotateDegrees = this.getRotationDegrees(spriteFrame.rotate);\n                imgSprite.style.width = spriteFrame.frame.width + 'px';\n                imgSprite.style.height = spriteFrame.frame.height + 'px';\n                imgSprite.style.backgroundPositionX = '-' + spriteFrame.frame.x + 'px';\n                imgSprite.style.backgroundPositionY = '-' + spriteFrame.frame.y + 'px';\n\n                const top = (this.rootStore.subjects.REELS_POSITION.value.symbolHeight - spriteFrame.frame.height) / 2;\n                const left = (this.rootStore.subjects.REELS_POSITION.value.symbolWidth - spriteFrame.frame.width) / 2;\n                imgSprite.style.top = top + 'px';\n                imgSprite.style.left = left + 'px';\n                imgSprite.style.transform = 'scale(' + scale + ') rotate(' + rotateDegrees + ')';\n                imgSprite.style.position = 'absolute';\n            }\n        } else {\n            imgSprite.style.width = this.rootStore.subjects.REELS_POSITION.value.symbolWidth + 'px';\n            imgSprite.style.height = this.rootStore.subjects.REELS_POSITION.value.symbolHeight + 'px';\n        }\n\n        holderImageSprite.appendChild(imgSprite);\n\n        if (symbol.topTexture) {\n            const topSprite = document.createElement('div') as HTMLDivElement;\n            const topSpriteFrame = Core.assets.getHTMLSpriteImage(spriteID, symbol.topTexture);\n            if (topSpriteFrame) {\n                topSprite.style.backgroundImage = bckgrUrl;\n                topSprite.style.width = topSpriteFrame.frame.width + 'px';\n                topSprite.style.height = topSpriteFrame.frame.height + 'px';\n                topSprite.style.backgroundPositionX = '-' + topSpriteFrame.frame.x + 'px';\n                topSprite.style.backgroundPositionY = '-' + topSpriteFrame.frame.y + 'px';\n\n                topSprite.style.position = 'absolute';\n                topSprite.style.pointerEvents = 'none';\n\n                const top =\n                    (this.rootStore.subjects.REELS_POSITION.value.symbolHeight - topSpriteFrame.frame.height) / 2;\n                const left =\n                    (this.rootStore.subjects.REELS_POSITION.value.symbolWidth - topSpriteFrame.frame.width) / 2;\n                topSprite.style.top = top + 'px';\n                topSprite.style.left = left + 'px';\n                topSprite.style.transform =\n                    'scale(' + scale + ') rotate(' + this.getRotationDegrees(topSpriteFrame.rotate) + ')';\n                holderImageSprite.appendChild(topSprite);\n            }\n        }\n\n        if (symbol.value) {\n            const txt = (\n                symbol.value *\n                this.rootStore.settings.factor *\n                this.rootStore.uiStore.SELECTED_BET.value\n            ).toString();\n            const textValue = document.createElement('span') as HTMLSpanElement;\n            textValue.innerHTML = txt;\n            textValue.className = 'txt';\n            textValue.style.pointerEvents = 'none';\n            holderImageSprite.appendChild(textValue);\n        }\n\n        this.selectImages.push(holderImageSprite);\n        return holderImageSprite;\n    }\n\n    private getSymbolArrayIndex(symbolIndex: number): number {\n        let id: number = -1;\n        for (let i: number = 0; i < this.slotConfiguration.symbolsConfig.length; i++) {\n            if (this.slotConfiguration.symbolsConfig[i].index === symbolIndex) {\n                id = i;\n            }\n        }\n        return id;\n    }\n}\n","import Core from '@egt/core';\nimport { Subject } from 'rxjs';\nimport { ISlotConfiguration } from '../../../slot-configuration/ISlotConfiguration';\nimport RootStore from '../../root/RootStore';\n\nimport CustomResultCustomContentView from './CustomResultCustomContentView';\n\nexport default class CustomResultScenarioContentView extends CustomResultCustomContentView {\n    public butNew: HTMLDivElement;\n    public butLoad: HTMLDivElement;\n    public butMulitple: HTMLDivElement;\n    public butSave: HTMLButtonElement;\n    public butDelete: HTMLButtonElement;\n    public butPrev: HTMLButtonElement;\n    public butNext: HTMLButtonElement;\n    public butCopy: HTMLButtonElement;\n    public butDeleleStep: HTMLButtonElement;\n    public selectSymbols: HTMLSelectElement;\n    public selectScenario: HTMLSelectElement;\n    public activeContent: string = '';\n\n    private tabsHolder: HTMLDivElement;\n    private scenarioMultiHolder: HTMLDivElement;\n    private allSymbolsHolder: HTMLDivElement;\n    private actionsHolder: HTMLDivElement;\n    private menuHolder: HTMLDivElement;\n    private selectedSymbolsValues: string[] = ['Symbols', '1', '2', '3', '4', '5'];\n\n    constructor(\n        public view: HTMLDivElement,\n        protected rootStore: RootStore,\n        protected slotConfiguration: ISlotConfiguration,\n        protected tabChanged: Subject<unknown>,\n    ) {\n        super(view, rootStore, slotConfiguration, tabChanged);\n\n        this.scaleFactor = 2;\n    }\n    public initialRenderrer(): void {\n        this.setInitialScreen();\n        super.initialRenderrer();\n        this.allSymbolsHolder = document.createElement('div') as HTMLDivElement;\n        this.allSymbolsHolder.id = 'allSymbolsHolder';\n        this.allSymbolsHolder.appendChild(this.symbolsHolder);\n        this.allSymbolsHolder.appendChild(this.reelSymbolsHolder);\n        this.allSymbolsHolder.style.display = 'none';\n        this.activateButHolder.style.display = 'none';\n\n        this.view.appendChild(this.allSymbolsHolder);\n    }\n    public scenariosLoaded(data: any): void {\n        const scenarioActions = document.createElement('div') as HTMLDivElement;\n        scenarioActions.id = 'scenarioActions';\n        if (this.activeContent === 'Multi') {\n            scenarioActions.className = 'actionsMulti';\n            this.scenarioMultiHolder.appendChild(scenarioActions);\n        } else {\n            scenarioActions.className = 'actionsLoad';\n            this.view.appendChild(scenarioActions);\n        }\n\n        this.selectScenario = document.createElement('select');\n        this.selectScenario.id = 'selectScenario';\n        this.selectScenario.classList.add('selectSymbols');\n        scenarioActions.insertAdjacentElement('afterbegin', this.selectScenario);\n\n        this.selectScenario.style.left = '5%';\n        this.selectScenario.style.width = '90%';\n        const selectOptions = data;\n\n        const option2 = document.createElement('option');\n        option2.value = option2.text = 'Select from loaded';\n        this.selectScenario.appendChild(option2);\n        selectOptions.forEach((scenario) => {\n            const option = document.createElement('option');\n            option.value = scenario.id;\n            option.text = scenario.name;\n            this.selectScenario.appendChild(option);\n        });\n    }\n\n    public newScenario(): void {\n        const scenarioActions = document.getElementById('scenarioActions');\n        if (scenarioActions) {\n            scenarioActions.remove();\n        }\n        this.tabsHolder.style.display = 'none';\n        this.allSymbolsHolder.style.display = 'block';\n\n        this.setActions();\n        this.setMenu();\n\n        this.resizeView();\n        // this.updateRound();\n    }\n\n    public newMultiple(): void {\n        const scenarioActions = document.getElementById('scenarioActions');\n        if (scenarioActions) {\n            scenarioActions.remove();\n        }\n        this.tabsHolder.style.display = 'none';\n        this.scenarioMultiHolder = document.createElement('div');\n        this.scenarioMultiHolder.className = 'scenarioMultiHolder';\n        this.view.appendChild(this.scenarioMultiHolder);\n\n        this.setMenu();\n        this.butSave.style.visibility = 'hidden';\n        this.butDelete.style.visibility = 'hidden';\n    }\n\n    public addScenario(scenarioId: string, name: string): HTMLDivElement {\n        this.activateButHolder.style.display = 'flex';\n        const scenario = document.createElement('div');\n        scenario.id = 'multi_' + scenarioId;\n        scenario.className = 'scenarioAdd';\n        scenario.innerHTML =\n            '<span>' +\n            name +\n            '</span><svg class=\"svg-icon\" viewBox=\"0 0 27 27\"><path class=\"st0\" d=\"M21.125,0H4.875C2.182,0,0,2.182,0,4.875v16.25C0,23.818,2.182,26,4.875,26h16.25   C23.818,26,26,23.818,26,21.125V4.875C26,2.182,23.818,0,21.125,0z M18.78,17.394l-1.388,1.387c-0.254,0.255-0.67,0.255-0.924,0   L13,15.313L9.533,18.78c-0.255,0.255-0.67,0.255-0.925-0.002L7.22,17.394c-0.253-0.256-0.253-0.669,0-0.926l3.468-3.467   L7.221,9.534c-0.254-0.256-0.254-0.672,0-0.925l1.388-1.388c0.255-0.257,0.671-0.257,0.925,0L13,10.689l3.468-3.468   c0.255-0.257,0.671-0.257,0.924,0l1.388,1.386c0.254,0.255,0.254,0.671,0.001,0.927l-3.468,3.467l3.468,3.467   C19.033,16.725,19.033,17.138,18.78,17.394z\"/></svg>';\n        this.scenarioMultiHolder.appendChild(scenario);\n        return scenario;\n    }\n\n    public removeScenarioFromList(id): void {\n        const scenario = document.getElementById(id);\n        if (scenario) {\n            this.scenarioMultiHolder.removeChild(scenario);\n        }\n    }\n\n    public resizeView(orientation = Core.ORIENTATION.value): void {\n        super.resizeView(orientation);\n        this.activateButHolder.style.width = '60px';\n        this.activateButton.style.width = '60px';\n        this.activateButHolder.style.position = 'relative';\n        this.activateButton.style.right = 'unset';\n\n        this.activateButHolder.style.top = '0';\n        this.activateButHolder.style.bottom = 'unset';\n    }\n\n    public setMenu(): void {\n        this.menuHolder = document.createElement('div');\n        this.menuHolder.className = 'scenarioMenu';\n        this.view.appendChild(this.menuHolder);\n        this.activateButHolder.style.display = 'flex';\n        this.menuHolder.appendChild(this.activateButHolder);\n        this.butSave = document.createElement('button');\n        this.butSave.innerHTML =\n            '<svg class=\"svg-icon\" viewBox=\"0 0 20 20\"><path class=\"st0\" d=\"M17.064,4.656l-2.05-2.035C14.936,2.544,14.831,2.5,14.721,2.5H3.854c-0.229,0-0.417,0.188-0.417,0.417v14.167c0,0.229,0.188,0.417,0.417,0.417h12.917c0.229,0,0.416-0.188,0.416-0.417V4.952C17.188,4.84,17.144,4.733,17.064,4.656M6.354,3.333h7.917V10H6.354V3.333z M16.354,16.667H4.271V3.333h1.25v7.083c0,0.229,0.188,0.417,0.417,0.417h8.75c0.229,0,0.416-0.188,0.416-0.417V3.886l1.25,1.239V16.667z M13.402,4.688v3.958c0,0.229-0.186,0.417-0.417,0.417c-0.229,0-0.417-0.188-0.417-0.417V4.688c0-0.229,0.188-0.417,0.417-0.417C13.217,4.271,13.402,4.458,13.402,4.688\"></path></svg>';\n        this.butSave.classList.add('prevnextBut');\n        this.butSave.style.order = '4';\n        this.butSave.id = 'bSave';\n        this.butSave.onclick = () => {\n            this.rootStore.customResultStore.saveToServer();\n        };\n        this.menuHolder.appendChild(this.butSave);\n\n        this.butDelete = document.createElement('button');\n        this.butDelete.innerHTML =\n            '<svg class=\"svg-icon\" viewBox=\"0 0 20 20\"><path class=\"st0\" d=\"M17.114,3.923h-4.589V2.427c0-0.252-0.207-0.459-0.46-0.459H7.935c-0.252,0-0.459,0.207-0.459,0.459v1.496h-4.59c-0.252,0-0.459,0.205-0.459,0.459c0,0.252,0.207,0.459,0.459,0.459h1.51v12.732c0,0.252,0.207,0.459,0.459,0.459h10.29c0.254,0,0.459-0.207,0.459-0.459V4.841h1.511c0.252,0,0.459-0.207,0.459-0.459C17.573,4.127,17.366,3.923,17.114,3.923M8.394,2.886h3.214v0.918H8.394V2.886z M14.686,17.114H5.314V4.841h9.372V17.114z M12.525,7.306v7.344c0,0.252-0.207,0.459-0.46,0.459s-0.458-0.207-0.458-0.459V7.306c0-0.254,0.205-0.459,0.458-0.459S12.525,7.051,12.525,7.306M8.394,7.306v7.344c0,0.252-0.207,0.459-0.459,0.459s-0.459-0.207-0.459-0.459V7.306c0-0.254,0.207-0.459,0.459-0.459S8.394,7.051,8.394,7.306\"></path></svg>';\n        this.butDelete.classList.add('prevnextBut');\n        this.butDelete.style.order = '5';\n        this.butDelete.disabled = true;\n        this.butDelete.id = 'bDelete';\n        this.butDelete.onclick = () => {\n            this.rootStore.customResultStore.deleteScenario();\n        };\n        this.menuHolder.appendChild(this.butDelete);\n    }\n    public setActions(): void {\n        this.actionsHolder = document.createElement('div');\n        this.actionsHolder.className = 'scenarioActions';\n        this.view.appendChild(this.actionsHolder);\n\n        this.butPrev = document.createElement('button');\n        this.butPrev.innerHTML =\n            '<svg class=\"svg-icon\" viewBox=\"0 0 20 20\"><path class=\"st0\" fill=\"none\" d=\"M8.388,10.049l4.76-4.873c0.303-0.31,0.297-0.804-0.012-1.105c-0.309-0.304-0.803-0.293-1.105,0.012L6.726,9.516c-0.303,0.31-0.296,0.805,0.012,1.105l5.433,5.307c0.152,0.148,0.35,0.223,0.547,0.223c0.203,0,0.406-0.08,0.559-0.236c0.303-0.309,0.295-0.803-0.012-1.104L8.388,10.049z\"></path></svg>';\n        this.butPrev.classList.add('prevnextBut');\n        this.butPrev.style.order = '1';\n        this.butPrev.id = 'bPrev';\n\n        this.actionsHolder.appendChild(this.butPrev);\n\n        this.butNext = document.createElement('button');\n        this.butNext.innerHTML =\n            '<svg class=\"svg-icon\" viewBox=\"0 0 20 20\"><path class=\"st0\" fill=\"none\" d=\"M11.611,10.049l-4.76-4.873c-0.303-0.31-0.297-0.804,0.012-1.105c0.309-0.304,0.803-0.293,1.105,0.012l5.306,5.433c0.304,0.31,0.296,0.805-0.012,1.105L7.83,15.928c-0.152,0.148-0.35,0.223-0.547,0.223c-0.203,0-0.406-0.08-0.559-0.236c-0.303-0.309-0.295-0.803,0.012-1.104L11.611,10.049z\"></path></svg>';\n        this.butNext.classList.add('prevnextBut');\n        this.butNext.style.order = '6';\n\n        this.butNext.id = 'bNext';\n\n        this.actionsHolder.appendChild(this.butNext);\n\n        this.butCopy = document.createElement('button');\n        this.butCopy.innerHTML =\n            '<svg class=\"svg-icon\" viewBox=\"0 0 20 20\"><path class=\"st0\" d=\"M17.391,2.406H7.266c-0.232,0-0.422,0.19-0.422,0.422v3.797H3.047c-0.232,0-0.422,0.19-0.422,0.422v10.125c0,0.232,0.19,0.422,0.422,0.422h10.125c0.231,0,0.422-0.189,0.422-0.422v-3.797h3.797c0.232,0,0.422-0.19,0.422-0.422V2.828C17.812,2.596,17.623,2.406,17.391,2.406 M12.749,16.75h-9.28V7.469h3.375v5.484c0,0.231,0.19,0.422,0.422,0.422h5.483V16.75zM16.969,12.531H7.688V3.25h9.281V12.531z\"></path></svg>';\n        this.butCopy.classList.add('prevnextBut');\n        this.butCopy.style.order = '2';\n        this.butCopy.id = 'bCopy';\n        this.actionsHolder.appendChild(this.butCopy);\n\n        const roundText: HTMLSpanElement = document.createElement('div');\n        roundText.innerText = this.rootStore.customResultStore.scenarioIndexPage.toString();\n        roundText.className = 'scenarioActionsTxt';\n        roundText.style.order = '3';\n        roundText.id = 'roundText';\n        this.actionsHolder.appendChild(roundText);\n\n        this.butDeleleStep = document.createElement('button');\n        this.butDeleleStep.innerHTML =\n            '<svg class=\"svg-icon\" viewBox=\"0 0 20 20\"><path class=\"st0\" d=\"M17.114,3.923h-4.589V2.427c0-0.252-0.207-0.459-0.46-0.459H7.935c-0.252,0-0.459,0.207-0.459,0.459v1.496h-4.59c-0.252,0-0.459,0.205-0.459,0.459c0,0.252,0.207,0.459,0.459,0.459h1.51v12.732c0,0.252,0.207,0.459,0.459,0.459h10.29c0.254,0,0.459-0.207,0.459-0.459V4.841h1.511c0.252,0,0.459-0.207,0.459-0.459C17.573,4.127,17.366,3.923,17.114,3.923M8.394,2.886h3.214v0.918H8.394V2.886z M14.686,17.114H5.314V4.841h9.372V17.114z M12.525,7.306v7.344c0,0.252-0.207,0.459-0.46,0.459s-0.458-0.207-0.458-0.459V7.306c0-0.254,0.205-0.459,0.458-0.459S12.525,7.051,12.525,7.306M8.394,7.306v7.344c0,0.252-0.207,0.459-0.459,0.459s-0.459-0.207-0.459-0.459V7.306c0-0.254,0.207-0.459,0.459-0.459S8.394,7.051,8.394,7.306\"></path></svg>';\n        this.butDeleleStep.classList.add('prevnextBut');\n        this.butDeleleStep.style.order = '4';\n        this.butDeleleStep.id = 'bDeleteStep';\n\n        this.actionsHolder.appendChild(this.butDeleleStep);\n\n        this.selectSymbols = document.createElement('select');\n        this.selectSymbols.id = 'mySymSelect';\n        this.selectSymbols.style.order = '5';\n        this.actionsHolder.appendChild(this.selectSymbols);\n\n        this.selectSymbols.classList.add('selectSymbols');\n\n        for (const selectedOption of this.selectedSymbolsValues) {\n            const option = document.createElement('option');\n            option.value = selectedOption;\n            option.text = selectedOption;\n            this.selectSymbols.appendChild(option);\n        }\n    }\n\n    public updateRound(): void {\n        const txt = document.getElementById('roundText');\n        if (txt) {\n            txt.innerHTML =\n                this.rootStore.customResultStore.scenarioIndexPage +\n                1 +\n                '/' +\n                this.rootStore.customResultStore.scenarioAllPage;\n        }\n\n        if (this.selectSymbols !== null) {\n            this.selectSymbols.selectedIndex =\n                this.rootStore.customResultStore.scenarioPageSymbols[\n                    this.rootStore.customResultStore.scenarioIndexPage\n                ] - this.rootStore.subjects.NUMBER_OF_GUARD_SYMBOLS.value;\n        }\n        if (this.rootStore.customResultStore.scenarioID > -1) {\n            this.butDelete.disabled = false;\n        } else {\n            this.butDelete.disabled = true;\n        }\n        if (this.rootStore.customResultStore.scenarioIndexPage > 0) {\n            this.butPrev.disabled = false;\n        } else {\n            this.butPrev.disabled = true;\n        }\n        if (this.rootStore.customResultStore.scenarioAllPage > 1) {\n            this.butDeleleStep.disabled = false;\n        } else {\n            this.butDeleleStep.disabled = true;\n        }\n        if (this.downReel) {\n            this.downReel.style.top =\n                (this.rootStore.customResultStore.scenarioPageSymbols[\n                    this.rootStore.customResultStore.scenarioIndexPage\n                ] -\n                    1) *\n                    this.rootStore.subjects.REELS_POSITION.value.symbolHeight +\n                'px';\n        }\n    }\n\n    private setInitialScreen(): void {\n        this.tabsHolder = document.createElement('div') as HTMLDivElement;\n        this.tabsHolder.className = 'tabsScenario';\n        this.view.appendChild(this.tabsHolder);\n\n        this.butNew = document.createElement('div') as HTMLDivElement;\n        this.butNew.className = 'tabScenario';\n        this.butNew.innerText = 'New Scenario';\n        this.tabsHolder.appendChild(this.butNew);\n\n        this.butLoad = document.createElement('div') as HTMLDivElement;\n        this.butLoad.className = 'tabScenario';\n        this.butLoad.innerText = 'Load Scenario List';\n        this.tabsHolder.appendChild(this.butLoad);\n\n        this.butMulitple = document.createElement('div') as HTMLDivElement;\n        this.butMulitple.className = 'tabScenario';\n        this.butMulitple.innerText = 'Load Multiple Scenarios';\n        this.tabsHolder.appendChild(this.butMulitple);\n    }\n}\n","import { CustomResultContentView } from '@egt/custom-result';\n\nexport default class CustomResultSettingsContentView extends CustomResultContentView {\n    public mediaButton;\n    public disconnectButton;\n    public infinityButton;\n    public consoleButton;\n    public animSpeedButton;\n    public fpsMeterButton;\n    public downloadPaytableButton;\n\n    constructor(public view: HTMLDivElement) {\n        super(view);\n\n        this.mediaButton = this.generateToggleButton('Media Info', 'Displays debug panel showing media information');\n        this.fpsMeterButton = this.generateToggleButton(\n            'Show FPS Stats',\n            'Shows window with fps, draw calls and textures',\n        );\n        this.disconnectButton = this.generateToggleButton(\n            'Disconnect Button',\n            'Shows disconnect buttons used to simulate loosing connection',\n        );\n        this.consoleButton = this.generateToggleButton('Console Button', 'Display Console on and off');\n        this.animSpeedButton = this.generateToggleButton('Animation Speed Button', 'Shows animation speed button');\n        this.downloadPaytableButton = this.generateToggleButton(\n            'Enable Download Button',\n            'Displays button inside paytable and help for download',\n        );\n    }\n\n    private generateToggleButton(lablel: string, description: string): HTMLDivElement {\n        const mediaBut = document.createElement('div') as HTMLDivElement;\n        mediaBut.className = 'radioDivHolder';\n        const title = document.createElement('span') as HTMLDivElement;\n        title.innerText = lablel;\n        title.className = 'radioDivTitle';\n        mediaBut.appendChild(title);\n\n        const button = document.createElement('div') as HTMLDivElement;\n        button.className = 'switch_box box_1 box_rel';\n\n        const btnRef = document.createElement('input') as HTMLInputElement;\n\n        btnRef.setAttribute('type', 'checkbox');\n        btnRef.className = 'switch_1';\n        button.appendChild(btnRef);\n        mediaBut.appendChild(button);\n\n        const desc = document.createElement('span') as HTMLDivElement;\n        // desc.innerText = 'Displays debug panel showing media information';\n        desc.innerText = description;\n        desc.className = 'radioDivDesc';\n        mediaBut.appendChild(desc);\n        this.view.appendChild(mediaBut);\n        return btnRef;\n    }\n}\n","import { IBigWinFeatureConfiguration } from '@egt/big-win';\nimport Core, { ISoundAsset } from '@egt/core';\nimport { CustomResultContentView } from '@egt/custom-result';\nimport { Features } from '@egt/slot';\nimport { Howl } from 'howler';\nimport { ISlotConfiguration } from '../../../slot-configuration/ISlotConfiguration';\n\nexport default class CustomResultSoundContentView extends CustomResultContentView {\n    public soundsButton;\n    private tabContainer: HTMLDivElement;\n\n    constructor(\n        public view: HTMLDivElement,\n        protected slotConfiguration: ISlotConfiguration,\n    ) {\n        super(view);\n\n        // Create Main Tab Container\n        this.tabContainer = document.createElement('div') as HTMLDivElement;\n        this.tabContainer.style.display = 'flex';\n        this.tabContainer.style.flexWrap = 'wrap';\n        this.tabContainer.style.justifyContent = 'center';\n        this.tabContainer.style.gap = '50px';\n        this.tabContainer.style.padding = '20px';\n        this.tabContainer.className = 'tabContainer';\n\n        this.view.appendChild(this.tabContainer);\n\n        // Create Debug Sounds\n        this.createDebugSoundsToggle();\n\n        // Create Change Sound Container & elements\n        this.createChangeSoundContainer();\n\n        // Create Set Sound Volume Container & elements\n        this.createChangeSoundVolumeContainer();\n\n        // Create Change Bg & CreditAnimation Sound Config Container & Elements\n        this.createChangeBGSoundsConfigContainer();\n\n        // Create Change BG Sounds FadeIn/Out configuration Container & Elements\n        this.createChangeBGSoundsFadeContainer();\n\n        // Create Background Inactivity Container & elements\n        this.createBackgroundInactivityContainer();\n\n        // Create Change Win Lines Fadeout Config when enter in bigWin\n        this.createBigWinLinesSoundsFadeOutContainer();\n    }\n\n    public destroy(): void {\n        super.destroy();\n\n        // @ts-ignore\n        this.tabContainer = null;\n    }\n\n    // Create Change Sound Container & elements\n    private createChangeSoundContainer() {\n        // Create the container\n        const changeSoundContainer = document.createElement('div') as HTMLDivElement;\n        changeSoundContainer.className = 'changeSoundContainer';\n        changeSoundContainer.style.display = 'flex';\n        changeSoundContainer.style.flexDirection = 'column';\n\n        // Description\n        const desc = document.createElement('p') as HTMLDivElement;\n        desc.innerText = 'Upload custom sound instead current:';\n        desc.className = 'radioDivDesc';\n\n        // Create Select Sound\n        const selectSound: HTMLSelectElement = document.createElement('select');\n        selectSound.id = 'soundReplaceId';\n        selectSound.onchange = this.onSoundFileChanged.bind(this);\n\n        // Create Play Current Button\n        const playBtn: HTMLButtonElement = document.createElement('button');\n        playBtn.id = 'btnSoundPlay';\n        playBtn.innerText = 'Play Current';\n        playBtn.onclick = this.onSoundFilePlay.bind(this);\n\n        // Create Restore\n        const defaultBtn: HTMLButtonElement = document.createElement('button');\n        defaultBtn.id = 'btnSoundRestore';\n        defaultBtn.innerText = 'Restore';\n        defaultBtn.onclick = this.onSoundSetDefault.bind(this);\n\n        // Create Choose File Button\n        const inputFile: HTMLInputElement = document.createElement('input');\n        inputFile.setAttribute('type', 'file');\n        inputFile.setAttribute('accept', '.mp3, .mp4, .wav, .ogg, .wma, .aac, .m4a, .flac');\n        inputFile.style.backgroundColor = '#cccccc';\n        inputFile.style.display = 'block';\n        inputFile.id = 'btnSoundReplace';\n        inputFile.onchange = this.onSoundReplaceFileChosen.bind(this);\n\n        // Populate the sound selector\n        this.createSoundsList(changeSoundContainer, selectSound);\n\n        // Append the elements to their container\n        const elements = [desc, selectSound, playBtn, defaultBtn, inputFile];\n        changeSoundContainer.append(...elements);\n\n        // Append to main tab container\n        this.tabContainer.appendChild(changeSoundContainer);\n    }\n\n    // Create Change Sound Volume Container & elements\n    private createChangeSoundVolumeContainer() {\n        // Create the container\n        const changeSoundVolumeContainer = document.createElement('div') as HTMLDivElement;\n        changeSoundVolumeContainer.className = 'changeSoundVolumeContainer';\n        changeSoundVolumeContainer.style.display = 'flex';\n        changeSoundVolumeContainer.style.flexDirection = 'column';\n\n        // Description\n        const desc = document.createElement('p') as HTMLDivElement;\n        desc.innerText = 'Set Custom Volume:';\n        desc.className = 'radioDivDesc';\n\n        // Create Sound Selector\n        const selectVolumeSound: HTMLSelectElement = document.createElement('select');\n        selectVolumeSound.id = 'soundReplaceVolumeId';\n\n        // Create Set Volume Input\n        const setVolumeInput: HTMLInputElement = document.createElement('input');\n        setVolumeInput.type = 'number';\n        setVolumeInput.min = '1';\n        setVolumeInput.max = '100';\n        setVolumeInput.placeholder = 'Volume';\n        setVolumeInput.id = 'setVolume';\n\n        // Create Set Volume Button\n        const setVolumeBtn: HTMLButtonElement = document.createElement('button');\n        setVolumeBtn.id = 'btnSoundPlay';\n        setVolumeBtn.innerText = 'Set';\n        setVolumeBtn.onclick = this.onSoundSetVolume.bind(this, setVolumeInput, selectVolumeSound);\n\n        // Create Save volume config Button\n        const saveVolumeConfig: HTMLButtonElement = document.createElement('button');\n        saveVolumeConfig.id = 'btnSoundPlay';\n        saveVolumeConfig.innerText = 'Save volume config';\n        saveVolumeConfig.onclick = this.onSaveVolumeConfig.bind(this);\n\n        this.createSoundsList(changeSoundVolumeContainer, selectVolumeSound);\n        // Populate the sound selector\n        this.createSoundsList(changeSoundVolumeContainer, selectVolumeSound);\n\n        // Append the elements to their container\n        const elements = [desc, selectVolumeSound, setVolumeInput, setVolumeBtn, saveVolumeConfig];\n        changeSoundVolumeContainer.append(...elements);\n\n        // Append to main tab container\n        this.tabContainer.appendChild(changeSoundVolumeContainer);\n    }\n\n    // Create Change Sound Background & creditAnimation Fade in/Out configuration\n    private createChangeBGSoundsConfigContainer() {\n        const bgSoundsConfig = Core.sounds.getBGSoundConfiguration();\n        if (!bgSoundsConfig?.syncCreditSoundWithBgSound) {\n            return;\n        }\n\n        // Create the container\n        const changeBGSoundConfigContainer = document.createElement('div') as HTMLDivElement;\n        changeBGSoundConfigContainer.className = 'changeBGSoundConfigContainer';\n        changeBGSoundConfigContainer.style.display = 'flex';\n        changeBGSoundConfigContainer.style.flexDirection = 'column';\n        changeBGSoundConfigContainer.style.gap = '5px';\n\n        // Description\n        const desc = document.createElement('p') as HTMLDivElement;\n        desc.innerText = 'Set Custom Background Sound Configuration Fades & Duration:';\n        desc.className = 'radioDivDesc';\n\n        // Create BG Sound Container\n        const selectBgCrSoundContainer: HTMLDivElement = document.createElement('div');\n        selectBgCrSoundContainer.className = 'selectBgCrSoundContainer';\n        // Description\n        const selectBgCrSoundDesc: HTMLSpanElement = document.createElement('span');\n        selectBgCrSoundDesc.style.paddingRight = '10px';\n        selectBgCrSoundDesc.innerText = 'Select Background Sound:';\n        // Create BG Sound Select\n        const selectBgCrSound: HTMLSelectElement = document.createElement('select');\n        selectBgCrSound.id = 'selectBgCrSoundId';\n        selectBgCrSoundContainer.append(selectBgCrSoundDesc, selectBgCrSound);\n\n        // Create Line Sound Container\n        const selectLineSoundContainer: HTMLDivElement = document.createElement('div');\n        selectLineSoundContainer.className = 'selectLineSoundContainer';\n        // Description\n        const selectLineSoundDesc: HTMLSpanElement = document.createElement('span');\n        selectLineSoundDesc.style.paddingRight = '10px';\n        selectLineSoundDesc.innerText = 'Select Line Sound:';\n        // Create Line Sound Selector\n        const selectLineSound: HTMLSelectElement = document.createElement('select');\n        selectLineSound.id = 'selectLineSound';\n        selectLineSoundContainer.append(selectLineSoundDesc, selectLineSound);\n\n        // Create Fade In Time Container\n        const setFadeInTimeContainer: HTMLDivElement = document.createElement('div');\n        setFadeInTimeContainer.className = 'setFadeInTimeContainer';\n        // Description\n        const setFadeInTimeDesc: HTMLSpanElement = document.createElement('span');\n        setFadeInTimeDesc.style.paddingRight = '10px';\n        setFadeInTimeDesc.innerText = 'Set Fade In Duration:';\n        // Create FadeIn Time Input\n        const setFadeInTime: HTMLInputElement = document.createElement('input');\n        setFadeInTime.type = 'number';\n        setFadeInTime.min = '1';\n        setFadeInTime.max = '1000';\n        setFadeInTime.placeholder = 'fadeIn';\n        setFadeInTime.id = 'setFadeInTimeId';\n        setFadeInTimeContainer.append(setFadeInTimeDesc, setFadeInTime);\n\n        // Create Fade In Volume Container\n        const setFadeInVolumeContainer: HTMLDivElement = document.createElement('div');\n        setFadeInVolumeContainer.className = 'setFadeInVolumeContainer';\n        // Description\n        const setFadeInVolumeDesc: HTMLSpanElement = document.createElement('span');\n        setFadeInVolumeDesc.style.paddingRight = '10px';\n        setFadeInVolumeDesc.innerText = 'Set Fade In Volume:';\n        // Create FadeIn Volume Input\n        const setFadeInVolume: HTMLInputElement = document.createElement('input');\n        setFadeInVolume.type = 'number';\n        setFadeInVolume.min = '1';\n        setFadeInVolume.max = '100';\n        setFadeInVolume.placeholder = 'vol';\n        setFadeInVolume.id = 'setFadeInVolumeId';\n        setFadeInVolumeContainer.append(setFadeInVolumeDesc, setFadeInVolume);\n\n        // Create Fade Out Time Container\n        const setFadeOutTimeContainer: HTMLDivElement = document.createElement('div');\n        setFadeOutTimeContainer.className = 'setFadeOutTimeContainer';\n        // Description\n        const setFadeOutTimeDesc: HTMLSpanElement = document.createElement('span');\n        setFadeOutTimeDesc.style.paddingRight = '10px';\n        setFadeOutTimeDesc.innerText = 'Set Fade Out Duration:';\n        // Create FadeOut Time Input\n        const setFadeOutTime: HTMLInputElement = document.createElement('input');\n        setFadeOutTime.type = 'number';\n        setFadeOutTime.min = '1';\n        setFadeOutTime.max = '1000';\n        setFadeOutTime.placeholder = 'fadeOut';\n        setFadeOutTime.id = 'setFadeOutTimeId';\n        setFadeOutTimeContainer.append(setFadeOutTimeDesc, setFadeOutTime);\n\n        // Create Line Sound Container\n        const setFadeOutVolumeContainer: HTMLDivElement = document.createElement('div');\n        setFadeOutVolumeContainer.className = 'setFadeOutVolumeContainer';\n        // Description\n        const setFadeOutVolumeDesc: HTMLSpanElement = document.createElement('span');\n        setFadeOutVolumeDesc.style.paddingRight = '10px';\n        setFadeOutVolumeDesc.innerText = 'Set Fade Out Volume:';\n        // Create FadeOut Volume Input\n        const setFadeOutVolume: HTMLInputElement = document.createElement('input');\n        setFadeOutVolume.type = 'number';\n        setFadeOutVolume.min = '1';\n        setFadeOutVolume.max = '100';\n        setFadeOutVolume.placeholder = 'vol';\n        setFadeOutVolume.id = 'setFadeOutVolumeId';\n        setFadeOutVolumeContainer.append(setFadeOutVolumeDesc, setFadeOutVolume);\n\n        // Create creditAnimationSound Delay Duration Container\n        const creditAnimationSoundDelayDurationContainer: HTMLDivElement = document.createElement('div');\n        creditAnimationSoundDelayDurationContainer.className = 'creditAnimationSoundDelayDurationContainer';\n        // Description\n        const setCreditAnimationSoundDelayDurationDesc: HTMLSpanElement = document.createElement('span');\n        setCreditAnimationSoundDelayDurationDesc.style.paddingRight = '10px';\n        setCreditAnimationSoundDelayDurationDesc.innerText = 'Set creditAnimationSound Delay Duration:';\n        // Create FadeOut Time Input\n        const setCreditAnimationSoundDelayDuration: HTMLInputElement = document.createElement('input');\n        setCreditAnimationSoundDelayDuration.type = 'number';\n        setCreditAnimationSoundDelayDuration.min = '1';\n        setCreditAnimationSoundDelayDuration.max = '100000';\n        setCreditAnimationSoundDelayDuration.placeholder = 'Delay Duration';\n        setCreditAnimationSoundDelayDuration.id = 'setCreditAnimationSoundDelayDurationId';\n        creditAnimationSoundDelayDurationContainer.append(\n            setCreditAnimationSoundDelayDurationDesc,\n            setCreditAnimationSoundDelayDuration,\n        );\n\n        // Create Set Fade Button\n        const setFadeOutBtn: HTMLButtonElement = document.createElement('button');\n        setFadeOutBtn.id = 'fadeIn';\n        setFadeOutBtn.innerText = 'Set';\n        setFadeOutBtn.onclick = this.onSetFadeBackgroundSound.bind(\n            this,\n            setFadeInTime,\n            setFadeInVolume,\n            setFadeOutTime,\n            setFadeOutVolume,\n            selectBgCrSound,\n            selectLineSound,\n            setCreditAnimationSoundDelayDuration,\n        );\n\n        // Create Save BG Sounds Config Button\n        const saveBGSoundsConfig: HTMLButtonElement = document.createElement('button');\n        saveBGSoundsConfig.id = 'btnSaveBGConfig';\n        saveBGSoundsConfig.innerText = 'Save BG config';\n        saveBGSoundsConfig.onclick = this.onSaveBGConfig.bind(this);\n\n        // Create Choose BG Sounds Config Button\n        const inputConfigFile: HTMLInputElement = document.createElement('input');\n        inputConfigFile.setAttribute('type', 'file');\n        inputConfigFile.setAttribute('accept', '.txt');\n        inputConfigFile.style.backgroundColor = '#cccccc';\n        inputConfigFile.style.display = 'block';\n        inputConfigFile.id = 'btnSoundConfigReplace';\n\n        // Populate the sound selectors\n        this.createBGSoundsList(selectBgCrSoundContainer, selectBgCrSound);\n        this.createSymbolsSoundList(selectLineSoundContainer, selectLineSound);\n\n        // Append the elements to their container\n        const elements = [\n            desc,\n            selectBgCrSoundContainer,\n            selectLineSoundContainer,\n            setFadeOutTimeContainer,\n            setFadeOutVolumeContainer,\n            setFadeInTimeContainer,\n            setFadeInVolumeContainer,\n            creditAnimationSoundDelayDurationContainer,\n            setFadeOutBtn,\n            saveBGSoundsConfig,\n            inputConfigFile,\n        ];\n        changeBGSoundConfigContainer.append(...elements);\n\n        // Append to main tab container\n        this.tabContainer.appendChild(changeBGSoundConfigContainer);\n\n        // Attach Event Listeners\n        const handler = this.populateDefaults.bind(\n            this,\n            selectBgCrSound,\n            selectLineSound,\n            setFadeInTime,\n            setFadeInVolume,\n            setFadeOutTime,\n            setFadeOutVolume,\n            setCreditAnimationSoundDelayDuration,\n        );\n        selectBgCrSound.removeEventListener('change', handler);\n        selectBgCrSound.addEventListener('change', handler);\n        selectLineSound.removeEventListener('change', handler);\n        selectLineSound.addEventListener('change', handler);\n\n        // Populate\n        handler();\n\n        // Pass the handler, in order to dynamically update the currently shown value in the selector\n        inputConfigFile.onchange = this.onReplaceBGSoundsConfig.bind(this, handler);\n    }\n\n    // Create configuration for set of win\n    private createBigWinLinesSoundsFadeOutContainer(): void {\n        if (!Core.hasFeature(Features.BIG_WIN) || !Core.hasFeature(Features.LINES)) {\n            return;\n        }\n\n        const bigWinConfig = Core.gameDependencyContainer.resolve(\n            'BigWinFeatureConfiguration',\n        ) as IBigWinFeatureConfiguration;\n        // Create the container\n        const changeBigWinWinLinesConfigContainer = document.createElement('div') as HTMLDivElement;\n        changeBigWinWinLinesConfigContainer.className = 'changeBGSoundConfigContainer';\n        changeBigWinWinLinesConfigContainer.style.display = 'flex';\n        changeBigWinWinLinesConfigContainer.style.flexDirection = 'column';\n        changeBigWinWinLinesConfigContainer.style.gap = '5px';\n\n        let options = `<option value='All Lines' selected='selected'>All Lines</option>`;\n        this.slotConfiguration.symbolsConfig\n            .filter((s) => s.winSound)\n            .forEach((s) => {\n                options += `<option value='${s.winSound}'>${s.winSound}</option>`;\n            });\n\n        // Take only unique fullLineSounds and append them to the selector\n        this.slotConfiguration.symbolsConfig\n            .reduce((res, cur) => {\n                if (cur.fullLineSound && !res.includes(cur.fullLineSound)) {\n                    res.push(cur.fullLineSound);\n                }\n                return res;\n            }, [])\n            .forEach((s) => {\n                options += `<option value='${s}'>${s}</option>`;\n            });\n\n        const html = `\n                <p>Set FadeOut of Win Lines when BigWIn starts:</p>\n                <div style='display: flex;'>\n                    <div>Win Line<br>\n                        <select id='bigWinLineSoundName'>${options}</select>\n                    </div>\n                    <div>Duration<br>\n                        <input type='number' id='bigWinLineDuration' min='0' max='1000'>\n                    </div>\n                    <div>Volume<br>\n                        <input type='number' id='bigWinLineVolume' min='0' max='100'>\n                    </div>\n                </div>\n                <button id='bigWinLineSetBtn'>Set</button>\n                <button id='bigWinLineSaveBtn'>Save BigWin Sounds Config</button>\n                `;\n        changeBigWinWinLinesConfigContainer.insertAdjacentHTML('beforeend', html);\n        this.tabContainer.appendChild(changeBigWinWinLinesConfigContainer);\n\n        const bigWinLineSoundName = document.getElementById('bigWinLineSoundName') as HTMLSelectElement;\n        const bigWinLineDuration = document.getElementById('bigWinLineDuration') as HTMLInputElement;\n        const bigWinLineVolume = document.getElementById('bigWinLineVolume') as HTMLInputElement;\n        const bigWinLineSetBtn = document.getElementById('bigWinLineSetBtn') as HTMLInputElement;\n        const bigWinLineSaveBtn = document.getElementById('bigWinLineSaveBtn') as HTMLInputElement;\n\n        const lineChangeHandler = (el) => {\n            const lineSound = el.target.options[el.target.selectedIndex].value;\n            const winSoundsConfig = bigWinConfig.winLinesSounds;\n            const lineWinConfig = winSoundsConfig.fadeOut[lineSound] || winSoundsConfig.fadeOut.default;\n            bigWinLineDuration.value = '' + lineWinConfig.duration;\n            bigWinLineVolume.value = '' + lineWinConfig.volume;\n        };\n        bigWinLineSoundName.removeEventListener('change', lineChangeHandler);\n        bigWinLineSoundName.addEventListener('change', lineChangeHandler);\n\n        const setBtnClickHandler = (_el) => {\n            const lineSound = bigWinLineSoundName.options[bigWinLineSoundName.selectedIndex].value;\n            const winSoundsConfig = bigWinConfig.winLinesSounds;\n            if (!winSoundsConfig.fadeOut[lineSound]) {\n                winSoundsConfig.fadeOut[lineSound] = {\n                    duration: winSoundsConfig.fadeOut.default.duration,\n                    volume: winSoundsConfig.fadeOut.default.volume,\n                };\n            }\n            const lineWinConfig = winSoundsConfig.fadeOut[lineSound];\n            lineWinConfig.duration = Number(bigWinLineDuration.value);\n            lineWinConfig.volume = Number(bigWinLineVolume.value);\n        };\n        bigWinLineSetBtn.removeEventListener('click', setBtnClickHandler);\n        bigWinLineSetBtn.addEventListener('click', setBtnClickHandler);\n\n        const saveBtnClickHandler = (_el) => {\n            const configText: string = JSON.stringify(bigWinConfig.winLinesSounds.positionData.defaults);\n\n            const textToBLOB = new Blob([configText], { type: 'text/plain' });\n            const sFileName = Core.configuration.gameKey + 'BigWinConfig.txt';\n\n            const newLink = document.createElement('a');\n            newLink.download = sFileName;\n\n            if (window.webkitURL != null) {\n                newLink.href = window.webkitURL.createObjectURL(textToBLOB);\n            } else {\n                newLink.href = window.URL.createObjectURL(textToBLOB);\n                newLink.style.display = 'none';\n                document.body.appendChild(newLink);\n            }\n\n            newLink.click();\n            newLink.parentElement?.removeChild(newLink);\n        };\n        bigWinLineSaveBtn.removeEventListener('click', saveBtnClickHandler);\n        bigWinLineSaveBtn.addEventListener('click', saveBtnClickHandler);\n\n        // fromEvent(bigWinLineSoundName, 'change').pipe(takeUntil(sub)).subscribe(this.onSelectImageClick.bind(this));\n        lineChangeHandler({ target: bigWinLineSoundName });\n    }\n\n    // Crate Debug Sounds\n    private createDebugSoundsToggle() {\n        const changeDebugSoundContainer = document.createElement('div') as HTMLDivElement;\n        changeDebugSoundContainer.className = 'debugSoundToggleContainer';\n        changeDebugSoundContainer.style.display = 'flex';\n        changeDebugSoundContainer.style.flexDirection = 'column';\n\n        // Title\n        const title = document.createElement('p') as HTMLDivElement;\n        title.innerText = 'Debug Sounds';\n        title.className = 'radioDivTitle';\n\n        // Description\n        const desc = document.createElement('p') as HTMLDivElement;\n        desc.innerText = 'Logs in the console whenever sound is played with its name:';\n        desc.className = 'radioDivDesc';\n\n        // Create the Toggle button\n        const button = document.createElement('div') as HTMLDivElement;\n        button.className = 'switch_box box_1 box_rel';\n\n        const btnRef = document.createElement('input') as HTMLInputElement;\n        btnRef.setAttribute('type', 'checkbox');\n        btnRef.className = 'switch_1';\n        button.appendChild(btnRef);\n\n        // Cache the reference\n        this.soundsButton = btnRef;\n\n        // Append the elements to their container\n        const elements = [title, desc, button];\n        changeDebugSoundContainer.append(...elements);\n\n        // Append to main tab container\n        this.tabContainer.appendChild(changeDebugSoundContainer);\n    }\n\n    // Create Change BG Sounds Fade Container & elements\n    private createChangeBGSoundsFadeContainer() {\n        // Populate Default values\n        const config = Core.sounds.getBGSoundFadeConfiguration();\n        if (!config) {\n            return;\n        }\n\n        // Create the container\n        const changeBGSoundFadeContainer = document.createElement('div') as HTMLDivElement;\n        changeBGSoundFadeContainer.className = 'changeBGSoundFadeContainer';\n        changeBGSoundFadeContainer.style.display = 'flex';\n        changeBGSoundFadeContainer.style.flexDirection = 'column';\n\n        // Description\n        const desc = document.createElement('p') as HTMLDivElement;\n        desc.innerText = 'Set Custom BG Sounds Fade:';\n        desc.className = 'radioDivDesc';\n\n        // Create backgroundMusicFadeOutDuration Container\n        const backgroundMusicFadeOutDurationContainer: HTMLDivElement = document.createElement('div');\n        backgroundMusicFadeOutDurationContainer.className = 'backgroundMusicFadeOutDuration';\n        // Description\n        const setBackgroundMusicFadeOutDurationDesc: HTMLSpanElement = document.createElement('span');\n        setBackgroundMusicFadeOutDurationDesc.style.paddingRight = '10px';\n        setBackgroundMusicFadeOutDurationDesc.innerText = 'Set backgroundMusic FadeOut Duration:';\n        // Create FadeIn Time Input\n        const setBackgroundMusicFadeOuTime: HTMLInputElement = document.createElement('input');\n        setBackgroundMusicFadeOuTime.type = 'number';\n        setBackgroundMusicFadeOuTime.min = '1';\n        setBackgroundMusicFadeOuTime.max = '100000';\n        setBackgroundMusicFadeOuTime.placeholder = 'fadeOut';\n        setBackgroundMusicFadeOuTime.id = 'setBackgroundMusicFadeOutDurationId';\n        backgroundMusicFadeOutDurationContainer.append(\n            setBackgroundMusicFadeOutDurationDesc,\n            setBackgroundMusicFadeOuTime,\n        );\n\n        // Create backgroundNoPlayFadeInDuration Container\n        const backgroundNoPlayFadeInDurationContainer: HTMLDivElement = document.createElement('div');\n        backgroundNoPlayFadeInDurationContainer.className = 'backgroundNoPlayFadeInDuration';\n        // Description\n        const setBackgroundNoPlayFadeInDurationDesc: HTMLSpanElement = document.createElement('span');\n        setBackgroundNoPlayFadeInDurationDesc.style.paddingRight = '10px';\n        setBackgroundNoPlayFadeInDurationDesc.innerText = 'Set backgroundNoPlay FadeIn Duration:';\n        // Create FadeIn Time Input\n        const setBackgroundNoPlayFadeInTime: HTMLInputElement = document.createElement('input');\n        setBackgroundNoPlayFadeInTime.type = 'number';\n        setBackgroundNoPlayFadeInTime.min = '1';\n        setBackgroundNoPlayFadeInTime.max = '100000';\n        setBackgroundNoPlayFadeInTime.placeholder = 'fadeIn';\n        setBackgroundNoPlayFadeInTime.id = 'setBackgroundNoPlayFadeInDurationId';\n        backgroundNoPlayFadeInDurationContainer.append(\n            setBackgroundNoPlayFadeInDurationDesc,\n            setBackgroundNoPlayFadeInTime,\n        );\n\n        // Create Set Fade Button\n        const setFadeBtn: HTMLButtonElement = document.createElement('button');\n        setFadeBtn.id = 'setBGFade';\n        setFadeBtn.innerText = 'Set';\n        setFadeBtn.onclick = this.onBGSoundSetFade.bind(\n            this,\n            setBackgroundMusicFadeOuTime,\n            setBackgroundNoPlayFadeInTime,\n        );\n\n        // Append the elements to their container\n        const elements = [\n            desc,\n            backgroundMusicFadeOutDurationContainer,\n            backgroundNoPlayFadeInDurationContainer,\n            setFadeBtn,\n        ];\n        changeBGSoundFadeContainer.append(...elements);\n\n        // Append to main tab container\n        this.tabContainer.appendChild(changeBGSoundFadeContainer);\n\n        // Populate the values with the ones from the config\n        setBackgroundNoPlayFadeInTime.value = config.backgroundNoPlayFadeInDuration;\n        setBackgroundMusicFadeOuTime.value = config.backgroundMusicFadeOutDuration;\n    }\n\n    // Create Background Inactivity Container & elements\n    private createBackgroundInactivityContainer() {\n        // Populate Default values\n        const backgroundInactivityTime = Core.sounds.getBGInactivityTimeConfiguration();\n\n        if (backgroundInactivityTime === null || backgroundInactivityTime === undefined) {\n            return;\n        }\n\n        // Create the container\n        const container = document.createElement('div') as HTMLDivElement;\n        container.className = 'backgroundInactivityContainer';\n        container.style.display = 'flex';\n        container.style.flexDirection = 'column';\n\n        // Description\n        const desc = document.createElement('p') as HTMLDivElement;\n        desc.innerText = 'Set Custom Background Inactivity Duration:';\n        desc.className = 'radioDivDesc';\n\n        // Create timeInIdleBeforeNoPlayDurationContainer Container\n        const backgroundInactivityInputContainer: HTMLDivElement = document.createElement('div');\n        backgroundInactivityInputContainer.className = 'backgroundInactivityInputContainer';\n        // Description\n        const setDesc: HTMLSpanElement = document.createElement('span');\n        setDesc.style.paddingRight = '10px';\n        setDesc.innerText = 'Set Time in Idle before bg no play Duration ms:';\n        // Create Duration Input\n        const setDuration: HTMLInputElement = document.createElement('input');\n        setDuration.type = 'number';\n        setDuration.min = '1';\n        setDuration.max = '100000';\n        setDuration.placeholder = 'duration ms';\n        setDuration.id = 'setDuration';\n        backgroundInactivityInputContainer.append(setDesc, setDuration);\n\n        // Create Set Fade Button\n        const setDurationBtn: HTMLButtonElement = document.createElement('button');\n        setDurationBtn.id = 'setDurationBeforeNoPlay';\n        setDurationBtn.innerText = 'Set';\n        setDurationBtn.onclick = this.onBGInactivityDuration.bind(this, setDuration);\n\n        // Append the elements to their container\n        const elements = [desc, backgroundInactivityInputContainer, setDurationBtn];\n        container.append(...elements);\n\n        // Append to main tab container\n        this.tabContainer.appendChild(container);\n\n        // Populate the values with the ones from the config\n        setDuration.value = backgroundInactivityTime.toString();\n    }\n\n    // ---------------- Creation Methods ----------------\n    private createBGSoundsList(soundsHolder: HTMLDivElement, selector: HTMLSelectElement): void {\n        // Sounds to list if they are available\n        const labels = [\n            'backgroundMusic',\n            'creditAnimationSound',\n            'fsCreditAnimationSound',\n            'freeSpinsBackgroundSound',\n            'freespinsBackgroundMusic',\n        ];\n\n        const allGameSounds = Core.sounds.getAllSounds();\n        // Extract only the supported sounds by the game\n        const supportedSounds: string[] = [];\n        const existingSounds = allGameSounds.reduce((result, sound) => {\n            labels.forEach((l) => sound.sprite.hasOwnProperty(l) && result.push(l));\n            return result;\n        }, supportedSounds);\n\n        existingSounds.forEach((l) => {\n            const og = document.createElement('option') as HTMLOptionElement;\n            og.setAttribute('label', l);\n            og.setAttribute('value', l);\n            selector.appendChild(og);\n        });\n        soundsHolder.appendChild(selector);\n    }\n\n    private createSymbolsSoundList(soundsHolder: HTMLDivElement, selector: HTMLSelectElement): void {\n        // Iterate symbols and extract the names\n\n        if (Core.hasFeature(Features.LINES)) {\n            const allLines = document.createElement('option') as HTMLOptionElement;\n            allLines.setAttribute('label', 'All Lines');\n            allLines.setAttribute('value', 'All Lines');\n            selector.appendChild(allLines);\n\n            this.slotConfiguration.symbolsConfig\n                .filter((s) => s.winSound || s.expandSound)\n                .forEach((s) => {\n                    const og = document.createElement('option') as HTMLOptionElement;\n                    og.setAttribute('label', s.winSound || s.expandSound);\n                    og.setAttribute('value', s.winSound || s.expandSound);\n                    selector.appendChild(og);\n                });\n\n            // Take only unique fullLineSounds and append them to the selector\n            this.slotConfiguration.symbolsConfig\n                .reduce((res, cur) => {\n                    if (cur.fullLineSound && !res.includes(cur.fullLineSound)) {\n                        res.push(cur.fullLineSound);\n                    }\n                    return res;\n                }, [])\n                .forEach((s) => {\n                    const og = document.createElement('option') as HTMLOptionElement;\n                    og.setAttribute('label', s);\n                    og.setAttribute('value', s);\n                    selector.appendChild(og);\n                });\n        }\n\n        if (Core.hasFeature(Features.BIG_WIN)) {\n            const bigWin = document.createElement('option') as HTMLOptionElement;\n            bigWin.setAttribute('label', 'bigWin');\n            bigWin.setAttribute('value', 'bigWin');\n            selector.appendChild(bigWin);\n        }\n\n        soundsHolder.appendChild(selector);\n    }\n\n    private createSoundsList(soundsHolder: HTMLDivElement, selector: HTMLSelectElement): void {\n        Core.sounds.getAllSounds().forEach((soundsGroup: ISoundAsset) => {\n            const og = document.createElement('optgroup') as HTMLElement;\n            og.setAttribute('label', soundsGroup.id);\n            for (const [key] of Object.entries(soundsGroup.sprite)) {\n                // console.log(`${key}: ${value}`);\n                const o = document.createElement('option') as HTMLOptionElement;\n                o.value = key;\n                o.text = key;\n                og.appendChild(o);\n            }\n            selector.appendChild(og);\n        });\n        soundsHolder.appendChild(selector);\n    }\n\n    private populateDefaults(\n        selectBgCrSound,\n        selectLineSound,\n        setFadeInTime,\n        setFadeInVolume,\n        setFadeOutTime,\n        setFadeOutVolume,\n        setCreditAnimationSoundDelayDuration,\n    ): void {\n        const bgSoundsConfig = Core.sounds.getBGSoundConfiguration();\n\n        // Get the current bg and line sounds\n        const bgSound = selectBgCrSound.value;\n        const lineSound = selectLineSound.value;\n\n        // Get the creditAnimationSound Config so we can properly fadeIn the sound\n        const config = bgSoundsConfig[bgSound];\n        const soundConfig = config[lineSound] ? config[lineSound] : config.default;\n\n        // Populate the values with the ones from the config or the default ones\n        setFadeInTime.value = soundConfig.fadeIn.duration;\n        setFadeInVolume.value = soundConfig.fadeIn.volume;\n        setFadeOutTime.value = soundConfig.fadeOut.duration;\n        setFadeOutVolume.value = soundConfig.fadeOut.volume;\n\n        // Toggle creditAnimationSoundDelayDurationContainer visibility and value\n        // This input should be visible only if we are changing values of the credits sounds\n        // Sounds to list if they are available\n        const labels = ['creditAnimationSound', 'fsCreditAnimationSound'];\n        // creditAnimationSoundDelayDurationContainer\n        const creditAnimationSoundDelayDurationContainer = document.querySelector(\n            '.creditAnimationSoundDelayDurationContainer',\n        ) as HTMLSelectElement;\n\n        if (labels.includes(selectBgCrSound.value)) {\n            // Show the element if hidden\n            if (creditAnimationSoundDelayDurationContainer) {\n                creditAnimationSoundDelayDurationContainer.style.display = 'block';\n                const delay = soundConfig.delay || null;\n                setCreditAnimationSoundDelayDuration.value = delay;\n            }\n        } else {\n            // hide the element if shown\n            if (creditAnimationSoundDelayDurationContainer) {\n                creditAnimationSoundDelayDurationContainer.style.display = 'none';\n            }\n        }\n    }\n\n    // ---------------- Handlers Methods----------------\n    private onSoundReplaceFileChosen(event): void {\n        // Read the file from the input\n        if (event.target.files) {\n            Core.LOADING_ASSETS.next(true);\n            const file = event.target.files[0];\n            const reader = new FileReader();\n            reader.addEventListener('load', () => {\n                const data = reader.result;\n                // Create a Howler sound\n                const soundHowl = new Howl({\n                    src: data,\n                    format: file.name.split('.').pop().toLowerCase(), // always give file extension: this is optional but helps\n                });\n                const s = document.getElementById('soundReplaceId') as HTMLSelectElement;\n                Core.sounds.replaceSound(s.value, soundHowl);\n                Core.LOADING_ASSETS.next(false);\n            });\n            reader.readAsDataURL(file);\n        }\n    }\n\n    private onReplaceBGSoundsConfig(cb, event): void {\n        // Read the file from the input\n        if (event.target.files) {\n            Core.LOADING_ASSETS.next(true);\n            const file = event.target.files[0];\n            const reader = new FileReader();\n            reader.readAsText(file, 'UTF-8');\n            reader.addEventListener('load', () => {\n                const data = reader.result;\n                const config = JSON.parse(data as string);\n                for (const bgSound in config) {\n                    const bgSoundConfig = config[bgSound];\n                    Core.sounds.updateBGSoundConfiguration({ bgSound, bgSoundConfig });\n                }\n                Core.LOADING_ASSETS.next(false);\n                cb && cb();\n            });\n        }\n    }\n\n    private onSoundSetDefault(): void {\n        this.onSoundFileChanged(undefined);\n        const s = document.getElementById('soundReplaceId') as HTMLSelectElement;\n        Core.sounds.replaceSound(s.value, undefined);\n    }\n\n    private onSoundFilePlay(_event): void {\n        const s = document.getElementById('soundReplaceId') as HTMLSelectElement;\n        Core.sounds.stopAll();\n        Core.sounds.play(s.value);\n    }\n\n    private onSoundSetVolume(setVolume: HTMLInputElement, sound: HTMLInputElement): void {\n        Core.sounds.changeSoundVolume.set(sound.value, Number(setVolume.value) / 100);\n        Core.sounds.setVolume(sound.value, Number(setVolume.value) / 100);\n    }\n\n    private onSoundFileChanged(_event): void {\n        Core.sounds.stopAll();\n        const s = document.getElementById('btnSoundReplace') as HTMLInputElement;\n        s.value = '';\n    }\n\n    private onSaveVolumeConfig(): void {\n        let configText: string = '';\n        Core.sounds.changeSoundVolume.forEach((value, key) => {\n            configText += key + ': ' + Number(value * 100) + '\\n';\n        });\n\n        const textToBLOB = new Blob([configText], { type: 'text/plain' });\n        const sFileName = Core.configuration.gameKey + 'VolumeConfig.txt';\n\n        const newLink = document.createElement('a');\n        newLink.download = sFileName;\n\n        if (window.webkitURL != null) {\n            newLink.href = window.webkitURL.createObjectURL(textToBLOB);\n        } else {\n            newLink.href = window.URL.createObjectURL(textToBLOB);\n            newLink.style.display = 'none';\n            document.body.appendChild(newLink);\n        }\n\n        newLink.click();\n    }\n\n    private onSaveBGConfig(): void {\n        const bgSoundsConfig = Core.sounds.getBGSoundConfiguration();\n        const configText: string = JSON.stringify(bgSoundsConfig.positionData.defaults);\n\n        const textToBLOB = new Blob([configText], { type: 'text/plain' });\n        const sFileName = Core.configuration.gameKey + 'BackgroundConfig.txt';\n\n        const newLink = document.createElement('a');\n        newLink.download = sFileName;\n\n        if (window.webkitURL != null) {\n            newLink.href = window.webkitURL.createObjectURL(textToBLOB);\n        } else {\n            newLink.href = window.URL.createObjectURL(textToBLOB);\n            newLink.style.display = 'none';\n            document.body.appendChild(newLink);\n        }\n\n        newLink.click();\n    }\n\n    private onSetFadeBackgroundSound(\n        fadeInTimeEl: HTMLInputElement,\n        fadeInVolumeEl: HTMLInputElement,\n        fadeOutTimeEl: HTMLInputElement,\n        fadeOutVolumeEl: HTMLInputElement,\n        bgSoundSelectEl: HTMLSelectElement,\n        lineSelectEL: HTMLSelectElement,\n        setCreditAnimationSoundDelayDurationEl: HTMLSelectElement,\n    ): void {\n        const fadeInTime = fadeInTimeEl.value ? parseInt(fadeInTimeEl.value) : 0;\n        const fadeInVol = fadeInVolumeEl.value ? parseFloat(fadeInVolumeEl.value) : 0;\n\n        const fadeOutTime = fadeOutTimeEl.value ? parseInt(fadeOutTimeEl.value) : 0;\n        const fadeOutVol = fadeOutVolumeEl.value ? parseFloat(fadeOutVolumeEl.value) : 0;\n\n        const bgSound = bgSoundSelectEl.value;\n        const lineSound = lineSelectEL.value;\n\n        let soundConfig: any = {\n            fadeOut: {\n                duration: fadeOutTime,\n                volume: fadeOutVol,\n            },\n            fadeIn: {\n                duration: fadeInTime,\n                volume: fadeInVol,\n            },\n        };\n\n        const creditAnimationSoundDelayDuration = setCreditAnimationSoundDelayDurationEl.value\n            ? parseInt(setCreditAnimationSoundDelayDurationEl.value)\n            : 0;\n\n        if (creditAnimationSoundDelayDuration) {\n            soundConfig = {\n                ...soundConfig,\n                delay: creditAnimationSoundDelayDuration,\n            };\n        }\n\n        if (lineSound === 'All Lines') {\n            Core.sounds.updateBgAllLinesSoundConfiguration({ bgSound, soundConfig });\n        } else {\n            Core.sounds.updateBgSingleLineSoundConfiguration({ bgSound, lineSound, soundConfig });\n        }\n    }\n\n    private onBGSoundSetFade(\n        backgroundMusicFadeOuTime: HTMLInputElement,\n        backgroundNoPlayFadeInTime: HTMLInputElement,\n    ): void {\n        const backgroundMusicFadeOutDurationNew = backgroundMusicFadeOuTime.value\n            ? parseFloat(backgroundMusicFadeOuTime.value)\n            : 0;\n        const backgroundNoPlayFadeInDurationNew = backgroundNoPlayFadeInTime.value\n            ? parseInt(backgroundNoPlayFadeInTime.value)\n            : 0;\n\n        Core.sounds.updateBgSoundFadeDuration({ backgroundMusicFadeOutDurationNew, backgroundNoPlayFadeInDurationNew });\n    }\n\n    private onBGInactivityDuration(backgroundInactivity: HTMLInputElement): void {\n        const backgroundInactivityNew = backgroundInactivity.value ? parseInt(backgroundInactivity.value) : 0;\n\n        Core.sounds.updateBGInactivityTimeConfiguration(backgroundInactivityNew);\n    }\n}\n","import Core from '@egt/core';\nimport { CustomResultContentView } from '@egt/custom-result';\nimport { SpineParser, TextureAtlas } from 'pixi-spine';\nimport { BaseTexture, Loader, LoaderResource, Spritesheet, Texture } from 'pixi.js';\nimport { ISlotConfiguration } from '../../../slot-configuration/ISlotConfiguration';\n\n/**\n * CustomResultVideoContentView class handles the display and configuration of video content in the custom result view.\n */\nexport default class CustomResultVideoContentView extends CustomResultContentView {\n    private tabContainer: HTMLDivElement;\n    private objectsArray: any[];\n    private videoIdInAssets: string;\n    private replacesAssets: string[] = [];\n    private selectedVideo: any;\n    private selectedSpine: any;\n\n    /**\n     * Constructs the CustomResultVideoContentView instance.\n     * @param view - The HTML div element where the view will be rendered.\n     * @param slotConfiguration - The slot configuration object.\n     */\n    constructor(\n        public view: HTMLDivElement,\n        protected slotConfiguration: ISlotConfiguration,\n    ) {\n        super(view);\n\n        // Create Main Tab Container\n        this.tabContainer = document.createElement('div');\n        this.tabContainer.style.display = 'flex';\n        this.tabContainer.style.flexWrap = 'wrap';\n        this.tabContainer.style.justifyContent = 'center';\n        this.tabContainer.style.gap = '50px';\n        this.tabContainer.style.padding = '20px';\n        this.tabContainer.className = 'tabContainer';\n\n        this.view.appendChild(this.tabContainer);\n        const form = `\n            <form id=\"dynamicForm\">\n                <label for=\"objectSelect\">Select Symbol Animation:</label>\n                <select id=\"objectSelect\">\n                    <option value=\"\">Select Video From the list...</option>\n                </select>\n                <br> <br>\n                <label for=\"spineSelect\">Select Spine Animation:</label>\n                <select id=\"spineSelect\">\n                    <option value=\"\">Select Spine from the list...</option>\n                </select>\n                <br>\n                <div id=\"spineConfig\" style=\"display: none;\">\n                    <h3>Spine Animation Configuration</h3>\n                        <label for=\"spineName\">Name:</label>\n                        <input id=\"spineName\" name=\"spineName\"><br>\n                        <form id=\"spineUploadForm\">\n                            <label for=\"atlas\">Select .Atlas:</label>\n                            <input type=\"file\" id=\"atlas\" accept=\".atlas\" />\n                            <br>\n                            <label for=\"png\">Select .PNG:</label>\n                            <input type=\"file\" id=\"png\" accept=\"image/png\" />\n                            <br>\n                            <label for=\"json\">Select .JSON</label>\n                            <input type=\"file\" id=\"json\" accept=\".json\" />\n                            <br>\n                            <button type=\"button\" id=\"spineUploadButton\">Upload</button>\n                            <br>\n                            <div id=\"spineTextureDisplay\" style=\"display: none;\">\n                            <h3>Texture</h3>\n                            <img id=\"spineTextureImage\" src=\"\" alt=\"Texture Image\" style=\"width: 50%;\">\n                        </form>\n                        <br>\n                    </div>\n                </div>\n                <div id=\"videoConfig\" style=\"display: none;\">\n                <br>\n                    <h3>Video Configuration</h3>\n                    <label for=\"fps\">FPS:</label>\n                    <input type=\"number\" id=\"fps\" name=\"fps\"><br>\n                    <label for=\"width\">Width:</label>\n                    <input type=\"number\" id=\"width\" name=\"width\"><br>\n                    <label for=\"height\">Height:</label>\n                    <input type=\"number\" id=\"height\" name=\"height\"><br>\n                    <label for=\"loopIndex\">Loop Index:</label>\n                    <input type=\"number\" id=\"loopIndex\" name=\"loopIndex\"><br>\n                    <label for=\"length\">Number Of Frames:</label>\n                    <input type=\"number\" id=\"length\" name=\"length\"><br>\n                    <label for=\"loop\">Loop:</label>\n                    <input type=\"checkbox\" id=\"loop\" name=\"loop\"><br>\n                <br>\n                    <h3>Upload New Spritesheet</h3>\n                    <form id=\"uploadForm\">\n                        <input type=\"file\" id=\"imageFiles\" multiple accept=\"image/png\" />\n                        <button type=\"button\" id=\"uploadButton\">Upload</button>\n                    <br>\n                    <div id=\"textureDisplay\" style=\"display: none;\">\n                        <h3>Texture</h3>\n                    <img id=\"textureImage\" src=\"\" alt=\"Texture Image\" style=\"\n                    width: 50%;\n                \">\n                    </div>\n                </form>\n                \n                </div>\n            </form>`;\n        this.tabContainer.innerHTML = form;\n        this.populateSelectList();\n        this.bindEvents();\n    }\n\n    /**\n     * Destroys the CustomResultVideoContentView instance.\n     */\n    public destroy(): void {\n        super.destroy();\n        this.tabContainer = null!;\n    }\n\n    /**\n     * Populates the select list with video options from the objects array.\n     */\n    private populateSelectList(): void {\n        this.populateSymbolsVideosSelect();\n        this.populateSpineAnimationSelect();\n    }\n\n    private populateSymbolsVideosSelect() {\n        const select = document.getElementById('objectSelect') as HTMLSelectElement;\n        select.addEventListener('change', this.populateVideoConfig.bind(this));\n        document.getElementById('uploadButton')?.addEventListener('click', this.onClick.bind(this));\n\n        this.objectsArray = this.slotConfiguration.symbolsConfig;\n        this.objectsArray.forEach((obj) => {\n            const option = document.createElement('option');\n            option.value = obj.name;\n            option.text = obj.name;\n            select.appendChild(option);\n        });\n    }\n\n    private populateSpineAnimationSelect() {\n        //filter spine animations\n        // Define the filtering criteria\n        const selectSpine = document.getElementById('spineSelect') as HTMLSelectElement;\n        selectSpine.addEventListener('change', this.populateSpineAnimationConfig.bind(this));\n\n        const criteria = (_key, value) => value.hasOwnProperty('spineData');\n        const filteredSpineAnimationsKeys = this.filterKeys(Core.assets.loadedAssets, criteria);\n        filteredSpineAnimationsKeys.forEach((animation) => {\n            const option = document.createElement('option');\n            option.value = animation;\n            option.text = animation;\n            selectSpine.appendChild(option);\n        });\n    }\n\n    private filterKeys(map, callback) {\n        const keys: any[] = [];\n        for (const [key, value] of map) {\n            if (callback(key, value, map)) {\n                keys.push(key);\n            }\n        }\n        return keys;\n    }\n\n    /**\n     * Handles the click event for the upload button, loading and displaying the selected images as a spritesheet.\n     */\n    private async onClick(): Promise<void> {\n        const files = (document.getElementById('imageFiles') as HTMLInputElement).files;\n        if (!files || files.length === 0) {\n            alert('Please select images to upload.');\n            return;\n        }\n\n        const imageElements: HTMLImageElement[] = [];\n        // @ts-ignore\n        for (const file of files) {\n            const imageElement = await this.loadImage(URL.createObjectURL(file));\n            imageElements.push(imageElement);\n        }\n\n        const { spritesheet, data } = this.generateSpritesheet(imageElements, 2048);\n        const textureImage = document.getElementById('textureImage') as HTMLImageElement;\n        textureImage.src = spritesheet;\n\n        const loader = new Loader();\n        loader.add('spritesheet', spritesheet);\n        loader.load((_loader, resources) => {\n            const spritesheetResource = resources.spritesheet;\n            if (spritesheetResource) {\n                // @ts-ignore\n                const spritesheet = new Spritesheet(spritesheetResource.texture.baseTexture, data);\n                spritesheet.parse(() => {\n                    resources.spritesheet.data = data;\n                    resources.spritesheet.textures = spritesheet.textures;\n                    resources.spritesheet.spritesheet = spritesheet;\n                    // @ts-ignore\n                    resources.spritesheet.children.push(spritesheetResource.texture);\n                });\n            }\n\n            Core.assets.loadedAssets.set(this.videoIdInAssets, resources.spritesheet);\n            this.replacesAssets.push(this.videoIdInAssets);\n        });\n    }\n\n    /**\n     * Loads an image from a given source URL.\n     * @param src - The source URL of the image.\n     * @returns A promise that resolves to the loaded HTMLImageElement.\n     */\n    private loadImage(src: string): Promise<HTMLImageElement> {\n        return new Promise((resolve, reject) => {\n            const img = new Image();\n            img.onload = () => resolve(img);\n            img.onerror = reject;\n            img.src = src;\n        });\n    }\n\n    /**\n     * Generates a spritesheet from an array of images.\n     * @param images - The array of images.\n     * @param maxWidth - The maximum width of the spritesheet.\n     * @returns An object containing the spritesheet data URL and frame data.\n     */\n    private generateSpritesheet(images: HTMLImageElement[], maxWidth: number) {\n        const spriteWidth = images[0].width;\n        const spriteHeight = images[0].height;\n\n        const canvasWidth = maxWidth;\n        let canvasHeight = spriteHeight * Math.ceil((spriteWidth * images.length) / maxWidth);\n        if (canvasHeight === 0) canvasHeight = spriteHeight;\n\n        const canvas = document.createElement('canvas');\n        const ctx = canvas.getContext('2d');\n        if (!ctx) {\n            throw new Error('Could not get canvas context');\n        }\n        canvas.width = canvasWidth;\n        canvas.height = canvasHeight;\n\n        const data = {\n            frames: {} as any,\n            animations: {\n                ace: [] as string[],\n            },\n            meta: {\n                app: 'https://www.codeandweb.com/texturepacker',\n                version: '1.0',\n                image: 'ace.png',\n                format: 'RGBA8888',\n                size: { w: canvasWidth, h: canvasHeight },\n                scale: '1',\n                smartupdate:\n                    '$TexturePacker:SmartUpdate:03c827fc476f20fe567ea6d74a1f9dec:f98291c358b735f8bc8d06f2397634a4:4d450bc290808d8ce6e01926845f7aa4$',\n            },\n        };\n\n        let x = 0;\n        let y = 0;\n        images.forEach((img, index) => {\n            if (x + spriteWidth > maxWidth) {\n                x = 0;\n                y += spriteHeight;\n            }\n            ctx.drawImage(img, x, y);\n            const frameName = `ace_${String(index + 1).padStart(2, '0')}.png`;\n            data.frames[frameName] = {\n                frame: { x, y, w: spriteWidth, h: spriteHeight },\n                rotated: false,\n                trimmed: false,\n                spriteSourceSize: { x: 0, y: 0, w: spriteWidth, h: spriteHeight },\n                sourceSize: { w: spriteWidth, h: spriteHeight },\n            };\n            data.animations.ace.push(frameName);\n            x += spriteWidth;\n        });\n\n        const spritesheet = canvas.toDataURL('image/png');\n        return { spritesheet, data };\n    }\n\n    /**\n     * Populates the video configuration inputs with the selected object's video data.\n     */\n    private populateVideoConfig(): void {\n        const selectedName = (document.getElementById('objectSelect') as HTMLSelectElement).value;\n        if (!selectedName) {\n            (document.getElementById('videoConfig') as HTMLElement).style.display = 'none';\n            (document.getElementById('textureDisplay') as HTMLElement).style.display = 'none';\n            return;\n        }\n\n        this.selectedVideo = this.objectsArray.find((obj) => obj.name === selectedName);\n        if (this.selectedVideo) {\n            (document.getElementById('fps') as HTMLInputElement).value = this.selectedVideo.video.fps;\n            (document.getElementById('width') as HTMLInputElement).value = this.selectedVideo.video.width;\n            (document.getElementById('height') as HTMLInputElement).value = this.selectedVideo.video.height;\n            (document.getElementById('loopIndex') as HTMLInputElement).value = this.selectedVideo.video.loopIndex;\n            (document.getElementById('length') as HTMLInputElement).value = this.selectedVideo.video.length ?? 0;\n            (document.getElementById('loop') as HTMLInputElement).checked = this.selectedVideo.video.loop;\n\n            (document.getElementById('videoConfig') as HTMLElement).style.display = 'block';\n            this.videoIdInAssets = this.selectedVideo.video?.id;\n            if (this.videoIdInAssets) {\n                let base64Image;\n                if (this.replacesAssets.includes(this.videoIdInAssets)) {\n                    base64Image = Core.assets.getAsset(this.videoIdInAssets).url;\n                } else {\n                    base64Image = Core.assets.getAsset(this.videoIdInAssets).children[0].texture.baseTexture.resource\n                        .source.currentSrc;\n                }\n                const textureImage = document.getElementById('textureImage') as HTMLImageElement;\n                textureImage.src = base64Image;\n                (document.getElementById('textureDisplay') as HTMLElement).style.display = 'block';\n            } else {\n                (document.getElementById('textureDisplay') as HTMLElement).style.display = 'none';\n            }\n        }\n    }\n\n    /**\n     * Populates the spine configuration inputs with the selected object's spine data.\n     */\n    private populateSpineAnimationConfig(): void {\n        (document.getElementById('spineConfig') as HTMLElement).style.display = 'block';\n        const selectedSpineAnimation = (document.getElementById('spineSelect') as HTMLSelectElement).value;\n        if (!selectedSpineAnimation) {\n            (document.getElementById('spineConfig') as HTMLElement).style.display = 'none';\n            (document.getElementById('spineTextureDisplay') as HTMLElement).style.display = 'none';\n            return;\n        }\n\n        (document.getElementById('spineName') as HTMLInputElement).value = selectedSpineAnimation;\n        const spineResource = Core.assets.getAsset(selectedSpineAnimation);\n        const res = spineResource.children.find((el) => el.extension === 'png');\n        const textureImage = document.getElementById('spineTextureImage') as HTMLImageElement;\n        textureImage.src = res.texture.baseTexture.resource.source.currentSrc;\n        (document.getElementById('spineTextureDisplay') as HTMLElement).style.display = 'block';\n    }\n\n    /**\n     * Handles the click event for the spine upload button, validating and loading the selected files.\n     */\n    private async onSpineUploadClick(): Promise<void> {\n        const atlasFile = (document.getElementById('atlas') as HTMLInputElement).files?.[0];\n        const pngFile = (document.getElementById('png') as HTMLInputElement).files?.[0];\n        const jsonFile = (document.getElementById('json') as HTMLInputElement).files?.[0];\n\n        if (!atlasFile || !pngFile || !jsonFile) {\n            alert('Please select all required files (.atlas, .png, .json) to upload.');\n            return;\n        }\n\n        const atlasContent = await this.readFileContent(atlasFile);\n        const jsonContent = await this.readFileContent(jsonFile);\n        const imageElement = await this.loadImage(URL.createObjectURL(pngFile));\n        const spineData = await this.createSpineData(atlasContent, jsonContent, imageElement);\n        const spineName = (document.getElementById('spineName') as HTMLInputElement).value;\n\n        Core.assets.loadedAssets.set(spineName, spineData);\n\n        const textureImage = document.getElementById('spineTextureImage') as HTMLImageElement;\n        textureImage.src = imageElement.src;\n        (document.getElementById('spineTextureDisplay') as HTMLElement).style.display = 'block';\n\n        alert('Spine animation uploaded successfully!');\n    }\n\n    /**\n     * Creates a new SpineData object from the uploaded files.\n     * @param atlasContent - The content of the .atlas file.\n     * @param jsonContent - The content of the .json file.\n     * @param imageElement - The loaded image element for the .png file.\n     * @returns A promise that resolves to the new SpineData object.\n     */\n    private async createSpineData(\n        atlasContent: string,\n        jsonContent: string,\n        imageElement: HTMLImageElement,\n    ): Promise<LoaderResource> {\n        // Create a canvas and draw the image to get a texture\n        const canvas = document.createElement('canvas');\n        canvas.width = imageElement.width;\n        canvas.height = imageElement.height;\n        const ctx = canvas.getContext('2d');\n        if (!ctx) throw new Error('Could not get canvas context');\n        ctx.drawImage(imageElement, 0, 0);\n\n        const baseTexture = new BaseTexture(canvas);\n        const texture = new Texture(baseTexture);\n\n        // Create a texture atlas from the .atlas content\n        const atlas = new TextureAtlas(atlasContent, (_line, callback) => {\n            // @ts-ignore\n            callback(texture);\n        });\n        // Create a Spine parser instance\n        const spineParser = new SpineParser().createJsonParser();\n        // Parse the skeleton data from the .json content\n        // @ts-ignore\n        const spineData = spineParser.readSkeletonData(atlas, JSON.parse(jsonContent));\n\n        // Create a new LoaderResource object\n        // @ts-ignore\n        const resource = new LoaderResource('spine', 'spine', { spineData, spineAtlas: atlas });\n        resource.spineData = spineData;\n        resource.spineAtlas = atlas;\n        resource.data = JSON.parse(jsonContent);\n\n        return resource;\n    }\n\n    /**\n     * Reads the content of a file as a text.\n     * @param file - The file to read.\n     * @returns A promise that resolves to the file content as a string.\n     */\n    private readFileContent(file: File): Promise<string> {\n        return new Promise((resolve, reject) => {\n            const reader = new FileReader();\n            reader.onload = () => resolve(reader.result as string);\n            reader.onerror = reject;\n            reader.readAsText(file);\n        });\n    }\n\n    /**\n     * Binds event listeners to the form inputs to update the video configuration.\n     */\n    private bindEvents() {\n        const fpsInput = document.getElementById('fps') as HTMLInputElement;\n        fpsInput.addEventListener('input', this.updateVideoConfig);\n\n        const widthInput = document.getElementById('width') as HTMLInputElement;\n        widthInput.addEventListener('input', this.updateVideoConfig);\n\n        const heightInput = document.getElementById('height') as HTMLInputElement;\n        heightInput.addEventListener('input', this.updateVideoConfig);\n\n        const loopIndexInput = document.getElementById('loopIndex') as HTMLInputElement;\n        loopIndexInput.addEventListener('input', this.updateVideoConfig);\n\n        const lengthInput = document.getElementById('length') as HTMLInputElement;\n        lengthInput.addEventListener('input', this.updateVideoConfig);\n\n        const loopCheckbox = document.getElementById('loop') as HTMLInputElement;\n        loopCheckbox.addEventListener('change', this.updateVideoConfig);\n\n        const spineUploadButton = document.getElementById('spineUploadButton') as HTMLButtonElement;\n        spineUploadButton.addEventListener('click', this.onSpineUploadClick.bind(this));\n    }\n\n    /**\n     * Updates the selected object's video configuration based on the input changes.\n     * @param event - The input event.\n     */\n    private updateVideoConfig = (event: Event) => {\n        if (!this.selectedVideo) return;\n\n        const target = event.target as HTMLInputElement;\n\n        switch (target.id) {\n            case 'fps':\n                this.selectedVideo.video.fps = parseInt(target.value, 10);\n                break;\n            case 'width':\n                this.selectedVideo.video.width = parseInt(target.value, 10);\n                break;\n            case 'height':\n                this.selectedVideo.video.height = parseInt(target.value, 10);\n                break;\n            case 'loopIndex':\n                this.selectedVideo.video.loopIndex = parseInt(target.value, 10);\n                break;\n            case 'length':\n                this.selectedVideo.video.length = parseInt(target.value, 10);\n                break;\n            case 'loop':\n                this.selectedVideo.video.loop = target.checked;\n                break;\n        }\n    };\n}\n","import RestoreResponse from './RestoreResponse';\n\nexport default class BaseResponse {\n    protected _restore: boolean;\n    protected _restoreResponse: RestoreResponse;\n    protected _restoreResponses: any;\n    protected _restorePoint: string;\n    protected _restorePoints: string[];\n\n    constructor(response: any) {\n        if (response.game.restore) {\n            this._restorePoints = response.game.result.restorePoints;\n            this._restorePoint = response.game.result.restorePoints[0];\n            this._restoreResponse = new RestoreResponse(response.game.restore[response.game.result.restorePoints[0]]);\n            this._restoreResponses = response.game.restore;\n            this._restore = true;\n        }\n    }\n\n    get restore(): boolean {\n        return this._restore;\n    }\n\n    get restoreResponse(): RestoreResponse {\n        return this._restoreResponse;\n    }\n\n    set restoreResponse(value: RestoreResponse) {\n        this._restoreResponse = value;\n    }\n\n    get restoreResponses(): any {\n        return this._restoreResponses;\n    }\n\n    set restoreResponses(value: any) {\n        this._restoreResponses = value;\n    }\n\n    get restorePoint(): string {\n        return this._restorePoint;\n    }\n\n    get restorePoints(): string[] {\n        return this._restorePoints;\n    }\n}\n","import Core, { IRequest } from '@egt/core';\nimport InitialSettings from './InitialSettings';\n\nexport default class BetRequest implements IRequest {\n    constructor(\n        private amount: number,\n        private denomination: number,\n        private lines: number,\n        private customRequest: null | number[][],\n        private demoRequest: null | string,\n        private gameSettings: InitialSettings,\n        private isDRGPick: boolean | undefined,\n        private isDRGRespin: boolean | undefined,\n        private multislam: number | undefined,\n        private pearlyBeachFeatures:\n            | {\n                  activator?: boolean;\n                  wildReplace?: boolean;\n                  potSymbol?: boolean;\n                  coolerSymbol?: boolean;\n                  maxWin?: boolean;\n              }\n            | undefined,\n        private isBLBoostJackpotTrigger: boolean | undefined,\n        private numberOfReels: number,\n        private autoPlay: boolean = false,\n        private rngValues: null | number[],\n        private leprechaunWheelFeatures: boolean[] = [false, false],\n        // customDemo is added to context.demo object\n        // it is of type (no sub-objects for now)\n        // {\n        //    demo.raFeature: true\n        // }\n        // all properties will be iterated and set to the custom object\n        private customDemo?: object,\n    ) {}\n\n    public serialize(): any {\n        let context: object = {};\n        if (this.customRequest !== null && Core.configuration.devTools) {\n            context = Core.devTools!.getSlotCustomResultContext(this.customRequest, this.numberOfReels);\n            /*  context = {\n            'gamble.skip': true,\n            'demo.request': true,\n            'demo.custom': true,\n            'demo.custom.reels': [\n                [0, 2, 2, 2, 0],\n \n                [0, 11, 0, 0, 0],\n \n                [1, 0, 3],\n \n                [1, 0, 11, 4, 1],\n \n                [1, 0, 11, 1, 1],\n \n                [1, 0, 11, 1],\n \n                [1, 0, 1, 1],\n            ],\n            'demo.custom.positions': [0, 0, 0, 0, 0, 0, 0],\n        }; */\n\n            if (this.isDRGPick) {\n                context['demo.custom.pick'] = true;\n            }\n            if (this.isDRGRespin) {\n                context['demo.custom.respin'] = true;\n            }\n            if (this.isBLBoostJackpotTrigger) {\n                context['demo.custom.boost.jackpot'] = true;\n            }\n        }\n        if (this.demoRequest !== null && this.demoRequest !== '' && this.demoRequest !== undefined) {\n            context = {\n                'demo.request': true,\n                'demo.custom': true,\n                'demo.custom.feature': this.demoRequest,\n            };\n        }\n        if (this.multislam && this.multislam > 0) {\n            context['demo.custom.multislam'] = this.multislam;\n        }\n        // Send this flag only if autoPlay is true, otherwise do not send anything\n        if (this.autoPlay) {\n            const autoPlay = 'autoPlay';\n            context[autoPlay] = this.autoPlay;\n        }\n\n        this.leprechaunWheelFeatures.forEach((feature, index) => {\n            if (feature) {\n                switch (index) {\n                    case 0:\n                        const leprechaunWheelFeatureMultiplier = 'demo.holdSpin.multiplier';\n                        context[leprechaunWheelFeatureMultiplier] = feature;\n                        break;\n                    case 1:\n                        const leprechaunWheelFeatureCoinPile = 'demo.main.spin.explode';\n                        context[leprechaunWheelFeatureCoinPile] = feature;\n                        break;\n                    case 2:\n                        const leprechaunWheelFeaturePosition = 'demo.custom.upgradePos';\n                        context[leprechaunWheelFeaturePosition] = feature;\n                        break;\n                }\n            }\n        });\n\n        if (this.rngValues !== null) {\n            const rng = 'rng';\n            context[rng] = this.rngValues;\n        }\n\n        if (this.customDemo) {\n            Object.assign(context, this.customDemo);\n        }\n\n        Object.entries({\n            activator: 'demo.custom.ensure.rainbow.symbol',\n            wildReplace: 'demo.custom.append.wild.neighbors',\n            potSymbol: 'demo.custom.ensure.pot.symbol',\n            coolerSymbol: 'demo.custom.ensure.clover.symbol',\n            characterMarks: 'demo.custom.ensure.rainbow.marks',\n            maxWin: 'demo.custom.ensure.coin.max.win',\n        }).forEach(([feature, contextKey]) => {\n            if (this.pearlyBeachFeatures?.[feature]) {\n                context[contextKey] = true;\n            }\n        });\n\n        return {\n            event: 'bet',\n            bet: {\n                level: this.amount,\n                denomination: this.denomination,\n                lines: this.lines,\n                // This will be different for games that have bigger bet over lines:\n                // Example: 40 burning hot -> has bet 50 over 40 lines\n                // {\n                // \tlevel: 1,\n                // \tdenomonination: 1,\n                // \tlines: 40,\n                // \tfactor: 50\n                // }\n                factor: this.gameSettings.factor,\n                gameMode: this.gameSettings.gameMode,\n            },\n            context,\n        };\n    }\n}\n","import Line from '../lines/Line';\nimport LineMode from '../lines/LineMode';\nimport BaseResponse from './BaseResponse';\nimport JackpotWin from './JackpotWin';\n\nexport default class BetResponse extends BaseResponse {\n    private _result: any;\n    private _gameState: any;\n    private _balance: number;\n    private _denomination: number;\n    private _currency: string;\n    private _overflow: boolean = false;\n    private _state: string;\n    private _entries: Line[];\n    private _scatterWin: number;\n    private _reels: number[][];\n    private _horizontalReel: number[];\n    private _respin: { pos: number[]; val: number; wheelRetriggerShown: boolean };\n    private _mutations: Array<{ cells: []; reels: []; primes: []; type: string; symbols: [] }>;\n    private _mutatedReels: number[][];\n    private _totalWinAmount: number;\n    private _stateWinAmount: number;\n    private _bonusGamesTotalWinAmount: number;\n    private _restoreJackpotWins: any[];\n    private _jpw: JackpotWin[];\n    // TO DO refactor_freespin  _blJackpotRounds _respinRounds to be only one member\n    // no need to have rounds for every feature type only rounds is enough\n    private _respinRounds: {\n        count: number;\n        type: string;\n        spin: number;\n        remain: number;\n        totalWin: number | undefined;\n        totalWinAmount: number | undefined;\n    };\n    private _freespin: { count: number; type: string; remain: number };\n    private _blJackpotRounds: { count: number; type: string; remain: number };\n    private _gaklJackpotRounds: { count: number; type: string; remain: number; totalWin?: number };\n    private _blBoostJackpotRounds: { count: number; type: string; remain: number };\n    private _bellLink: { pos: number[]; val: number[]; multiplier: number; totalWin: number; boost: boolean };\n    private _godsKingsLink: { pos: number[]; val: number[]; multiplier: number; totalWin: number; boost: boolean };\n    private _bellLinkBoost: {\n        pos: number[];\n        val: number[];\n        multiplier: number;\n        totalWin: number;\n        boostAdd: boolean;\n        boostExpand: boolean; // the old bell link boost\n        boostFour: boolean;\n    };\n    private _bonus: {\n        bet: number;\n        count: number;\n        denomination: number;\n        factor: number;\n        remain: number;\n        totalWin: number;\n        type: string;\n        // countdown campaigns only: round length in seconds, and the deadline the server\n        // stamps on the first round of the campaign\n        interval?: number;\n        expiresOn?: string;\n    };\n    private _gambles: number;\n    private _gambleHistory: number[];\n    private _matchId: any;\n    // private _retriggerFreespin: number = 0;\n    private _roundWinAmount: number = 0;\n    private _cascadeRoundWinAmount: number = 0;\n    private _bonuses: any[];\n    private _scatters: number[];\n    private _rounds: any;\n    private _wheel: number[];\n    private _bonusWins: {\n        multipliers: number[];\n        totalBonusWin: number;\n        totalBonusWinAmount: number;\n        collectSymbol: any;\n        bonusMultiplier: number;\n    };\n    private _megaRespin: {\n        reels: number[][];\n        totalWin: number;\n        totalWinAmount: number;\n    };\n\n    private _wilds: any[];\n\n    constructor(response: any, index: number) {\n        super(response);\n\n        this._result = response.game.result;\n        this._gameState = response.game.state;\n\n        let spin: any;\n        if (response.game.result?.spins) {\n            spin = response.game.result.spins[index];\n            spin.totalWinAmount = Number(spin.totalWinAmount) || 0;\n            spin.entries = spin.entries.filter(this.checkOverflow.bind(this));\n            spin.overflow = this._overflow;\n        }\n        const rounds: any = response.game.state.rounds;\n        // convert all amount from strings to number\n        response.game.state.totalWinAmount = Number(response.game.state.totalWinAmount) || 0;\n\n        this._balance = response.balance.balance;\n        this._denomination = response.balance.denomination;\n        this._currency = response.balance.currency;\n        this._state = response.state;\n        this._gambles = response.game.state.gambles;\n        if (response.game.state.gambleHistory && index === 0) {\n            this._gambleHistory = response.game.state.gambleHistory.reverse();\n        }\n        if (spin) {\n            this._entries = spin.entries.map((entry) => {\n                return new Line(\n                    entry.symbol,\n                    entry.cells,\n                    entry.line,\n                    entry.multiplier,\n                    entry.occurs,\n                    entry.win,\n                    Number(entry.winAmount),\n                    entry.mode,\n                    entry.winsJackpot,\n                    [],\n                    '',\n                    entry.ways,\n                );\n            });\n            this._reels = spin.reels;\n            this._scatterWin = spin.scatterWin;\n            this._horizontalReel = spin.horizontalReels ? spin.horizontalReels[0] : [];\n            this._mutatedReels = spin.mutatedReels;\n            this._mutations = spin.mutations;\n            this._totalWinAmount = this._roundWinAmount = this._cascadeRoundWinAmount = spin.totalWinAmount;\n        }\n        this._matchId = response.game.state.matchId;\n        this._bellLink = response.game?.result?.bellLink;\n        this._godsKingsLink = response.game?.result?.godsKingsLink;\n        this._bellLinkBoost = response.game?.result?.bellLinkBoost;\n\n        this._rounds = rounds;\n        const freeSpinBonus = rounds?.find((bonus) => bonus.type === 'FREESPIN' || bonus.type === 'FREESPIN_SCATTERS');\n        const freeRespinBonus = rounds?.find((bonus) => bonus.type === 'FREERESPIN');\n        if (freeSpinBonus && (!freeRespinBonus || freeRespinBonus.remain === 0)) {\n            this._freespin = freeSpinBonus;\n            // if (spin && spin.bonuses) {\n            //     for (const bonus of spin.bonuses) {\n            //         if (bonus.type === 'FREESPIN') {\n            //             this._retriggerFreespin = spin.bonuses[0].count;\n            //         }\n            //     }\n            // }\n        }\n        const blBonus = rounds?.find((bonus) => bonus.type === 'HOLDSPIN');\n        if (blBonus) {\n            this._blJackpotRounds = blBonus;\n            this._gaklJackpotRounds = blBonus;\n            this._blBoostJackpotRounds = blBonus;\n        }\n        if (\n            rounds &&\n            rounds[0] &&\n            (rounds[0].type === 'RESPIN' || rounds[0].type === 'FREERESPIN' || rounds[0].type === 'WHEEL_RESPIN')\n        ) {\n            this._respinRounds = rounds[0];\n        }\n        this._wheel = response.game.result?.wheel;\n\n        this._bonusGamesTotalWinAmount = Number(response.game.state.totalWinAmount) || 0;\n\n        /// REMOVE WHEN SERVER IS FIXED\n        if (response.game && response.game.state) {\n            if (response.game.state.totalWinAmount > 0) {\n                this._stateWinAmount = response.game.state.totalWinAmount;\n            }\n\n            if (response.game.state.jackpotWins) {\n                this._restoreJackpotWins = response.game.state.jackpotWins;\n            }\n        }\n        if (response.game.result && response.game.result.jpw) {\n            this._jpw = [];\n            for (const jackpot of response.game.result.jpw) {\n                this._jpw.push(jackpot);\n            }\n        }\n\n        if (spin) {\n            this._bonuses = spin.bonuses;\n        }\n\n        if (response.bonus) {\n            this._bonus = response.bonus;\n        }\n\n        if (spin) {\n            this._scatters = response.game.result.scatters;\n        }\n        if (response.game.result?.respin) {\n            this._respin = response.game.result.respin;\n        }\n\n        if (response.game.result && response.game.result.BonusWins) {\n            this._bonusWins = response.game.result.BonusWins;\n        }\n\n        if (response.game?.result?.megaRespin) {\n            this.megaRespin = response.game.result.megaRespin;\n            this._reels = this.megaRespin.reels;\n        }\n        this._wilds = response.game?.result?.wilds;\n    }\n\n    get gameState(): any {\n        return this._gameState;\n    }\n    get result(): any {\n        return this._result;\n    }\n    get balance(): number {\n        return this._balance;\n    }\n\n    get denomination(): number {\n        return this._denomination;\n    }\n\n    get gambles(): number {\n        return this._gambles;\n    }\n\n    get gambleHistory(): number[] {\n        return this._gambleHistory;\n    }\n\n    get overflow(): boolean {\n        return this._overflow;\n    }\n\n    get currency(): string {\n        return this._currency;\n    }\n\n    get state(): string {\n        return this._state;\n    }\n    set state(value: string) {\n        this._state = value;\n    }\n\n    get entries(): Line[] {\n        return this._entries;\n    }\n\n    get scatterWin(): number {\n        return this._scatterWin;\n    }\n\n    get reels(): number[][] {\n        return this._reels;\n    }\n\n    get horizontalReel(): number[] {\n        return this._horizontalReel;\n    }\n\n    get mutatedReels(): number[][] {\n        return this._mutatedReels;\n    }\n\n    get totalWinAmount(): number {\n        return this._totalWinAmount;\n    }\n\n    set totalWinAmount(value: number) {\n        if (value !== this._totalWinAmount) {\n            this._totalWinAmount = value;\n        }\n    }\n\n    get stateWinAmount(): number {\n        return this._stateWinAmount;\n    }\n\n    get roundWinAmount(): number {\n        return this._roundWinAmount;\n    }\n\n    get cascadeRoundWinAmount(): number {\n        return this._cascadeRoundWinAmount;\n    }\n\n    set cascadeRoundWinAmount(value: number) {\n        if (value !== this._cascadeRoundWinAmount) {\n            this._cascadeRoundWinAmount = value;\n        }\n    }\n\n    get jpw(): JackpotWin[] {\n        return this._jpw;\n    }\n    set jpw(value: JackpotWin[]) {\n        this._jpw = value;\n    }\n\n    get bonusGamesTotalWinAmount(): number {\n        return this._bonusGamesTotalWinAmount;\n    }\n\n    set bonusGamesTotalWinAmount(value: number) {\n        this._bonusGamesTotalWinAmount = value;\n    }\n\n    get freespin(): { count: number; type: string; remain: number } | undefined {\n        return this._freespin;\n    }\n\n    get blJackpotRounds(): { count: number; type: string; remain: number } | undefined {\n        return this._blJackpotRounds;\n    }\n\n    get gaklJackpotRounds(): { count: number; type: string; remain: number; totalWin?: number } | undefined {\n        return this._gaklJackpotRounds;\n    }\n\n    get blBoostJackpotRounds(): { count: number; type: string; remain: number } | undefined {\n        return this._blBoostJackpotRounds;\n    }\n\n    get respinRounds():\n        | {\n              count: number;\n              type: string;\n              spin: number;\n              remain: number;\n              totalWin: number | undefined;\n              totalWinAmount: number | undefined;\n          }\n        | undefined {\n        return this._respinRounds;\n    }\n\n    get mutations(): Array<{ cells: any[]; reels: any[]; primes: any[]; type: string; symbols: number[] }> {\n        return this._mutations;\n    }\n\n    get matchId(): any {\n        return this._matchId;\n    }\n\n    get bonusWins(): any {\n        return this._bonusWins;\n    }\n\n    set bonusWins(value: any) {\n        this._bonusWins = value;\n    }\n\n    get megaRespin(): any {\n        return this._megaRespin;\n    }\n\n    set megaRespin(value: any) {\n        this._megaRespin = value;\n    }\n\n    // get retriggerFreespin(): number {\n    //     return this._retriggerFreespin;\n    // }\n\n    get bonuses(): any[] {\n        return this._bonuses;\n    }\n\n    get bellLink(): any {\n        return this._bellLink;\n    }\n    set bellLink(value: any) {\n        this._bellLink = value;\n    }\n\n    get godsKingsLink(): any {\n        return this._godsKingsLink;\n    }\n    set godsKingsLink(value: any) {\n        this._godsKingsLink = value;\n    }\n\n    get bellLinkBoost(): any {\n        return this._bellLinkBoost;\n    }\n    set bellLinkBoost(value: any) {\n        this._bellLinkBoost = value;\n    }\n\n    get bonus(): any {\n        return this._bonus;\n    }\n\n    set bonus(value: any) {\n        this._bonus = value;\n    }\n\n    get scatters(): number[] {\n        return this._scatters;\n    }\n\n    get respin(): { pos: number[]; val: number; wheelRetriggerShown: boolean } {\n        return this._respin;\n    }\n\n    get rounds(): any[] {\n        return this._rounds;\n    }\n\n    set rounds(setRounds) {\n        this._rounds = setRounds;\n    }\n\n    get wheel(): number[] {\n        return this._wheel;\n    }\n\n    get restoreJackpotWins(): any[] {\n        return this._restoreJackpotWins;\n    }\n\n    get wilds(): any[] {\n        return this._wilds;\n    }\n\n    private checkOverflow(a): boolean {\n        if (a.mode !== LineMode.OVERFLOW) {\n            return true;\n        }\n        this._overflow = true;\n        return false;\n    }\n}\n","enum BonusTypes {\n    GIFT_SPIN = 'GIFT_SPIN',\n    BUY_BONUS = 'BUY_BONUS',\n    COUNTDOWN = 'COUNTDOWN',\n}\n\nexport default BonusTypes;\n","import { Log } from '@egt/core';\nimport { Subject } from 'rxjs';\nimport PriorityList from './PriorityList';\n\nexport default class ChainSubject<T> extends Subject<T> {\n    public priorities: PriorityList;\n    public executors: Map<string, any> = new Map<string, any>();\n    private _stopNextExecutor: boolean = false;\n\n    public chainSubscribe(feature: string, callback: any): void {\n        this.executors.set(feature, callback);\n    }\n\n    public executorExecOnly(nextPriority: string): void {\n        const pointer = this.priorities.setPriorityTo(nextPriority);\n        if (pointer > -1) {\n            if (this.executors.has(nextPriority)) {\n                this._stopNextExecutor = true;\n                this.executors.get(nextPriority)();\n            }\n        } else {\n            Log.error('*** PRIORITY NOT FOUND', nextPriority);\n        }\n    }\n\n    public executorContinueTo(nextPriority: string): void {\n        const pointer = this.priorities.setPriorityTo(nextPriority);\n        this._stopNextExecutor = false;\n        if (pointer > -1) {\n            if (this.executors.has(nextPriority)) {\n                this.executors.get(nextPriority)();\n            }\n            this.priorities.checkForResetPointer();\n        } else {\n            this.executorComplete();\n        }\n    }\n\n    public executorComplete(): void {\n        if (this._stopNextExecutor) {\n            this._stopNextExecutor = false;\n            return;\n        }\n        const nextPriority: string = this.priorities.nextPriority();\n        if (this.executors.has(nextPriority)) {\n            this.executors.get(nextPriority)();\n        }\n        this.priorities.checkForResetPointer();\n    }\n\n    public destroy(): void {\n        this.executors.clear();\n        this.priorities.destroy();\n        // @ts-ignore\n        this.priorities = null;\n        // @ts-ignore\n        this.executors = null;\n    }\n}\n","import { IRequest } from '@egt/core';\n\nexport default class CollectRequest implements IRequest {\n    constructor(\n        private amount: number,\n        private denomination: number,\n        private lines: number,\n    ) {}\n\n    public serialize(): any {\n        return {\n            event: 'collect',\n            bet: {\n                level: this.amount,\n                denomination: this.denomination,\n                lines: this.lines,\n                // This will be different for games that have bigger bet over lines:\n                // Example: 40 burning hot -> has bet 50 over 40 lines\n                // {\n                // \tlevel: 1,\n                // \tdenomonination: 1,\n                // \tlines: 40,\n                // \tfactor: 50\n                // }\n                factor: this.lines,\n            },\n        };\n    }\n}\n","export default class CollectResponse {\n    private _balance: number;\n    private _denomination: number;\n    private _currency: string;\n    private _state: string;\n    private _bonus: {\n        bet: number;\n        count: number;\n        denomination: number;\n        factor: number;\n        remain: number;\n        spin: number;\n        totalWin: number;\n        type: string;\n    };\n\n    constructor(response: any) {\n        this._balance = response.balance.balance;\n        this._denomination = response.balance.denomination;\n        this._currency = response.balance.currency;\n        this._state = response.state;\n        if (response.bonus) {\n            this._bonus = response.bonus;\n        }\n    }\n\n    get balance(): number {\n        return this._balance;\n    }\n\n    get denomination(): number {\n        return this._denomination;\n    }\n\n    get currency(): string {\n        return this._currency;\n    }\n\n    get state(): string {\n        return this._state;\n    }\n\n    get bonus(): any {\n        return this._bonus;\n    }\n}\n","import { BehaviorSubject } from 'rxjs';\n\nexport default class CustomBehaviorSubject<T> extends BehaviorSubject<T> {\n    public additionalData: any;\n\n    constructor(val: T) {\n        super(val);\n    }\n}\n","import Core, { AnalyticsDispatcher, BalanceResponse, BaseStore } from '@egt/core';\nimport { Subject, Subscription } from 'rxjs';\nimport { tap } from 'rxjs/operators';\nimport { ISlotConfiguration } from '../../slot-configuration/ISlotConfiguration';\nimport Features from '../feature/Features';\nimport RootStore from '../root/RootStore';\nimport UIState from '../ui/UIState';\nimport BetRequest from './BetRequest';\nimport BetResponse from './BetResponse';\nimport CollectRequest from './CollectRequest';\nimport CollectResponse from './CollectResponse';\nimport HistorySubject from './HistorySubject';\nimport MessBarTypes from './MessBarTypes';\nimport RestoreResponse from './RestoreResponse';\nimport ServerState from './ServerState';\nimport StateSubject from './StateSubject';\n\nexport default class DomainStore extends BaseStore {\n    public serverBetResponse: any = {};\n    public currentSpinResults: number = 0;\n    public readonly BET: Subject<BetResponse> = new Subject();\n    public readonly COLLECT_RESPONSE: Subject<CollectResponse> = new Subject();\n    public readonly SPIN_MODE: StateSubject<string> = new StateSubject(Features.MANUAL_SPIN);\n    /** holds original game state received from server */\n    public readonly SERVER_STATE: HistorySubject<string> = new HistorySubject(ServerState.UNSET);\n\n    private _betResponse: BetResponse;\n    private _collectResponse: CollectResponse;\n    private _balanceResponse: BalanceResponse;\n    private _onGameMessageSubscription: Subscription;\n\n    private collectRequested: boolean;\n\n    constructor(\n        private rootStore: RootStore,\n        private slotConfiguration: ISlotConfiguration,\n    ) {\n        super();\n        this.enableLogging();\n        this.SPIN_MODE.pipe(\n            tap((value) => {\n                AnalyticsDispatcher.spinMode = value;\n            }),\n        ).subscribe();\n        this._onGameMessageSubscription = Core.ON_SERVER_MESSAGE.subscribe(this.onMessage.bind(this));\n    }\n\n    public get betResponse(): BetResponse {\n        return this._betResponse;\n    }\n    public set betResponse(value: BetResponse) {\n        this._betResponse = value;\n    }\n\n    public get collectResponse(): CollectResponse {\n        return this._collectResponse;\n    }\n\n    public bet(): any {\n        if (this.currentSpinResults > 0 && !this.slotConfiguration.cascadeGame) {\n            this.setBet(\n                this.serverBetResponse,\n                this.serverBetResponse.game.result.spins.length - this.currentSpinResults,\n            );\n            this.currentSpinResults -= 1;\n            this.rootStore.subjects.REELS_STOPPED.next();\n        } else {\n            //this event should be dispatched only when new bet request is created this is for notification for new bet to server\n            this.rootStore.uiStore.NEW_BET_REQUEST_CREATED.next();\n            // TODO: remove customResultStore values for Dragons when protocol and server are done\n            const customDemo: any = {};\n            if (this.rootStore.customResultStore.isCustomDemoFeatureResult.value.customValue) {\n                customDemo[this.rootStore.customResultStore.isCustomDemoFeatureResult.value.feature] =\n                    this.rootStore.customResultStore.isCustomDemoFeatureResult.value.customValue;\n            }\n            const request: BetRequest = new BetRequest(\n                this.rootStore.uiStore.SELECTED_BET.value,\n                Core.SELECTED_DENOMINATION.value,\n                this.rootStore.uiStore.LINES.value,\n                this.rootStore.customResultStore.request,\n                this.rootStore.uiStore.selectedDemoResult,\n                this.rootStore.settings,\n                this.rootStore.customResultStore.isDRGPick.value,\n                this.rootStore.customResultStore.isDRGRespin.value,\n                this.rootStore.customResultStore.multislamValue.value,\n                this.rootStore.customResultStore.pearlyBeachFeatures.value,\n                this.rootStore.customResultStore.isBLBoostJackpotTrigger.value,\n                this.rootStore.subjects.NUMBER_OF_REELS.value,\n                this.SPIN_MODE.value === Features.AUTO_PLAY ? true : false,\n                this.rootStore.customResultStore.rngRequest,\n                this.rootStore.customResultStore.leprechaunWheelFeatures.value,\n                customDemo,\n            );\n            Core.sendMessage(request);\n        }\n    }\n\n    public collect(): any {\n        if (this.collectRequested) {\n            return;\n        }\n        const request: CollectRequest = new CollectRequest(\n            this.rootStore.uiStore.SELECTED_BET.value,\n            Core.SELECTED_DENOMINATION.value,\n            this.rootStore.uiStore.LINES.value,\n        );\n        Core.DISABLE_KEYBOARD_EVENTS.next(true);\n        Core.sendMessage(request);\n        this.collectRequested = true;\n    }\n\n    // public freeSpinRestore(): void {\n    //     this.RESTORE.next(this._betResponse.restoreResponse);\n    // }\n\n    public destroy(): void {\n        this._onGameMessageSubscription.unsubscribe();\n        // @ts-ignore\n        this._onGameMessageSubscription = null;\n        Core.ON_SERVER_MESSAGE.observers.forEach((observer) => observer.complete());\n        Core.ON_CONNECTION_RESTORED.observers.forEach((observer) => observer.complete());\n        // @ts-ignore\n        delete this.rootStore;\n        if (this._betResponse) {\n            // @ts-ignore\n            this._betResponse = null;\n        }\n        if (this._collectResponse) {\n            // @ts-ignore\n            this._collectResponse = null;\n        }\n        if (this._balanceResponse) {\n            // @ts-ignore\n            this._balanceResponse = null;\n        }\n        if (this.BET) {\n            this.BET.complete();\n            // @ts-ignore\n            this.BET = null;\n        }\n        if (this.COLLECT_RESPONSE) {\n            this.COLLECT_RESPONSE.complete();\n            // @ts-ignore\n            this.COLLECT_RESPONSE = null;\n        }\n        if (this.SPIN_MODE) {\n            this.SPIN_MODE.complete();\n            // @ts-ignore\n            this.SPIN_MODE = null;\n        }\n        if (this.SERVER_STATE) {\n            this.SERVER_STATE.complete();\n            // @ts-ignore\n            this.SERVER_STATE = null;\n        }\n        if (this.slotConfiguration) {\n            // @ts-ignore\n            this.slotConfiguration = null;\n        }\n        if (this.rootStore) {\n            // @ts-ignore\n            this.rootStore = null;\n        }\n        if (this.serverBetResponse) {\n            // @ts-ignore\n            this.serverBetResponse = null;\n        }\n    }\n\n    public setBet(betResponse: any, index: number): void {\n        this._betResponse = new BetResponse(betResponse, index);\n        this.BET.next(this._betResponse);\n    }\n\n    public setBalance(balanceResponse: any): void {\n        this._balanceResponse = new BalanceResponse(balanceResponse);\n        if (this.rootStore.uiStore.BALANCE.value !== this._balanceResponse.balance) {\n            this.rootStore.uiStore.BALANCE.next(this._balanceResponse.balance);\n            if (\n                this.rootStore.uiStore.STATE.value === UIState.IDLE ||\n                (this.rootStore.subjects.SHOW_DIRECT_MESSAGEBAR_TEXT.value &&\n                    this.rootStore.subjects.SHOW_DIRECT_MESSAGEBAR_TEXT.value[0] === MessBarTypes.INSUFFICIENT &&\n                    this.rootStore.uiStore.BALANCE.value >= this.rootStore.getBetAmount())\n            ) {\n                this.rootStore.subjects.SHOW_DIRECT_MESSAGEBAR_TEXT.next(false);\n            }\n        }\n    }\n\n    private setCollect(collectResponse: any): void {\n        this.collectRequested = false;\n        Core.DISABLE_KEYBOARD_EVENTS.next(false);\n        this._collectResponse = new CollectResponse(collectResponse);\n        this.COLLECT_RESPONSE.next(this._collectResponse);\n        this.setBalance(collectResponse);\n\n        if (this.rootStore.uiStore.STATE.value !== UIState.SLIDING_BETS) {\n            this.rootStore.uiStore.STATE.next(collectResponse.state);\n        }\n\n        // this.rootStore.uiStore.WIN.next({ amount: 0, action: BangupActionConsts.COLLECT, feature: Features.NONE });\n    }\n\n    private onMessage(response: any): void {\n        /**\n         * 'collectPrizePop' always carries game.restore, but there's nothing of interest for us in there\n         */\n        if (response.game && response.game.restore && response.event !== 'collectPrizePop') {\n            const restoreResponse = new RestoreResponse(response.game.restore[response.game.result.restorePoints[0]]);\n            this.rootStore.subjects.RESTORE_BET.next(restoreResponse);\n        }\n\n        // store original state from server\n        if (response.state) {\n            this.SERVER_STATE.next(response.state);\n        }\n\n        // store gambles on every response if exists\n        if (response.game && response.game.state && response.game.state.gambles !== undefined) {\n            this.rootStore.uiStore.gamblesLeft = response.game.state.gambles;\n        }\n\n        // if it is collect do not change balance - it will be done after the balance bangup animation\n        if (response.balance !== undefined && response.event !== 'collect') {\n            this.setBalance(response);\n        }\n\n        switch (response.event) {\n            case 'bet':\n            case 'restore':\n                if (response.game.result.spins) {\n                    this.currentSpinResults = response.game.result.spins.length - 1;\n                }\n                this.serverBetResponse = response;\n                this.setBet(response, 0);\n                break;\n            case 'collectPrizePop':\n                if (response.game.state?.rounds.length > 1) {\n                    this.serverBetResponse.game.state = response.game.state;\n                    break;\n                }\n                if (response.game.result.spins) {\n                    this.currentSpinResults = response.game.result.spins.length - 1;\n                }\n                this.serverBetResponse = response;\n                this.setBet(response, 0);\n                break;\n            case 'collect':\n                this.setCollect(response);\n                break;\n            case 'loadGame':\n                this.setBalance(response);\n                this.rootStore.subjects.REELS_STOP_ALL.next();\n                this.rootStore.uiStore.STATE.next(response.state);\n                break;\n            case 'pick':\n                this.serverBetResponse = response;\n                break;\n        }\n    }\n}\n","import { IRequest } from '@egt/core';\n\nexport default class FreeSpinRestoreRequest implements IRequest {\n    public serialize(): any {\n        return {\n            event: 'restore',\n        };\n    }\n}\n","import { BehaviorSubject } from 'rxjs';\nimport Features from '../feature/Features';\nimport BangupActionConsts from '../ui/BangupActionConsts';\n\nexport default class HistorySubject<T> extends BehaviorSubject<T> {\n    public prevValue: any;\n\n    constructor(val: T) {\n        super(val);\n    }\n\n    public next(val: T): void {\n        // TODO: better to have other Subject class for WINSUBJECT instead HistorySubject\n\n        if (val && val['action']) {\n            switch (val['action']) {\n                case BangupActionConsts.RESTORE:\n                    this.prevValue = {};\n\n                    this.prevValue['amount'] = val['amount'];\n\n                    this.prevValue['action'] = BangupActionConsts.SET;\n\n                    this.prevValue['feature'] = Features.RESTORE;\n\n                    val['amount'] = 0;\n\n                    val['action'] = BangupActionConsts.RESTORE;\n\n                    val['feature'] = Features.RESTORE;\n                    break;\n                case BangupActionConsts.ADD:\n                    val['amount'] = (this.prevValue ? this.prevValue['amount'] : 0) + val['amount'];\n                    this.prevValue = this.value;\n                    break;\n                case BangupActionConsts.WIN:\n                    this.prevValue = { amount: 0, action: BangupActionConsts.SET, feature: val['feature'] };\n                    break;\n                case BangupActionConsts.COLLECT:\n                    val['amount'] = 0;\n\n                    this.prevValue = {\n                        amount: this.value['amount'],\n                        action: BangupActionConsts.SET,\n\n                        feature: val['feature'],\n                    };\n                    break;\n                default:\n                    this.prevValue = this.value;\n            }\n        } else {\n            this.prevValue = this.value;\n        }\n        super.next(val);\n    }\n\n    public restore(): void {\n        super.next(this.prevValue);\n    }\n\n    public get prev(): T {\n        return this.prevValue;\n    }\n}\n","import Core, { Log } from '@egt/core';\nimport { injectable } from 'tsyringe';\nimport LineMode from '../lines/LineMode';\nimport BonusTypes from './BonusTypes';\nimport ServerState from './ServerState';\n\n@injectable()\nexport default class InitialSettings {\n    public settings;\n    private _autoplay: boolean = true;\n    private _matchId: string = '';\n    private _balance: number;\n    private _denomination: number;\n    private _currency: string;\n    private _state: string;\n    private _bet: number;\n    private _factor: number;\n    private _factors: number[];\n    private _gameMode: string;\n    private _gameModes: { gameMode: string; factor: number; lines: number }[];\n    private _buyBonusOptions: number[];\n    private _denominations: number[];\n    private _buyBonusDenominations: null | number[] = null;\n    private _paytable: any;\n    private _reels: number[][];\n    private _multipliers: number[][];\n    private _multiplier: number;\n    private _mutatedReels: number[][];\n    private _bets: number[];\n    private _lines: number;\n    private _linesOptions: number[];\n    private _win: number;\n    private _lastBetWin: number;\n    private _entries: any[];\n    private _units: number;\n    private _demoWins: string[];\n    private _gambleMax: number;\n    private _gambleMultiplier: number;\n    private _gambles: number;\n    private _cancelGSAvailable = false;\n    private _maxGambleAttempts: number = 0;\n    private _gsFinalCollection: boolean = false;\n    private _gsHideInfo: boolean = false;\n    // private _coinFeatureCoef: number = 15;\n    private _mutations: Array<{ cells: []; reels: []; primes: []; type: string }>;\n    // TODO: Remove this. We will recieve the last BetResponse instead of this.\n    private _freespin: { count: number; type: string; spin: number; remain: number };\n    private _restoringFromFreespin: boolean = false;\n    private _jackpotStats: any;\n    private _bellLink: { pos: number[]; val: number[]; multiplier: number; totalWin: number; boost: boolean };\n    private _blJackpotRounds: { count: number; type: string; spin: number; remain: number };\n    private _godsKingsLink: { pos: number[]; val: number[]; multiplier: number; totalWin: number; boost: boolean };\n    private _gaklJackpotRounds: { count: number; type: string; spin: number; remain: number };\n    private _bellLinkBoost: {\n        pos: number[];\n        val: number[];\n        multiplier: number;\n        totalWin: number;\n        boostAdd: boolean;\n        boostExpand: boolean; // the old bell link boost\n        boostFour: boolean;\n    };\n    private _blBoostJackpotSeedValues: {\n        bonusCoinFeature: number;\n        boostGrandValues: number;\n        boostMajorValues: number;\n        mini: number;\n        minor: number;\n    };\n    private _blBoostJackpotRounds: { count: number; type: string; spin: number; remain: number };\n    private _bonusWins: {\n        multipliers: number[];\n        totalBonusWin: number;\n        totalBonusWinAmount: number;\n        collectSymbol: any;\n        bonusMultiplier: number;\n    };\n    private _autoplayRestrictions: any;\n    private _bonus: {\n        bet: number;\n        count: number;\n        denomination: number;\n        factor: number;\n        remain: number;\n        spin: number;\n        totalWin: number;\n        type: BonusTypes;\n        validityDate: string;\n        endDate: string;\n        // countdown campaigns only: round length in seconds, and the deadline the server\n        // stamps on the first round of the campaign\n        interval?: number;\n        expiresOn?: string;\n    };\n    private _clientSettings: any;\n    private _bonusSummary: any;\n    private _scatterCoefs: number[][];\n    private _rtp: any;\n    private _minimumSpinTime: number = 0;\n    private _gameVersion: string = '';\n    private _limit: any;\n    private _numberOfLinesPerDenomination: [number, number][];\n    private _country: string;\n    private _maxBet: number;\n    private _wilds: any[];\n    private _gameName: string;\n    private _gameSummary: any;\n    private _multipleLinesGameAvailableLines: number[];\n    private _enableVipUi: boolean;\n\n    constructor(settings: any) {\n        //for testing\n        // this._gameModes = [\n        //     {\n        //         gameMode: 'NORMAL_MODE',\n        //         factor: 20,\n        //     },\n        //     {\n        //         gameMode: 'DOUBLE_CHANCE',\n        //         factor: 25,\n        //     },\n        //     {\n        //         gameMode: 'WISDOM_SPINS',\n        //         factor: 2000,\n        //     },\n        // ];\n        //   this._gameModes = [\n        //     {\n        //       gameMode: \"NORMAL_MODE\",\n        //       factor: 50\n        //     },\n        //     {\n        //       gameMode: \"NORMAL_MODE\",\n        //       factor: 25\n        //     }\n        //   ];\n\n        // to be used if you need to check bug with more than 1 denom\n\n        // settings.settings.bets = [\n        //     1, 2, 5, 8, 10, 12, 15, 20, 25, 30, 50, 100, 120, 150, 200, 250, 500, 700, 800, 1000, 1500, 2000, 3000,5000,10000\n        // ];\n        // settings.settings.denominations = [1,2,3,5,10];\n        // to be used if you need to check bug with more than 1 denom\n        this.settings = settings;\n        this._balance = settings.balance.balance;\n        this._units = settings.balance.units;\n        // for testing with on denom\n        // settings.settings.denomination = 1;\n        this._denomination = settings.settings.denomination;\n        this._currency = settings.balance.currency;\n        this._state = settings.state;\n        this._bet = settings.settings.bet;\n        this._denominations = settings.settings.denominations;\n\n        if (settings.settings?.buyBonus?.denominations?.length > 0) {\n            const bbDenomValues: number[] = [];\n            for (const denom of settings.settings.buyBonus.denominations) {\n                bbDenomValues.push(settings.settings.denominations[denom - 1]);\n            }\n            this._buyBonusDenominations = bbDenomValues;\n        }\n        //for test with one denom\n        // this._denominations = [1];\n\n        // settings.settings.denomination = 1;\n        this._paytable = settings.settings.paytable;\n        this._reels = settings.settings.reels;\n        this._multipliers = settings.settings.multipliers;\n        this._multiplier = settings.settings.multiplier;\n        if (settings.settings.scatterCoefs) {\n            this._scatterCoefs = settings.settings.scatterCoefs;\n        }\n        this._limit = settings.settings.limit;\n        this._clientSettings = settings.settings.clientSettings;\n\n        // for testing max bet amount\n        // this._clientSettings.maxBetLimits = {\n        //     BGN: 10000,\n        //     EUR: 10000,\n        //     RSD: 10000,\n        //     USD: 10000,\n        //     EGT: 10,\n        // };\n        //max bet for Greece\n        // this.settings.settings.jurisdiction.maxJurisdictionalBet = [{ EGT: 20 }, { EUR: 20 }, { USD: 20 }];\n\n        this._rtp = settings.settings.clientSettings?.rtp;\n        // this._rtp = {\n        //     \"min\": 9651,\n        //     \"max\": 9651,\n        //     \"showTotals\": false,\n        //     \"doubleChance\": 9568, \"buyBonus\": 9685,\n        //     // }\n        //     \"modes\":\n\n        //         { \"BUY_BONUS\": 9685, \"DOUBLE_CHANCE\": 9568, \"NORMAL_MODE\": 9651 }\n\n        // }\n        // if (!settings.settings.rtp) {\n        //     this._rtp = {\n        //         min: 96.17,\n        //         max: 98.05\n        //     }\n        // } else {\n        //     this._rtp = settings.settings.rtp;\n        // }\n        // this._reels = [\n        //     [3, 102, 101, 101, 0],\n        //     [1, 120, 108, 101, 3],\n        //     [3, 101, 150, 1, 6],\n        //     [7, 103, 10, 105, 1],\n        //     [0, 101, 101, 101, 10],\n        // ];\n\n        this._bets = settings.settings.bets;\n        //for test with one denom\n        // this._bets = [1, 2, 4, 6, 8, 10, 12, 16, 20, 30, 40, 50, 60, 80, 100, 120, 160, 200, 240, 300, 360, 400, 500, 600, 1000, 1200, 1600, 2000, 2400, 3000, 4000, 5000, 6000, 8000, 10000];\n        // TODO only for review delete later\n        // this._bets.pop();\n        // this._bets.pop();\n        this._maxBet = settings.settings.jurisdiction?.maxJurisdictionalBet?.find(\n            (bet) => bet && bet.hasOwnProperty(this.currency),\n        )?.[this.currency];\n        this._lines = settings.settings.lines;\n        this._linesOptions = settings.settings.linesOptions;\n        if (settings.settings.hasOwnProperty('gamble') && settings.settings.gamble.hasOwnProperty('doubleUp')) {\n            this._gambleMax = settings.settings.gamble.doubleUp.maxGambleAmount;\n            this._gambleMultiplier = settings.settings.gamble.doubleUp.maxBetLimit;\n            this._maxGambleAttempts = settings.settings.gamble.doubleUp.maxGambleAttempts;\n        }\n        // this._maxBet = 800;\n        this._jackpotStats = settings.jackpotStats;\n\n        this._factor = settings.settings.factor;\n        this._factors = settings.settings.factors;\n        this._buyBonusOptions = settings.settings.buyBonusOptions;\n        // if (settings.settings.buyBonusOptions) {\n        //     this._buyBonusOptions = [430, 1050, 2940]; // only for testing, comment this if block when buy bonus backend is ready\n        // }\n\n        this._country = settings.settings.jurisdiction.country;\n        this._enableVipUi = settings.settings.clientSettings.enableVipUi;\n        this._minimumSpinTime = settings.settings.jurisdiction.minimumSpinTime\n            ? settings.settings.jurisdiction.minimumSpinTime\n            : 0;\n\n        this._gameVersion = settings.settings.gameVersion ? settings.settings.gameVersion : '';\n        if (this._factors.indexOf(this._factor) === -1) {\n            this._factor = this._factors[0];\n        }\n\n        if (settings.bonus && settings.bonus.factor && settings.bonus.type !== BonusTypes.BUY_BONUS) {\n            this._factor = settings.bonus.factor;\n        }\n\n        if (settings.settings.jurisdiction.gsFinalCollection) {\n            this._gsFinalCollection = settings.settings.jurisdiction.gsFinalCollection;\n        }\n\n        if (settings.settings.jurisdiction.gsHideInfo) {\n            this._gsHideInfo = settings.settings.jurisdiction.gsHideInfo;\n        }\n\n        // if (settings.game.state.bet && settings.game.state.bet.gameMode) {\n        //     this._gameMode = settings.game.state.bet.gameMode;\n        // } else {\n        this._gameMode = 'NORMAL_MODE';\n        // }\n        if (settings.settings.gameModes) {\n            this._gameModes = settings.settings.gameModes;\n            //     // for testing\n            //     // remove next for loop when server add lines in game modes\n            //     for (let i: number = 0; i < this._gameModes.length; i++) {\n            //         this._gameModes[i].lines = this._linesOptions[i];\n            //     }\n        }\n\n        if (settings.settings.jurisdiction.hasOwnProperty('autoplayRestrictions')) {\n            this._autoplayRestrictions = settings.settings.jurisdiction.autoplayRestrictions;\n            if (settings.settings.jurisdiction.autoplayRestrictions.extend === undefined) {\n                this._autoplayRestrictions.extend = true;\n            }\n            if (\n                this._autoplayRestrictions.autoPlays === undefined ||\n                this._autoplayRestrictions.autoPlays.length === 0\n            ) {\n                this._autoplayRestrictions.autoPlays = [10, 20, 50, 100, -1];\n            }\n        } else {\n            this._autoplay = false;\n            this._autoplayRestrictions = {\n                mandatory: [],\n                autoPlays: [10, 20, 50, 100, -1],\n                lossLimits: [20],\n                winLimits: [20],\n                singleWinLimit: 5000,\n                infinityByDefault: false,\n                extend: true,\n            };\n        }\n\n        // this._autoplayRestrictions = {\n        //     mandatory: [],\n        //     autoPlays: [10, 20, 50, 100, -1],\n        //     lossLimits: [20],\n        //     winLimits: [20],\n        //     singleWinLimit: 5000,\n        //     infinityByDefault: false,\n        //     extend: true,\n        // };\n        // this._autoplayRestrictions.mandatory = ['lossLimits'];\n\n        if (settings.settings.hasOwnProperty('demo') && settings.settings.demo.length > 0) {\n            this._demoWins = settings.settings.demo;\n        } else {\n            this._demoWins = [];\n        }\n        if (settings.hasOwnProperty('bonus')) {\n            this._bonus = settings.bonus;\n        }\n\n        // if (settings.settings.hasOwnProperty('coinFeature')) {\n        //     this._coinFeatureCoef = settings.settings.coinFeature;\n        // }\n\n        if (settings.hasOwnProperty('game')) {\n            this._matchId = settings.game.state.matchId;\n            const result: any = settings.game.result;\n            const state: any = settings.game.state;\n            let restore: any;\n            if (settings.game.restore) {\n                restore =\n                    settings.game.restore[\n                        this.settings.game.result.restorePoints[this.settings.game.result.restorePoints.length - 1]\n                    ];\n            } else {\n                restore = settings.game.result;\n            }\n\n            if (state && state.bet) {\n                this._denomination = state.bet.denomination;\n                this._bet = state.bet.level;\n                if (this._linesOptions && this._linesOptions.length > 1) {\n                    this._factor = state.bet.factor;\n                }\n            }\n\n            /*  if (state && state.gambleHistory) {\n                this._gambleHistory = state.gambleHistory.reverse();\n            } */\n\n            if (result && result.spins && result.spins[result.spins.length - 1]) {\n                // convert strings to number\n                state.totalWinAmount = Number(state.totalWinAmount);\n                result.spins[result.spins.length - 1].totalWinAmount = Number(\n                    result.spins[result.spins.length - 1].totalWinAmount,\n                );\n\n                this._entries = result.spins[result.spins.length - 1].entries.filter(\n                    (a) => a.mode !== LineMode.OVERFLOW,\n                );\n                this._reels = result.spins[result.spins.length - 1].reels;\n                this._multipliers = result.spins[result.spins.length - 1].multipliers;\n                this._multiplier = result.spins[result.spins.length - 1].multiplier;\n                this._mutations = result.spins[result.spins.length - 1].mutations;\n                this._mutatedReels = result.spins[result.spins.length - 1].mutatedReels;\n                if (\n                    result.spins[result.spins.length - 1].type &&\n                    result.spins[result.spins.length - 1].type === 'FREESPIN'\n                ) {\n                    // this._win =\n                    //     settings.game.state.totalWin * this._denomination ||\n                    //     result.spins[result.spins.length - 1].totalWin * this._denomination;\n                    this._win =\n                        settings.game.state.totalWinAmount || result.spins[result.spins.length - 1].totalWinAmount || 0;\n                    this._lastBetWin = settings.state === 'idle' ? this._win : 0;\n                    this._restoringFromFreespin = this._state === 'win';\n                } else {\n                    this._win = settings.game.state.totalWinAmount;\n                    // if (this._win === 0) {\n                    //     this._win = state.totalWin * this._denomination;\n                    // }\n                    this._lastBetWin = this._win > 0 && settings.state === 'idle' ? this._win : 0;\n                    this._gambles = settings.game.state.gambles;\n                }\n                this._wilds = result.wilds;\n            }\n\n            // Restore Gamble\n            if (result && result.type && result.type === 'GAMBLE') {\n                this._win = settings.game.state.totalWinAmount;\n                this._lastBetWin = 0;\n                this._gambles = settings.game.state.gambles;\n            }\n\n            if (result && result.bonusSummary) {\n                this._bonusSummary = result.bonusSummary;\n            }\n\n            if (restore && restore.spins) {\n                this._entries = restore.spins[restore.spins.length - 1].entries.filter(\n                    (a) => a.mode !== LineMode.OVERFLOW,\n                );\n                this._reels = restore.spins[restore.spins.length - 1].reels;\n                this._wilds = restore.wilds;\n                this._multipliers = restore.spins[restore.spins.length - 1].multipliers;\n                this._multiplier = restore.spins[restore.spins.length - 1].multiplier;\n            }\n\n            if (settings.game.state.rounds) {\n                for (const round of settings.game.state.rounds) {\n                    if (round.type === ServerState.FREESPIN) {\n                        this._freespin = round;\n                        break;\n                    }\n                }\n            }\n\n            // restore bl jackpot\n            if (this._state === 'holdspin') {\n                if (settings.game.result.bellLink) {\n                    this._bellLink = settings.game.result.bellLink;\n                } else if (settings.game.result.godsKingsLink) {\n                    this._godsKingsLink = settings.game.result.godsKingsLink;\n                } else if (settings.game.result.bellLinkBoost) {\n                    this._bellLinkBoost = settings.game.result.bellLinkBoost;\n                }\n                if (\n                    settings.game.state.rounds &&\n                    settings.game.state.rounds.find((round) => round.type === 'HOLDSPIN')\n                ) {\n                    if (settings.game.result.bellLink) {\n                        this._blJackpotRounds = settings.game.state.rounds[0];\n                    } else if (settings.game.result.godsKingsLink) {\n                        this._gaklJackpotRounds = settings.game.state.rounds.find((round) => round.type === 'HOLDSPIN');\n                    } else if (settings.game.result.bellLinkBoost) {\n                        this._blBoostJackpotRounds = settings.game.state.rounds[0];\n                    }\n                }\n            }\n\n            // restore points for KTSlot\n            if (result && result.BonusWins && Object.keys(result.BonusWins).length !== 0) {\n                this._bonusWins = result.BonusWins;\n            }\n            if (restore && restore.BonusWins && Object.keys(restore.BonusWins).length !== 0) {\n                this._bonusWins = restore.BonusWins;\n                // the case when you enter free spins with 3 scatters and respin, then interupt before fs start\n                // and recovery in fs intro ( the problem was that the win amount is 0 )\n                if (this._state === 'freespin' && settings.game.restore && settings.game.restore.SPIN) {\n                    this._win = settings.game.state.totalWinAmount;\n                }\n            }\n            if (this._state === 'megaRespin') {\n                if (result && result.BonusWins && Object.keys(result.BonusWins).length !== 0) {\n                    this._bonusWins = result.BonusWins;\n                }\n                if (!result.respin && result.spins) {\n                    this._reels = result.spins[result.spins.length - 1].reels;\n                    this._multipliers = result.spins[result.spins.length - 1].multipliers;\n                } else if (result.respin) {\n                    this._win = settings.game.state.totalWinAmount;\n                    if (settings.game.restore.FREESPIN) {\n                        this._bonusWins = settings.game.restore.FREESPIN.BonusWins;\n                        this._reels = settings.game.restore.FREESPIN.spins[0].reels;\n                        this._multipliers = settings.game.restore.FREESPIN.spins[0].multipliers;\n                    }\n                }\n            } else if (this._state === 'freespin' && settings.game.restore && settings.game.restore.FREESPIN) {\n                this._bonusWins = settings.game.restore.FREESPIN.BonusWins;\n                this._reels = settings.game.restore.FREESPIN.spins[0].reels;\n                this._multipliers = settings.game.restore.FREESPIN.spins[0].multipliers;\n                this._multiplier = settings.game.restore.FREESPIN.spins[0].multiplier;\n                if (result.respin) {\n                    this._win = settings.game.state.totalWinAmount;\n                }\n            }\n        }\n        // restore points for KTSlot End\n\n        if (\n            settings.settings.hasOwnProperty('linesPerDenomination') &&\n            (settings.settings['linesPerDenomination'] as number[]).length\n        ) {\n            const denominations = [...settings.settings.denominations];\n            const linesPerDenomination = [...settings.settings.linesPerDenomination];\n\n            this._numberOfLinesPerDenomination = [];\n            for (let i = 0; i < denominations.length; i++) {\n                this._numberOfLinesPerDenomination.push([denominations[i], linesPerDenomination[i]]);\n            }\n\n            //NB exact oreder should be considered, this.filterDenominations() checks maxBet opposing to _numberOfLinesPerDenomination;\n            const denominationsAccordingToMaxBet = this._maxBet\n                ? this.filterDenominations()\n                : [...settings.settings.denominations];\n            this._multipleLinesGameAvailableLines = this._numberOfLinesPerDenomination.reduce(\n                (acc: number[], curr, i) => {\n                    const [denomination, lines] = curr;\n                    if (\n                        !!denominationsAccordingToMaxBet[i] &&\n                        denominationsAccordingToMaxBet[i] === denomination &&\n                        !acc.includes(lines)\n                    ) {\n                        acc.push(lines);\n                    }\n                    return acc;\n                },\n                [],\n            );\n        }\n\n        if (settings.settings.clientSettings?.customName) {\n            this._gameName = settings.settings.clientSettings.customName;\n        }\n\n        if (settings.settings.bellLinkBoost) {\n            this._blBoostJackpotSeedValues = settings.settings.bellLinkBoost;\n        }\n\n        if (settings.settings.gameSummary) {\n            this._gameSummary = settings.settings.gameSummary;\n        }\n    }\n\n    /* max win limit */\n    public get limit(): any {\n        return this._limit;\n    }\n\n    public get clientSettings(): any {\n        return this._clientSettings;\n    }\n\n    public get rtp(): any {\n        return this._rtp;\n    }\n\n    public get matchId(): string {\n        return this._matchId;\n    }\n\n    public get balance(): number {\n        return this._balance;\n    }\n\n    public get denomination(): number {\n        return this._denomination;\n    }\n\n    public get buyBonusDenominations(): null | number[] {\n        return this._buyBonusDenominations;\n    }\n\n    public get currency(): string {\n        return this._currency;\n    }\n\n    public get state(): string {\n        return this._state;\n    }\n\n    public get bet(): number {\n        return this._bet;\n    }\n\n    public get lastWinAmount(): any {\n        return Number(this.settings.game.result?.lastWinAmount) || 0;\n    }\n\n    public set gameMode(value: string) {\n        this._gameMode = value;\n    }\n\n    public get gameMode(): string {\n        return this._gameMode;\n    }\n\n    public get gameModes(): { gameMode: string; factor: number }[] {\n        return this._gameModes;\n    }\n\n    public set factor(value: number) {\n        this._factor = value;\n    }\n\n    public get factor(): number {\n        return this._factor;\n    }\n\n    public haveGameMode(gameMode: string): boolean {\n        return this._gameModes.find((el) => el.gameMode === gameMode) ? true : false;\n    }\n\n    // use this method only in case when have unique factor for game mode.\n    public getGameModeByUniqueFactor(factor: number): string {\n        let mode: string = 'NONE';\n        let moreThenOneModeFortFactor: boolean = false;\n        for (const gameMode of this._gameModes) {\n            if (gameMode.factor === factor) {\n                if (mode !== 'NONE') {\n                    moreThenOneModeFortFactor = true;\n                }\n                mode = gameMode.gameMode;\n            }\n        }\n        if (moreThenOneModeFortFactor) {\n            Log.error('HAVE MORE THEN ONE GAME MODE FOR FACTOR: ' + factor, this.constructor.name);\n        }\n        if (mode === 'NONE') {\n            Log.error('NO MODE FOUND FOR FACTOR: ' + factor, this.constructor.name);\n        }\n        return mode;\n    }\n\n    // use this method only in case when have unique gameMode.\n    public getFactorByUniqueGameMode(mode: string): number {\n        let factor: number = 0;\n        let moreThenOneGameModeWithThisName: boolean = false;\n        for (const gameMode of this._gameModes) {\n            if (gameMode.gameMode === mode) {\n                if (factor !== 0) {\n                    moreThenOneGameModeWithThisName = true;\n                }\n                factor = gameMode.factor;\n            }\n        }\n        if (moreThenOneGameModeWithThisName) {\n            Log.error('HAVE MORE THEN ONE GAME MODE WITH THIS NAME: ' + mode, this.constructor.name);\n        }\n        if (factor === 0) {\n            Log.error('NO GAME MODE FOUND: ' + mode, this.constructor.name);\n        }\n        return factor;\n    }\n\n    public getAllFactorsForGameMode(mode: string): number[] {\n        return this._gameModes.filter((m) => m.gameMode === mode).map((el) => el.factor);\n    }\n\n    public get factors(): number[] {\n        return this._factors;\n    }\n\n    public get buyBonusOptions(): number[] {\n        return this._buyBonusOptions;\n    }\n\n    public get denominations(): number[] {\n        if (this.maxBet) {\n            return this.filterDenominations();\n        } else {\n            return this._denominations;\n        }\n    }\n\n    public get paytable(): any {\n        return this._paytable;\n    }\n\n    public get reels(): number[][] {\n        return this._reels;\n    }\n\n    public set reels(reels: number[][]) {\n        this._reels = reels;\n    }\n\n    public get multipliers(): number[][] {\n        return this._multipliers;\n    }\n\n    public set multipliers(multipliers: number[][]) {\n        this._multipliers = multipliers;\n    }\n\n    public get multiplier(): number {\n        return this._multiplier;\n    }\n\n    public set multiplier(multiplier: number) {\n        this._multiplier = multiplier;\n    }\n\n    public get mutatedReels(): number[][] {\n        return this._mutatedReels;\n    }\n\n    public set mutatedReels(reels: number[][]) {\n        this._mutatedReels = reels;\n    }\n\n    public get bets(): number[] {\n        if (this.maxBet && this._denominations.length === 1 && !Core.isReplayer) {\n            return this.filterBets();\n        } else {\n            return this._bets;\n        }\n    }\n\n    public get allBets(): number[] {\n        return this._bets;\n    }\n\n    public get lines(): number {\n        return this._lines;\n    }\n\n    public get linesOptions(): number[] {\n        return this._linesOptions;\n    }\n\n    /** win amount in currency */\n    public get winAmount(): number {\n        return this._win;\n    }\n\n    public get entries(): any[] {\n        return this._entries;\n    }\n\n    public get units(): number {\n        return this._units;\n    }\n\n    public get freespin(): { count: number; type: string; spin: number; remain: number } {\n        return this._freespin;\n    }\n\n    public get lastBetWin(): number {\n        return this._lastBetWin;\n    }\n\n    public get restoringFromFreespin(): boolean {\n        return this._restoringFromFreespin;\n    }\n\n    // public get coinFeatureCoef(): number {\n    //     return this._coinFeatureCoef;\n    // }\n\n    public get demoWinsArray(): string[] {\n        return this._demoWins;\n    }\n\n    public get gambleMax(): number {\n        return this._gambleMax;\n    }\n\n    public get gambleMultiplier(): number {\n        return this._gambleMultiplier;\n    }\n\n    public get gambles(): number {\n        return this._gambles;\n    }\n\n    public get maxGambleAttempts(): number {\n        return this._maxGambleAttempts;\n    }\n\n    public get jackpotStats(): any {\n        return this._jackpotStats;\n    }\n\n    public get mutations(): any {\n        return this._mutations;\n    }\n\n    public get autoplayRestrictions(): any {\n        return this._autoplayRestrictions;\n    }\n\n    public get bellLink(): any {\n        return this._bellLink;\n    }\n\n    public get blJackpotRounds(): any {\n        return this._blJackpotRounds;\n    }\n\n    public get godsKingsLink(): any {\n        return this._godsKingsLink;\n    }\n\n    public get gaklJackpotRounds(): any {\n        return this._gaklJackpotRounds;\n    }\n\n    public get bellLinkBoost(): any {\n        return this._bellLinkBoost;\n    }\n\n    public get blBoostJackpotSeedValues(): {\n        bonusCoinFeature: number;\n        boostGrandValues: number;\n        boostMajorValues: number;\n        mini: number;\n        minor: number;\n    } {\n        return this._blBoostJackpotSeedValues;\n    }\n\n    public get blBoostJackpotRounds(): any {\n        return this._blBoostJackpotRounds;\n    }\n\n    public get bonusWins(): any {\n        return this._bonusWins;\n    }\n\n    public get bonus(): any {\n        return this._bonus;\n    }\n\n    public get scatterCoefs(): number[][] {\n        return this._scatterCoefs;\n    }\n\n    public get bonusSummary(): any {\n        return this._bonusSummary;\n    }\n\n    public set bonusSummary(summary: any) {\n        this._bonusSummary = summary;\n    }\n\n    public get country(): string {\n        return this._country;\n    }\n\n    public get enableVipUi(): boolean {\n        return this._enableVipUi;\n    }\n\n    public get maxBet(): number {\n        return this._maxBet;\n    }\n\n    public get minimumSpinTime(): number {\n        return this._minimumSpinTime;\n    }\n\n    public get autoplay(): boolean {\n        return this._autoplay;\n    }\n\n    public get gsFinalCollection(): any {\n        return this._gsFinalCollection;\n    }\n\n    public get gsHideInfo(): any {\n        return this._gsHideInfo;\n    }\n\n    public get cancelGSAvailable(): boolean {\n        return this._cancelGSAvailable;\n    }\n\n    public get gameVersion(): string {\n        return this._gameVersion;\n    }\n\n    public get numberOfLinesPerDenomination(): [number, number][] | undefined {\n        return this._numberOfLinesPerDenomination;\n    }\n\n    public get wilds(): any[] {\n        return this._wilds;\n    }\n\n    public get gameName(): string {\n        return this._gameName;\n    }\n\n    public get gameSummary(): any {\n        return this._gameSummary;\n    }\n\n    public get multipleLinesGameAvailableLines(): number[] {\n        return this._multipleLinesGameAvailableLines;\n    }\n\n    private filterBets(): number[] {\n        const baseGameFactor = this.factors[0];\n        return this._bets.filter((bet) => {\n            return (bet * this._denominations[0] * baseGameFactor) / this.units <= this.maxBet;\n        });\n    }\n\n    private filterDenominations() {\n        return this._denominations.filter((denom: number, index: number) => {\n            return this.maxBetCheck(\n                denom,\n                this._numberOfLinesPerDenomination ? this._numberOfLinesPerDenomination[index][1] : this.factor,\n            );\n        });\n    }\n\n    private maxBetCheck(denom: number, factor: number): unknown {\n        return this.bets.some((bet) => (bet * denom * factor) / this.units <= this.maxBet);\n    }\n}\n","export default class JackpotWin {\n    private _amount: number;\n    private _gameTriggered: boolean;\n    private _jackpotName: string;\n    private _levelId: number;\n    private _levelName: string;\n    private _mystery: boolean;\n    private _progressive: boolean;\n    private _progressiveBaseWin: number;\n    private _triggerRoundType: string;\n    private _win: number;\n    private _type: string;\n    private _winId: number;\n    constructor(response: any) {\n        this._amount = response.amount;\n        this._gameTriggered = response.gameTriggered;\n        this._jackpotName = response.jackpotName;\n        this._levelId = response.levelId;\n        this._levelName = response.levelName;\n        this._mystery = response.mystery;\n        this._progressive = response.progressive;\n        this._progressiveBaseWin = response.progressiveBaseWin;\n        this._triggerRoundType = response.triggerRoundType;\n        this._win = response.win;\n        this._winId = response.winId;\n    }\n    // win from jackpot in currency\n    public get amount(): number {\n        return this._amount;\n    }\n    public get jackpotName(): string {\n        return this._jackpotName;\n    }\n    public get levelName(): string {\n        return this._levelName;\n    }\n    public get levelId(): number {\n        return this._levelId;\n    }\n    // win from jackpot in credites\n    public get win(): number {\n        return this._win;\n    }\n    public get gameTriggered(): boolean {\n        return this._gameTriggered;\n    }\n    public get mystery(): boolean {\n        return this._mystery;\n    }\n    public get progressive(): boolean {\n        return this._progressive;\n    }\n    public get triggerRoundType(): string {\n        return this._triggerRoundType;\n    }\n    public get type(): string {\n        return this._type;\n    }\n    public get progressiveBaseWin(): number {\n        return this._progressiveBaseWin;\n    }\n    public get winId(): number {\n        return this._winId;\n    }\n}\n","const enum MessBarTypes {\n    NONE = 0,\n    INSUFFICIENT = 1,\n}\nexport default MessBarTypes;\n","import { BehaviorSubject } from 'rxjs';\n\nexport default class PausableSubject<T> extends BehaviorSubject<T> {\n    public prevValue: T;\n    public additionalData: any;\n    public isPaused: boolean = false;\n\n    constructor(val: T) {\n        super(val);\n    }\n\n    public next(val: T, paused?: boolean): void {\n        this.prevValue = val;\n        if (!this.isPaused) {\n            super.next(val);\n        }\n        if (paused) {\n            this.isPaused = paused;\n        }\n    }\n\n    public restore(): void {\n        this.isPaused = false;\n        super.next(this.prevValue);\n    }\n\n    public get prev(): T {\n        return this.prevValue;\n    }\n}\n","// import PriorityTypes from './PriorityTypes';\n\nexport default class PriorityList {\n    private priorities: string[];\n    private pointer: number;\n    private priorityType: string;\n\n    constructor(priorities: string[], type: string) {\n        // adding priorityType for better debugging\n        this.priorityType = type;\n        this.priorities = priorities;\n        this.pointer = -1;\n    }\n\n    // used from chain subject executorContinueTo in order to skip some features in list\n    // and continue to the exact feature as REEL_STOPPED.executorContinueTo(Features.MYSTERY_JACKPOT)\n    public setPriorityTo(priority: string): number {\n        this.pointer = this.priorities.indexOf(priority);\n        return this.pointer;\n    }\n\n    public nextPriority(): string {\n        this.pointer++;\n        // if (this.priorityType === PriorityTypes.REEL_STOPPED) {\n        //     console.log('*******', this.priorityType, ':', this.priorities[this.pointer]);\n        // }\n        // if (this.priorityType === PriorityTypes.RESTORE) {\n        //     console.log('*******', this.priorityType, ':', this.priorities[this.pointer]);\n        // }\n        return this.priorities[this.pointer];\n    }\n\n    public checkForResetPointer(): void {\n        if (this.priorities.length - 1 <= this.pointer) {\n            this.resetPointer();\n        }\n    }\n\n    public changePriorities(priorities: string[]): void {\n        this.priorities = priorities;\n        this.resetPointer();\n    }\n\n    public changeLastPriorities(lastPriority: string): void {\n        this.priorities[this.priorities.length - 1] = lastPriority;\n    }\n\n    public resetPointer(): void {\n        this.pointer = -1;\n    }\n\n    public destroy(): void {\n        this.priorities = [];\n        // @ts-ignore\n        this.priorities = null;\n        // @ts-ignore\n        this.pointer = null;\n    }\n}\n","const enum PriorityTypes {\n    REEL_STOPPED = 'REEL_STOPPED',\n    COLLECT_CLICKED = 'COLLECT_CLICKED',\n    RESTORE = 'RESTORE',\n    PROCESS_CURRENT_SPIN_RESULT = 'PROCESS_CURRENT_SPIN_RESULT',\n}\nexport default PriorityTypes;\n","import Line from '../lines/Line';\n\nexport default class RestoreResponse {\n    private _alreadyRestored = false;\n    private _entries: Line[];\n    private _reels: number[][];\n    private _horizontalReel: number[];\n    private _multipliers: number[][];\n    private _multiplier: number;\n    private _respin: { pos: number[]; val: number; wheelRetriggerShown: boolean };\n    private _mutations: Array<{ cells: []; reels: []; primes: []; type: string }>;\n    private _mutatedReels: number[][];\n    private _totalWin: number;\n    private _restorePoint: string;\n    private _bonuses: any[];\n    private _scatters: number[];\n    private _bonusWins: {\n        multipliers: number[];\n        totalBonusWin: number;\n        totalBonusWinAmount: number;\n        collectSymbol: any;\n        bonusMultiplier: number;\n    };\n    private _wilds: any[];\n\n    constructor(private response: any) {\n        const spin = response.spins[response.spins.length - 1];\n        this._entries = spin.entries.map((entry) => {\n            return new Line(\n                entry.symbol,\n                entry.cells,\n                entry.line,\n                entry.multiplier,\n                entry.occurs,\n                entry.win,\n                Number(entry.winAmount),\n                entry.mode,\n                entry.winsJackpot,\n                [],\n                '',\n                entry.ways,\n            );\n        });\n        this._multipliers = spin.multipliers;\n        this._multiplier = spin.multiplier;\n        this._reels = spin.reels;\n        this._mutatedReels = spin.mutatedReels;\n        this._mutations = spin.mutations;\n        this._horizontalReel = spin.horizontalReels ? spin.horizontalReels[0] : [];\n        this._totalWin = spin.totalWin;\n        this._restorePoint = response.restorePoint;\n        this._scatters = response.scatters;\n\n        if (spin) {\n            this._bonuses = spin.bonuses;\n        }\n        if (response.respin) {\n            this._respin = response.respin;\n        }\n        if (response.BonusWins) {\n            this._bonusWins = response.BonusWins;\n        }\n\n        this._wilds = response.wilds;\n    }\n\n    get entries(): Line[] {\n        return this._entries;\n    }\n\n    get reels(): number[][] {\n        return this._reels;\n    }\n\n    get horizontalReel(): number[] {\n        return this._horizontalReel;\n    }\n\n    get multipliers(): number[][] {\n        return this._multipliers;\n    }\n    get multiplier(): number {\n        return this._multiplier;\n    }\n\n    get respin(): { pos: number[]; val: number; wheelRetriggerShown: boolean } {\n        return this._respin;\n    }\n\n    get mutatedReels(): number[][] {\n        return this._mutatedReels;\n    }\n\n    get totalWin(): number {\n        return this._totalWin;\n    }\n\n    get restorePoint(): string {\n        return this._restorePoint;\n    }\n\n    get mutations(): Array<{ cells: []; reels: []; primes: []; type: string }> {\n        return this._mutations;\n    }\n\n    get bonuses(): any[] {\n        return this._bonuses;\n    }\n\n    set bonuses(value: any[]) {\n        this._bonuses = value;\n    }\n\n    get scatters(): number[] {\n        return this._scatters;\n    }\n\n    get alreadyRestored(): boolean {\n        return this._alreadyRestored;\n    }\n\n    set alreadyRestored(value: boolean) {\n        this._alreadyRestored = value;\n    }\n\n    get bonusWins(): any {\n        return this._bonusWins;\n    }\n\n    set bonusWins(value: any) {\n        this._bonusWins = value;\n    }\n\n    get result(): any {\n        return this.response;\n    }\n\n    get wilds(): any[] {\n        return this._wilds;\n    }\n}\n","const enum ServerState {\n    UNSET = 'unset',\n    WIN = 'win',\n    IDLE = 'idle',\n    GAMBLE = 'gamble',\n    FREESPIN = 'freespin',\n    FREESPIN_SCATTERS = 'freespinScatters',\n    FREESPIN_PICK = 'pickFreeGamesConfig',\n    RESPIN = 'respin',\n    FREERESPIN = 'freeRespin',\n    HOLDSPIN = 'holdspin',\n    PICK = 'pick',\n    CHOICE = 'choice',\n    SCATTERCHOICE = 'scatterChoice',\n    BONUS_IDLE = 'bonusIdle',\n    BONUS_SUMMARY = 'bonusSummary',\n    BONUS_CHANCE = 'bonusChance',\n    MYSTERY = 'mystery',\n    WHEEL_SPIN = 'wheelspin',\n    CREDIT_WHEEL = 'creditWheelSpin',\n    RESPIN_WHEEL = 'respinWheelSpin',\n    RESPIN_FROM_WHEEL = 'wheelRespin',\n    JACKPOT_PICK = 'jackpotPick',\n    HIGH_CASH_FREE_RESPIN = 'highCashFreeRespin',\n    MEGARESPIN = 'megaRespin',\n    MAIN_RESPIN = 'mainRespin',\n    PRIZE_POPS = 'prizePop',\n}\nexport default ServerState;\n","import Core from '@egt/core';\nimport { inject, injectable } from 'tsyringe';\nimport { ISlotConfiguration } from '../../slot-configuration/ISlotConfiguration';\nimport Line from '../lines/Line';\nimport RootStore from '../root/RootStore';\nimport { ISymbol } from '../symbols/ISymbol';\nimport BetResponse from './BetResponse';\n\n@injectable()\nexport default class SpinAnalyzer {\n    public defaultWinSound: string = '';\n    public anticipateScatterSymbol: any;\n    // set next variable \"playWinSounds\" to false when want to skip win\n    // sounds and play any special sound like coin animation sound\n    public playWinSounds: boolean = true;\n    protected fullLines: any[] = [];\n    protected scatterMap: Map<number, number> = new Map();\n    protected scattersCount: number = 0;\n\n    constructor(\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('RootStore') protected rootStore: RootStore,\n    ) {\n        [this.anticipateScatterSymbol] = this.slotConfiguration.scattersConfig.filter((scatter) => {\n            return scatter.anticipate === true;\n        });\n    }\n\n    public destroy(): void {\n        if (this.fullLines) {\n            this.fullLines.length = 0;\n            // @ts-ignore\n            this.fullLines = null;\n        }\n        if (this.scatterMap) {\n            this.scatterMap.clear();\n            // @ts-ignore\n            this.scatterMap = null;\n        }\n    }\n    public parseReel(reelIndex: number): number[] {\n        const parsedReel: number[] = this.rootStore.uiStore.REAL_REELS.value[reelIndex].slice();\n        parsedReel.shift();\n        parsedReel.pop();\n        return parsedReel;\n    }\n\n    public isSymbolOnReel(symbolIndex: number, reelIndex: number): boolean {\n        return this.parseReel(reelIndex).indexOf(symbolIndex) !== -1;\n    }\n\n    public isSymbolOnCell(symbolIndex: number, reelIndex: number, rowIndex: number): boolean {\n        return this.parseReel(reelIndex).indexOf(symbolIndex) === rowIndex;\n    }\n\n    public getSybmolFromIndex(index: number): ISymbol {\n        return this.slotConfiguration.symbols[index];\n    }\n\n    public getSymbolFromRowAndColValues(row: number, col: number) {\n        const response = this.rootStore.domainStore.betResponse;\n        const symbolIndex = response.reels[row][col + 1];\n        return this.slotConfiguration.symbols[symbolIndex];\n    }\n\n    public getScattersIndexes(): number[] {\n        return this.slotConfiguration.scattersConfig.map((scatter) => scatter.index);\n    }\n\n    public getSymbolCountOnReel(reel: any, index: number): number {\n        let symbolCountOnReel: number = 0;\n\n        for (let i = 0; i < reel.length; i++) {\n            if (reel[i] === index) {\n                symbolCountOnReel++;\n            }\n        }\n        return symbolCountOnReel;\n    }\n\n    public getScatterIndexOnReel(reelIndex: number): number {\n        let scatterIndex: number = -1;\n        const currentReel = this.parseReel(reelIndex);\n        this.slotConfiguration.scattersConfig.forEach((scatter) => {\n            if (currentReel.indexOf(scatter.index) !== -1) {\n                scatterIndex = scatter.index;\n            }\n        });\n        return scatterIndex;\n    }\n\n    // public getSymbolIndexOnReel(symbolIndex: number, reelIndex: number): number {\n    //     let index: number = -1;\n    //     const currentReel = this.parseReel(reelIndex);\n    //     if (currentReel.indexOf(symbolIndex) !== -1) {\n    //         index = currentReel.indexOf(symbolIndex);\n    //     }\n    //     return index;\n    // }\n\n    public getEnoughScatterIndexStopped(reels: number[]): number {\n        let scatterNum: number = 0;\n        for (const reel of reels) {\n            scatterNum += this.countFSScatterOnReel(reel);\n        }\n\n        return scatterNum;\n    }\n\n    public hasFSScatterOnReel(reelIndex: number): boolean {\n        return (\n            this.anticipateScatterSymbol && this.parseReel(reelIndex).indexOf(this.anticipateScatterSymbol.index) !== -1\n        );\n    }\n\n    public getWildIndex(): number {\n        let wildIndex: number = -1;\n        this.slotConfiguration.symbols.forEach((sym) => {\n            if (sym.isWild()) {\n                wildIndex = sym.index();\n            }\n        });\n        return wildIndex;\n    }\n\n    public getVerticalStackedSymbolIndex(): number {\n        let index: number = -1;\n        this.slotConfiguration.symbols.forEach((sym) => {\n            if (sym.isVerticalStackedSymbol()) {\n                index = sym.index();\n            }\n        });\n        return index;\n    }\n\n    public getVerticalStackedPositions(reels: number[][], entries: Line[]): number[][] {\n        const stackedPositions: number[][] = [];\n        const verticalStackedSymbolIndex = this.getVerticalStackedSymbolIndex();\n        reels.forEach((reel) => {\n            stackedPositions.push([]);\n            for (let i = 1; i < reel.length - 2; i++) {\n                if (\n                    reel[i] === reel[i + 1] &&\n                    reel[i] === verticalStackedSymbolIndex &&\n                    this.isPartOfLine(reels.indexOf(reel), i - 1, entries) &&\n                    this.isPartOfLine(reels.indexOf(reel), i, entries)\n                ) {\n                    stackedPositions[reels.indexOf(reel)].push(i);\n                }\n            }\n        });\n        return stackedPositions;\n    }\n\n    public isPartOfLine(row: number, col: number, entries: Line[]): boolean {\n        let partOfLine: boolean = false;\n        entries.forEach((entry: Line) => {\n            for (let i = 0; i < entry.cells.length; i += 2) {\n                const rowIndex: number = entry.cells[i];\n                const colIndex: number = entry.cells[i + 1];\n                if (rowIndex === row && colIndex === col) {\n                    partOfLine = true;\n                }\n            }\n        });\n        return partOfLine;\n    }\n\n    public countFSScatterOnReel(reelIndex: number): number {\n        const parsedReel = this.parseReel(reelIndex);\n        return this.getSymbolCountOnReel(parsedReel, this.anticipateScatterSymbol.index);\n    }\n\n    public getReplacedCells(betResponse: BetResponse): number[] {\n        const modifiedCells: number[] = [];\n\n        for (let k = 0; k < betResponse.mutations.length; k++) {\n            const primePositions: number[] = betResponse.mutations[k].primes;\n            const cells: number[] = betResponse.mutations[k].cells;\n\n            let isMember: boolean = false;\n            for (let i = 0; i < cells.length; i += 2) {\n                for (let j = 0; j < primePositions.length; j += 2) {\n                    if (cells[i] !== primePositions[j] || cells[i + 1] !== primePositions[j + 1]) {\n                        isMember = false;\n                    } else {\n                        isMember = true;\n                        break;\n                    }\n                }\n                if (!isMember) {\n                    modifiedCells.push(cells[i]);\n                    modifiedCells.push(cells[i + 1]);\n                } else {\n                    isMember = !isMember;\n                }\n            }\n        }\n        return modifiedCells;\n    }\n\n    public shouldAnticipateReel(scatterCount: number, reelIndex: number): boolean {\n        let shouldAnticipate: boolean = false;\n        if (scatterCount > 0) {\n            if (\n                scatterCount >=\n                    this.anticipateScatterSymbol.startFeatureMinCount - this.anticipateScatterSymbol.maxPerReel &&\n                this.anticipateScatterSymbol.startFeatureMinCount > 0 &&\n                this.anticipateScatterSymbol.validReels[reelIndex] === true\n            ) {\n                shouldAnticipate = true;\n            }\n        }\n\n        return shouldAnticipate;\n    }\n\n    public getReelStopDelay(scatterCount: number, reelIndex: number): number {\n        let delay: number = 0;\n        if (this.shouldAnticipateReel(scatterCount, reelIndex)) {\n            delay = this.rootStore.subjects.GAME_ANTICIPATION_REELS_DELAY.value;\n        } else if (reelIndex !== 0) {\n            delay =\n                this.rootStore.uiStore.quickSpinEnabled &&\n                !this.rootStore.uiStore.disableSpecialSpinSpeedForCurrentState\n                    ? this.rootStore.subjects.GAME_BETWEEN_REELS_DELAY_IN_QUICK_SPIN.value\n                    : this.rootStore.subjects.GAME_BETWEEN_REELS_DELAY.value;\n        } else {\n            delay = 1;\n        }\n        return delay;\n    }\n\n    public getFSScatterValidReels(reelIndex: number): number {\n        let availableValidReels: number = 0;\n        for (let i = reelIndex + 1; i < this.anticipateScatterSymbol.validReels.length; i++) {\n            if (this.anticipateScatterSymbol.validReels[i] === true) {\n                availableValidReels += 1;\n            }\n        }\n\n        return availableValidReels;\n    }\n\n    public shouldPlayWildStopSound(reelIndex: number): boolean {\n        let shouldPlay = false;\n        if (this.getWildIndex() !== -1) {\n            if (\n                this.isSymbolOnReel(this.getWildIndex(), reelIndex) &&\n                this.getSybmolFromIndex(this.getWildIndex()).stopWildSound()\n            ) {\n                shouldPlay = true;\n            }\n        }\n\n        return shouldPlay;\n    }\n\n    public getReelStopSound(scatterCount: number, reelIndex: number): string {\n        let stopSound: string = '';\n        if (this.hasFSScatterOnReel(reelIndex) && scatterCount > 0) {\n            if (this.anticipateScatterSymbol.validReels[reelIndex] === false) {\n                stopSound = this.checkForDefaultSound(reelIndex);\n            } else {\n                if (\n                    this.anticipateScatterSymbol.maxPerReel > 1 &&\n                    scatterCount + this.getFSScatterValidReels(reelIndex) * this.anticipateScatterSymbol.maxPerReel >=\n                        this.anticipateScatterSymbol.startFeatureMinCount &&\n                    this.hasFSScatterOnReel(reelIndex)\n                ) {\n                    stopSound = this.anticipateScatterSymbol.stopSounds[reelIndex];\n                } else if (\n                    reelIndex === this.rootStore.subjects.NUMBER_OF_REELS.value &&\n                    scatterCount + this.countFSScatterOnReel(reelIndex) >=\n                        this.anticipateScatterSymbol.startFeatureMinCount\n                ) {\n                    stopSound = this.anticipateScatterSymbol.stopSounds[reelIndex];\n                } else {\n                    stopSound = this.checkForDefaultSound(reelIndex);\n                }\n            }\n        } else {\n            stopSound = this.checkForDefaultSound(reelIndex);\n        }\n        return stopSound;\n    }\n\n    public getScatterStopSoundPerCount(scatterCount: number, reelIndex: number): string {\n        let stopSound: string = '';\n        if (this.hasFSScatterOnReel(reelIndex) && scatterCount > 0) {\n            if (this.anticipateScatterSymbol.validReels[reelIndex] === false) {\n                stopSound = this.checkForStopScatterSound(reelIndex, scatterCount);\n            } else {\n                if (\n                    this.anticipateScatterSymbol.maxPerReel > 1 &&\n                    scatterCount + this.getFSScatterValidReels(reelIndex) * this.anticipateScatterSymbol.maxPerReel >=\n                        this.anticipateScatterSymbol.startFeatureMinCount &&\n                    this.hasFSScatterOnReel(reelIndex)\n                ) {\n                    stopSound = this.anticipateScatterSymbol.stopSounds[reelIndex];\n                } else if (\n                    reelIndex === this.rootStore.subjects.NUMBER_OF_REELS.value &&\n                    scatterCount + this.countFSScatterOnReel(reelIndex) >=\n                        this.anticipateScatterSymbol.startFeatureMinCount\n                ) {\n                    stopSound = this.anticipateScatterSymbol.stopSounds[reelIndex];\n                } else {\n                    stopSound = this.checkForStopScatterSound(reelIndex, scatterCount);\n                }\n            }\n        } else {\n            stopSound = this.checkForStopScatterSound(reelIndex, scatterCount);\n        }\n\n        return stopSound;\n    }\n\n    public getHighestPayingSymbolSound(data: any[]): string {\n        if (!this.playWinSounds) {\n            this.playWinSounds = true;\n            this.fullLines = [];\n            return '';\n        }\n        this.fullLines = [];\n\n        let highestPayingSymbolSound: string = '';\n        this.slotConfiguration.symbolsConfig.forEach((config: any) => {\n            if (config.index === this.getHighestPayingWinLine(data).symbol) {\n                if (\n                    this.getHighestPayingWinLine(data).occurs < this.rootStore.subjects.NUMBER_OF_REELS.value ||\n                    config.isScatter ||\n                    (this.anticipateScatterSymbol &&\n                        this.getHighestPayingWinLine(data).symbol === this.anticipateScatterSymbol.index)\n                ) {\n                    if (config.hasSecondVideo && !this.shouldPlaySecondVideo(config.index)) {\n                        highestPayingSymbolSound = config.winSound2;\n                    } else if (config.winSound) {\n                        highestPayingSymbolSound = config.winSound;\n                    } else {\n                        highestPayingSymbolSound =\n                            this.inFreeSpins() && Core.sounds.hasSound('fsCreditAnimationSound')\n                                ? 'fsCreditAnimationSound'\n                                : 'creditAnimationSound';\n                    }\n                } else {\n                    highestPayingSymbolSound = config.fullLineSound;\n                }\n            }\n        });\n        this.fullLines = [];\n        return highestPayingSymbolSound;\n    }\n\n    public getHighestPayingWinLine(entries: any[]): Line {\n        const fsWonLine = this.checkFreeSpinWin(entries);\n        if (fsWonLine) {\n            return fsWonLine;\n        }\n\n        if (this.fullLines.length === 0) {\n            entries.forEach((entry) => {\n                if (entry.occurs === this.rootStore.subjects.NUMBER_OF_REELS.value) {\n                    this.fullLines.push(entry);\n                }\n            });\n        }\n\n        if (this.fullLines.length !== 0) {\n            return this.fullLines.reduce((line1, line2) => (line1.symbol > line2.symbol ? line1 : line2));\n        } else {\n            return entries.reduce((line1, line2) => (line1.symbol > line2.symbol ? line1 : line2));\n        }\n    }\n\n    public hasFullLineWin(): boolean {\n        return this.fullLines.length > 0;\n    }\n\n    public emptyFullLinesArray(): void {\n        this.fullLines.length = 0;\n    }\n\n    public shouldPlaySecondVideo(scatterIndex: number): boolean {\n        let fsMinCount: number = 0;\n        for (const scatter of this.slotConfiguration.scattersConfig) {\n            if (scatter.index === scatterIndex) {\n                fsMinCount = scatter.fsMinCount;\n            }\n        }\n        if (this.getEnoughScatterIndexStopped(this.getReelsNumberArray()) >= fsMinCount) {\n            return false;\n        } else {\n            return true;\n        }\n    }\n\n    public getReelsNumberArray(): number[] {\n        const reels: number[] = [];\n        for (let i: number = 0; i < this.rootStore.subjects.NUMBER_OF_REELS.value; i++) {\n            reels.push(i);\n        }\n        return reels;\n    }\n\n    /** Check if there are any scatters and expanding wild on the same reel, and the wild is going to expand over the scatter */\n    public hasScatterAndExpandingWildOnSameReel(betResponse: BetResponse): boolean {\n        const wildIndex = this.getWildIndex();\n\n        for (let i = 0; i < this.rootStore.subjects.NUMBER_OF_REELS.value; i++) {\n            const parsedReel = this.parseReel(i);\n            const scatterIndeces = this.slotConfiguration.scattersConfig.map((scatter: any) => scatter.index);\n\n            if (!parsedReel.includes(wildIndex)) {\n                continue;\n            } else {\n                // search for scatter symbol on the reel\n                const foundIndex = parsedReel.findIndex((symbolIndex: number) => scatterIndeces.includes(symbolIndex));\n\n                if (foundIndex !== -1) {\n                    const foundScatterIndex = parsedReel[foundIndex];\n                    const foundScatterConfig = this.slotConfiguration.scattersConfig.find(\n                        (scatterConfig: any) => scatterConfig.index === foundScatterIndex,\n                    );\n\n                    // check for scatter validity on the reel\n                    if (foundScatterConfig.validReels[i]) {\n                        // check for mutation replacement on that specific reel\n                        const allMutations = betResponse.result.spins[1].mutations.reduce(\n                            (prev, curr) => [...prev, ...curr.cells],\n                            [],\n                        );\n                        const mutatedCells = allMutations.reduce((prev, curr, _idx) => {\n                            if (prev.length && prev[prev.length - 1].length === 1) {\n                                prev[prev.length - 1].push(curr);\n                            } else {\n                                prev.push([curr]);\n                            }\n\n                            return prev;\n                        }, []);\n\n                        if (mutatedCells.find(([reel, cell]: number[]) => reel === i && cell === foundIndex)) {\n                            return true;\n                        }\n                    }\n                }\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Checks if the current round is in FreeSpins\n     * @returns boolean\n     */\n    public inFreeSpins(): boolean {\n        const freespinRound = this.rootStore.domainStore.betResponse?.rounds?.filter(\n            (round) => round.type === 'FREESPIN',\n        )[0];\n        return freespinRound?.remain >= 0 && freespinRound.count !== freespinRound.remain;\n    }\n    public inSuperFreeSpins(): boolean {\n        return (\n            this.rootStore.settings.haveGameMode(this.slotConfiguration.superBuyBonusGameMode) &&\n            this.rootStore.domainStore.betResponse.gameState.bet.factor ===\n                this.rootStore.settings.getFactorByUniqueGameMode(this.slotConfiguration.superBuyBonusGameMode)\n        );\n    }\n\n    protected isScatterWithinRange(reels: boolean[], startReelIndex: number, endReelIndex: number): boolean {\n        return reels.every((val, i) => !val || (i >= startReelIndex && i <= endReelIndex));\n    }\n\n    protected checkForDefaultSound(reelIndex: number): string {\n        if (reelIndex === 0) {\n            this.scattersCount = 0;\n        }\n        let stopSound =\n            this.rootStore.uiStore.quickSpinEnabled && !this.rootStore.uiStore.disableSpecialSpinSpeedForCurrentState\n                ? 'quickReelsStop'\n                : 'stopReelSound';\n        // const scatterIndexOnReel = this.getScatterIndexOnReel(reelIndex);\n        const scatterIndexOnReel = this.getScatterIndexOnReel(reelIndex);\n        if (scatterIndexOnReel !== -1) {\n            if (!this.scatterMap.has(scatterIndexOnReel)) {\n                this.scatterMap.set(scatterIndexOnReel, 0);\n            }\n            this.slotConfiguration.scattersConfig.forEach((scatter, index) => {\n                if (\n                    scatter.index === scatterIndexOnReel &&\n                    // !scatter.fsMinCount &&\n                    this.scatterWinIsPossible(reelIndex, scatterIndexOnReel, index)\n                ) {\n                    this.scatterMap.set(scatterIndexOnReel, this.scatterMap.get(scatterIndexOnReel)! + 1);\n                    // only for 6 reel games and scatter between 2d and 5th reel\n                    if (\n                        this.isScatterWithinRange(scatter.validReels, 1, 4) &&\n                        this.rootStore.subjects.NUMBER_OF_REELS.value === 6\n                    ) {\n                        this.scattersCount++;\n                        stopSound = scatter.stopSounds[this.scattersCount];\n                    } else {\n                        stopSound = scatter.stopSounds[reelIndex];\n                    }\n                }\n            });\n        }\n        if (reelIndex === this.rootStore.subjects.NUMBER_OF_REELS.value - 1) {\n            this.scatterMap.clear();\n        }\n        return stopSound;\n    }\n\n    protected checkForStopScatterSound(reelIndex: number, scatterCount: number): string {\n        let stopSound =\n            this.rootStore.uiStore.quickSpinEnabled && !this.rootStore.uiStore.disableSpecialSpinSpeedForCurrentState\n                ? 'quickReelsStop'\n                : 'stopReelSound';\n        const scatterIndexOnReel = this.getScatterIndexOnReel(reelIndex);\n\n        if (scatterIndexOnReel !== -1) {\n            if (!this.scatterMap.has(scatterIndexOnReel)) {\n                this.scatterMap.set(scatterIndexOnReel, 0);\n            }\n\n            this.slotConfiguration.scattersConfig.forEach((scatter, index) => {\n                if (\n                    scatter.index === scatterIndexOnReel &&\n                    this.scatterWinIsPossible(reelIndex, scatterIndexOnReel, index)\n                ) {\n                    this.scatterMap.set(scatterIndexOnReel, this.scatterMap.get(scatterIndexOnReel)! + 1);\n                    stopSound = scatter.stopSounds[scatterCount - 1];\n                }\n            });\n        }\n\n        if (reelIndex === this.rootStore.subjects.NUMBER_OF_REELS.value - 1) {\n            this.scatterMap.clear();\n        }\n\n        return stopSound;\n    }\n\n    protected scatterWinIsPossible(reelIndex, scatterIndex, scatterConfigIndex): boolean {\n        let possibleScatters: number = 0;\n\n        for (let i: number = 0; i < this.rootStore.subjects.NUMBER_OF_REELS.value - reelIndex; i++) {\n            if (this.slotConfiguration.scattersConfig[scatterConfigIndex].validReels[reelIndex + i]) {\n                possibleScatters++;\n            }\n        }\n\n        if (\n            this.scatterMap!.get(scatterIndex)! + possibleScatters <\n            this.slotConfiguration.scattersConfig[scatterConfigIndex].minCount\n        ) {\n            return false;\n        } else {\n            return true;\n        }\n    }\n\n    protected checkFreeSpinWin(entries: any[]): Line | undefined {\n        for (const entrie of entries) {\n            for (const scater of this.slotConfiguration.scattersConfig) {\n                if (entrie.symbol === scater.index && scater.fsMinCount && scater.fsMinCount <= entrie.occurs) {\n                    return entrie;\n                }\n            }\n        }\n        return undefined;\n    }\n}\n","import { BehaviorSubject } from 'rxjs';\nimport Features from '../feature/Features';\n\nexport default class StateSubject<T> extends BehaviorSubject<T> {\n    public prevValue: T;\n\n    public next(val: T): void {\n        if (\n            (this.value as any) === Features.AUTO_PLAY ||\n            (this.value as any) === Features.MANUAL_SPIN ||\n            (this.value as any) === Features.FREE_SPINS\n        ) {\n            this.prevValue = this.value;\n        }\n        super.next(val);\n    }\n\n    public restore(): void {\n        super.next(this.prevValue);\n    }\n\n    public get prev(): T {\n        return this.prevValue;\n    }\n}\n","import { BackgroundMusic } from '@egt/background-sound';\nimport { SPINES } from '@egt/character-animations';\nimport { ContainerReel } from '@egt/container-reels';\nimport { DynamicPositionObject, IVideoPositionPoint, VideoTypes } from '@egt/core';\nimport { ILinesConfig } from '@egt/lines';\nimport { IChangeBackgroundMusicLayerCommand } from '@egt/multilayered-bg-sound';\nimport { NonProportionalReel } from '@egt/non-proportional-reels';\nimport { IReelPositionDefault, ReelDefault, ReelDesktopForLandscape } from '@egt/reels';\nimport { ICellPosition, IUniversalReelPosition } from '@egt/slot-components/universal-reels';\nimport { DisplayObject, ITextStyle } from 'pixi.js';\nimport { BehaviorSubject, ReplaySubject, Subject } from 'rxjs';\nimport UniversalReel from 'slot-components/universal-reels/src/egt/views/UniversalReel';\nimport { injectable } from 'tsyringe';\nimport RootElementsAnimationTypes from '../enums/RootElementsAnimationTypes';\nimport SlotComponents from '../enums/SlotComponents';\nimport Features from '../feature/Features';\nimport BetResponse from './BetResponse';\nimport ChainSubject from './ChainSubject';\nimport CustomBehaviorSubject from './CustomBehaviorSubject';\nimport MessBarTypes from './MessBarTypes';\nimport RestoreResponse from './RestoreResponse';\n\n@injectable()\nexport default class Subjects {\n    // General\n    public readonly MODAL_PRESSED = new Subject();\n    public readonly SETTINGS_BET_CHANGED = new Subject();\n    public readonly SEND_DEMO_CHOICE = new Subject();\n    public readonly START_MANUAL_SPIN = new Subject();\n    public readonly SETTINGS_DENOMINATION_CHANGED = new Subject();\n\n    public readonly KEY_UP: BehaviorSubject<any> = new BehaviorSubject<any>(null);\n    public readonly KEY_DOWN: BehaviorSubject<any> = new BehaviorSubject<any>(null);\n    public readonly RESET_KEY_EVENTS = new Subject();\n\n    /////////////////////////////////////////////////////////////\n\n    public readonly MAX_WIN_LIMIT_HIT: BehaviorSubject<boolean> = new BehaviorSubject(false);\n    public readonly MAX_WIN_LIMIT_MESSAGE: BehaviorSubject<boolean | string> = new BehaviorSubject(false);\n    public readonly REPOSITION_MSG_BAR_ALERT: BehaviorSubject<{ x?: number; y?: number } | undefined> =\n        new BehaviorSubject(undefined);\n\n    /////////////////////////////////////////////////////////////\n\n    public readonly PULSATE_SPIN_BTN: BehaviorSubject<boolean> = new BehaviorSubject(false);\n    public readonly STOP_PULSATE_SPIN_BTN = new Subject();\n    // public readonly SPECIAL_ANIMATION_ON_SCREEN: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n\n    public readonly REELS_START = new Subject();\n    public readonly REELS_STOPPED = new ChainSubject();\n    public readonly REELS_STOP_ALL = new Subject();\n    public readonly REEL_BOUNCED = new Subject<\n        ReelDefault | NonProportionalReel | ContainerReel | UniversalReel | ReelDesktopForLandscape\n    >();\n    public readonly REEL_STOPPED = new Subject<\n        ReelDefault | NonProportionalReel | ContainerReel | UniversalReel | ReelDesktopForLandscape\n    >();\n    public readonly REEL_ACCELERATE = new Subject<\n        ReelDefault | NonProportionalReel | ContainerReel | UniversalReel | ReelDesktopForLandscape\n    >();\n    public readonly REEL_ACCELERATE_DISBALED = new BehaviorSubject<boolean>(false);\n    public readonly HIDE_REELS = new BehaviorSubject(false);\n    public readonly BEFORE_SPIN = new Subject();\n    public readonly SHOW_DIRECT_MESSAGEBAR_TEXT: BehaviorSubject<boolean | [MessBarTypes, string]> =\n        new BehaviorSubject(false);\n    public readonly SPIN_STARTED = new Subject();\n    public readonly SPIN_STARTED_WITHOUT_NEW_REQUEST = new Subject();\n    public readonly TINT_REELS = new Subject();\n    public readonly TINT_CELL: BehaviorSubject<number[]> = new BehaviorSubject([]);\n    public readonly UNTINT_CELL: BehaviorSubject<number[]> = new BehaviorSubject([]);\n    public readonly SPIN_SPEED: BehaviorSubject<number> = new BehaviorSubject(0);\n    public readonly SPIN_SPEED_EXTERNAL = new Subject();\n\n    public readonly RESET_BELL_LINK_REELS = new Subject();\n    public readonly BELL_LINK_REELS_REMOVE_ELEMENTS = new Subject();\n    public readonly RESET_REELS = new Subject();\n    public readonly REELS_REMOVE_ELEMENTS = new Subject();\n\n    public readonly REDRAW_REELS = new Subject();\n\n    public readonly MODIFY_CONTAINER_REELS: BehaviorSubject<\n        { reels: number[][]; modifyLastGuard: boolean } | undefined\n    > = new BehaviorSubject(undefined);\n    public readonly RESTORE_CONTAINER_REELS: BehaviorSubject<number[][]> = new BehaviorSubject([[]]);\n    public readonly SERVER_REELS: BehaviorSubject<number[][]> = new BehaviorSubject([[]]);\n    public readonly ARE_REELS_ROTATING: BehaviorSubject<boolean> = new BehaviorSubject(false);\n\n    // cascade reels and games with multiple results in spin object\n    public readonly PROCESS_CURRENT_SPIN_RESULT = new ChainSubject();\n    public readonly WIN_VISUALISATION_FINISHED = new Subject();\n    public readonly PREPARE_NEXT_SPIN_RESULT: BehaviorSubject<boolean> = new BehaviorSubject(false);\n\n    public readonly REPLACE_REELS_SYMBOLS_TO_SPECIAL_SYMBOLS = new Subject();\n\n    // cascade subjects extracted here, because of the max win modul\n    public readonly UN_TINT_ALL_CASCADE_REELS_ON_NEXT_SPIN = new Subject();\n    public readonly REPLACE_CASCADE_REELS = new Subject<any[]>();\n    public readonly REPLACE_CASCADE_REEL_CELL = new Subject<any>();\n    public readonly TINT_CASCADE_REELS = new Subject<any[]>();\n    public readonly UN_TINT_CASCADE_REELS = new Subject<any[]>();\n    public readonly UN_TINT_ALL_CASCADE_REELS = new Subject();\n    public MULTIPLIERS_IDS: BehaviorSubject<number[]> = new BehaviorSubject([10]);\n\n    // Popups\n    public readonly TAB_OPENED: BehaviorSubject<boolean> = new BehaviorSubject(false);\n    public readonly DISABLE_MENU_BUTTONS: BehaviorSubject<boolean> = new BehaviorSubject(false);\n    public readonly OPEN_SETTINGS_POPUP = new Subject();\n    public readonly CLOSE_SETTINGS_POPUP = new Subject();\n    public readonly SETTINGS_POPUP_CLOSED = new Subject();\n    public readonly SETTINGS_POPUP_OPENED = new Subject();\n    public readonly TOGGLE_AUTOPLAY_POPUP = new Subject();\n    public readonly CLOSE_AUTOPLAY_POPUP = new Subject();\n    public readonly CLOSE_ALL_POPUPS = new Subject();\n    public readonly TOGGLE_DENOMINATION_POPUP = new Subject();\n    public readonly CLOSE_DENOMINATION_POPUP = new Subject();\n    public readonly TOGGLE_BET_SETTINGS_POPUP = new Subject();\n    public readonly CLOSE_BET_SETTINGS_POPUP = new Subject();\n    public readonly OPEN_HELP_POPUP: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly OPEN_INFO_POPUP: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n\n    public readonly FEATURE_MODIFY_PAYTABLE: BehaviorSubject<string> = new BehaviorSubject<string>('');\n    public readonly FEATURE_MODIFIED_PAYTABLE: BehaviorSubject<string> = new BehaviorSubject<string>('');\n    public readonly EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(\n        false,\n    );\n    public readonly EXTENDED_MULTIPLE_BUY_BONUS_BTN_VISIBLE: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(\n        true,\n    );\n    public readonly EXTENDED_MULTIPLE_BUY_BONUS_OUTSIDE_BETS_VISIBLE: BehaviorSubject<boolean> =\n        new BehaviorSubject<boolean>(false);\n\n    public readonly EXTENDED_MULTIPLE_BUY_BONUS_BTN_CLICKED = new Subject();\n    public readonly EXTENDED_DENOMINATION_POP_UP_TITLE: BehaviorSubject<string> = new BehaviorSubject<string>(\n        'BET LEVELS',\n    );\n    public readonly SPIN_BUTTON_SPECIAL_TEXT_VISIBLE = new Subject<boolean>();\n    public readonly BET_SETTINGS_TITLE: BehaviorSubject<string> = new BehaviorSubject<string>('BET');\n\n    public readonly INCREASE_MULTIPLIERS_AFTER_CASCADE: BehaviorSubject<boolean> = new BehaviorSubject(false);\n    public readonly DISABLE_CAMPAIGN_WIDGET: BehaviorSubject<boolean> = new BehaviorSubject(false);\n    // Pin the campaign widget to a single container by name; '' resumes auto-cycling\n    public readonly PIN_CAMPAIGN_CONTAINER: BehaviorSubject<string> = new BehaviorSubject<string>('');\n\n    // public readonly POPUP_ANIM_IN_PROGRESS: BehaviorSubject<boolean> = new BehaviorSubject(false);\n\n    // public readonly COIN_FEAT_ANIM_IN_PROGRESS: BehaviorSubject<boolean> = new BehaviorSubject(false);\n\n    // Stats view\n    public readonly DISABLE_JACKPOT_STATS: BehaviorSubject<boolean> = new BehaviorSubject(false);\n    public readonly JACKPOT_STATS_POINTER: BehaviorSubject<boolean> = new BehaviorSubject(true);\n    public readonly SHOW_JP_STATS: BehaviorSubject<{ type: number; id: string }> = new BehaviorSubject({\n        type: -1,\n        id: '',\n    });\n    public readonly JP_STATS_SEEN: BehaviorSubject<boolean> = new BehaviorSubject(false);\n    public readonly REGISTER_ROOT_ELEMENTS_FOR_ANIMATION = new Subject<DisplayObject>();\n    public readonly ROOT_ELEMENT_ANIMATE = new Subject<RootElementsAnimationTypes>();\n\n    // reels\n\n    // Freespin\n    // public readonly START_FREESPIN = new Subject();\n    // public readonly ENTER_FREESPIN = new Subject();\n    // public readonly EXIT_FREESPIN = new Subject();\n    // public readonly FREESPIN_STARTED = new Subject();\n    // public readonly FREESPIN_STOPPED = new Subject();\n    // public readonly FREESPIN_CLEAR = new Subject();\n    // public readonly PAUSE_FREESPIN = new Subject();\n    // public readonly RESUME_FREESPIN = new Subject();\n    // public readonly RETRIGGER_FREESPIN = new Subject();\n    // public readonly RESTORE_FROM_FREESPIN = new Subject();\n    public readonly SECONDARY_BAR_VISIBLE = new BehaviorSubject<boolean>(false);\n    // public readonly FREESPIN_START_CLICKED = new Subject();\n    // public readonly FREESPIN_INTRO_VISIBLE = new Subject();\n    // public readonly FREESPIN_INTRO_FINISHED = new Subject();\n    // public readonly FREESPIN_OUTRO_VISIBLE = new Subject();\n    // public readonly FREESPIN_OUTRO_FINISHED = new Subject();\n    // public readonly FREESPIN_RETRIGER_VISIBLE = new Subject();\n    // public readonly FREESPIN_RETRIGER_FINISHED = new Subject();\n\n    // Autoplay\n    public readonly START_AUTOPLAY = new Subject();\n    public readonly STOP_AUTOPLAY = new Subject();\n    public readonly RESET_AUTOPLAY_RESTRICTIONS = new Subject();\n\n    // change bet buttons opacity\n    public readonly SET_BET_BUTTONS_OPACITY: BehaviorSubject<number> = new BehaviorSubject(1);\n\n    // Can change Z-Order of every view nested in RoorView\n    public readonly CHANGE_Z_ORDER: BehaviorSubject<{ name: string; order: number }[]> = new BehaviorSubject([\n        {\n            name: '',\n            order: 1,\n        },\n    ]);\n\n    // Can show or hide every view nested in RoorView\n    public readonly SHOW_HIDE_VIEW: BehaviorSubject<{ name: string; display: boolean }> = new BehaviorSubject({\n        name: '',\n        display: false,\n    });\n\n    // Can show or hide every view nested in RoorView\n    public readonly SHOW_HIDE_MAIN_VIEW_COMPONENTS: BehaviorSubject<{\n        name: string;\n        actions: string[] | string;\n        values: boolean[] | boolean;\n    }> = new BehaviorSubject({\n        name: '',\n        actions: 'display',\n        values: false,\n    });\n\n    // Can show or hide every element by name. The 1st param is used mostly as filter which subscription to be executed\n    // SHOW_HIDE_ANY_VIEW_COMPONENTS.pipe(filter((f) => f.feature === Features.MYSTERY_JACKPOT),takeUntil(this.DESTROY)).subscribe\n    public readonly SHOW_HIDE_ANY_VIEW_COMPONENTS: Subject<{\n        feature: Features | SlotComponents;\n        elementName: string;\n        display: boolean;\n    }> = new Subject<{ feature: Features | SlotComponents; elementName: string; display: boolean }>();\n\n    // Can show,hide,enable,disable components in UIView\n    public readonly PROCCESS_UI_VIEW_COMPONENTS: BehaviorSubject<{\n        name: string;\n        actions: string[] | string;\n        values: boolean[] | boolean;\n        update?: boolean;\n    }> = new BehaviorSubject({\n        name: '',\n        actions: 'display',\n        values: false,\n    });\n\n    // Retrieve the value of custom property\n    public readonly GET_UI_VIEW_COMPONENT_STATE: BehaviorSubject<{\n        name: string;\n        property?: string;\n        value?: boolean;\n    }> = new BehaviorSubject({\n        name: '',\n    });\n\n    // Fast play\n    public readonly STOP_FAST_PLAY = new Subject();\n\n    // Wild expand\n    public readonly WILD_EXPAND = new Subject();\n    public readonly WILD_EXPAND_END = new Subject();\n    public readonly STOP_WILD_VIDEO: BehaviorSubject<boolean> = new BehaviorSubject(false);\n\n    public CLEAR_CELLS = new Subject();\n    public CLEAR_CELLS_LAYERS = new Subject();\n    public SHOW_CELLS = new Subject();\n\n    public readonly REPLAYER_BUTTON_HIT: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly FEATURE_STARTED = new Subject<Features>();\n    public readonly FEATURE_FINISHED = new Subject<Features>();\n    public readonly FEATURE_COMPLETE = new Subject<Features>();\n    public readonly ACTIVE_FEATURE = new BehaviorSubject<Features[]>([]);\n    public readonly BACKGROUND_SOUND_DURING_BIG_WIN = new Subject();\n    public readonly BIG_WIN_IS_ACTIVE: BehaviorSubject<boolean> = new BehaviorSubject(false);\n    public readonly RESTORE_BET = new Subject();\n    public readonly RESTORE = new ChainSubject();\n\n    public readonly ACTIVE_COMPONENT = new BehaviorSubject<SlotComponents[]>([]);\n\n    public readonly MODAL_LAYER_ENABLED: BehaviorSubject<boolean> = new BehaviorSubject(true);\n\n    public readonly HIDE_MESSAGE_BAR: BehaviorSubject<boolean> = new BehaviorSubject(false);\n    public readonly HIDE_SPECIAL_BAR: BehaviorSubject<boolean> = new BehaviorSubject(false);\n    public readonly RESTORE_MESSAGE_BAR_SETTINGS = new Subject();\n    public readonly MESSAGE_BAR_PLAY_NEXT_MESSAGE = new Subject();\n    public readonly FORCE_DESTROY_MESSAGE_BAR = new Subject();\n\n    public readonly GAME_LOGO_VISIBLE: BehaviorSubject<boolean> = new BehaviorSubject(true);\n\n    public readonly TOGGLE_QUICK_SPIN: CustomBehaviorSubject<boolean> = new CustomBehaviorSubject(false);\n    public readonly TOGGLE_TURBO_SPIN: CustomBehaviorSubject<boolean> = new CustomBehaviorSubject(false);\n\n    // use this event only when want to start coin feature until other is in action\n    public readonly START_COIN_FEATURE_FROM_OTHER_FEATURE: BehaviorSubject<boolean> = new BehaviorSubject(false);\n    // use this event only when some feature wants to stop coin feature immediately\n    public readonly STOP_COIN_FEATURE_FROM_OTHER_FEATURE = new Subject();\n\n    public readonly FACTOR_CHANGED = new Subject();\n    public readonly DENOMINATIONS_CHANGED = new Subject();\n    public readonly DISABLED_DOUBLE_CHANCE: BehaviorSubject<boolean> = new BehaviorSubject(false);\n    public readonly DOUBLE_CHANCE_ACTIVATED: BehaviorSubject<boolean> = new BehaviorSubject(false);\n    public readonly CLOSE_BUY_BONUS_POPUP = new Subject();\n    public readonly BUY_BONUS_POPUP_OPENED: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly DISABLED_BUY_BONUS: BehaviorSubject<{ disabled: boolean; doNotChangeVisual: boolean }> =\n        new BehaviorSubject({ disabled: false, doNotChangeVisual: false });\n\n    public readonly GAMBLE_OPENED: BehaviorSubject<boolean> = new BehaviorSubject(false);\n\n    public readonly VIDEOS_PLAYING: BehaviorSubject<boolean> = new BehaviorSubject(false);\n    public readonly HIDE_VIDEO_SYMBOLS_ON_TOP = new Subject();\n    public readonly DESTROY_CUSTOM_VIDEO = new Subject();\n    public readonly PLAY_CUSTOM_VIDEO: BehaviorSubject<{\n        symbol: number;\n        pos: DynamicPositionObject<IVideoPositionPoint> | undefined;\n        // biome-ignore lint/complexity/noBannedTypes: <explanation>\n        handler?: Function;\n        videoType?: VideoTypes;\n        videoConfig?: any;\n        frameIndexNotification?: number;\n        // biome-ignore lint/complexity/noBannedTypes: <explanation>\n        handlerFrameDisplayed?: Function;\n    }> = new BehaviorSubject({ symbol: -1, pos: undefined });\n    public readonly POP_VIDEO = new Subject<ReelDefault | NonProportionalReel | ContainerReel>();\n    public readonly POP_VIDEO_ENDED = new Subject<number>();\n    public readonly CHANGE_BACKGROUND = new Subject();\n    public readonly PLAY_FS_BACKGROUND_ANIMATIONS: BehaviorSubject<boolean> = new BehaviorSubject(false);\n    public readonly PLAY_FS_FOOTER_BACKGROUND: BehaviorSubject<boolean> = new BehaviorSubject(false);\n    public readonly SET_BACKGROUND_ANIMATION: BehaviorSubject<{ type: string; duration?: number }> =\n        new BehaviorSubject({ type: 'backgroundAnimation', duration: 0.2 });\n    public readonly BACKGROUND_ANIMATION_STARTED: ReplaySubject<string> = new ReplaySubject();\n    public readonly BACKGROUND_ANIMATION_FINISHED: ReplaySubject<string> = new ReplaySubject();\n    // set / mix new animation for mixingDuration time,\n    // loop =-1 -> infinity loop no CHARACTER_ANIMATION_FINISHED\n    // loop = 0 no loop (same as loop 1) CHARACTER_ANIMATION_FINISHED at complete\n    // loop = 1/2/3/4.... - loop 1 (same as loop 0), 2, 3, 4 times and then CHARACTER_ANIMATION_FINISHED\n    public readonly SET_CHARACTER_ANIMATION: BehaviorSubject<{\n        type: string;\n        mixDuration: number;\n        loop: number;\n        data?: any;\n    }> = new BehaviorSubject({ type: '', mixDuration: 0, loop: -1 });\n    public readonly SET_CHARACTER_SPINE: BehaviorSubject<{\n        spine: SPINES;\n        alpha?: number;\n        visible?: boolean;\n    }> = new BehaviorSubject({ spine: SPINES.BASE });\n    public readonly CHARACTER_ANIMATION_FINISHED: BehaviorSubject<string> = new BehaviorSubject('');\n\n    public readonly ALL_LINES_DRAWN_FINISHED = new Subject();\n    public readonly LINES_PAUSED: BehaviorSubject<boolean> = new BehaviorSubject(false);\n    // add ZOrder for BuyBonus and DoubleChance, if 0 buttons will be visible false\n    public BUY_BONUS_AND_DOUBLE_CHANCE_VISIBLE: Subject<number> = new Subject();\n    public readonly SHOW_BACKGROUND: BehaviorSubject<boolean> = new BehaviorSubject(true);\n    public readonly SHOW_FOREGROUND: BehaviorSubject<boolean> = new BehaviorSubject(true);\n    // BET BUTTONS\n    // public readonly CHANGE_SELECTED_BET_BTN_EXTERNALLY: Subject<number> = new Subject();\n    public readonly CHANGE_SELECTED_BET_BTN_EXTERNALLY: BehaviorSubject<{\n        betVal: number;\n        changedFromPopUp: boolean;\n    }> = new BehaviorSubject({ betVal: -1, changedFromPopUp: false });\n    public readonly BET_BUTTONS_LABLE_STATE: BehaviorSubject<string> = new BehaviorSubject('PLAY');\n    public readonly ENABLE_BET_BUTTON: Subject<{ id: number; enabled: boolean }> = new Subject();\n    public readonly ENABLE_ALL_BET_BUTTONS: Subject<boolean> = new Subject();\n    public readonly SHOW_BET_BUTTONS: Subject<boolean> = new Subject();\n    public readonly HIDE_BET_BUTTONS: Subject<boolean> = new Subject();\n    public readonly CHANGE_MONEY_CONTAINER_GROUP_ALPHA: Subject<'defaultAlpha' | 'customAlpha'> = new Subject(); //change the alpha of all bet btns, defaultAlpha is setting bet buttons component configuration alpha;\n\n    // MATCH ID\n    public readonly MATCH_ID_VALUE_AND_STYLE: BehaviorSubject<{\n        val: string;\n        style: ITextStyle | null;\n    }> = new BehaviorSubject({ val: '', style: null });\n\n    // LINE BUTTON\n    public readonly LINE_BUTTON_VISIBLE: BehaviorSubject<boolean> = new BehaviorSubject(true);\n\n    // GAME TITLE WIDTH\n    public readonly GAME_TITLE_WIDTH: BehaviorSubject<number> = new BehaviorSubject(0);\n\n    // REELS SUBJECTS\n    public readonly FAKE_REELS: BehaviorSubject<number[][]> = new BehaviorSubject([\n        [0, 0, 0, 0, 0],\n        [1, 1, 1, 1, 1],\n        [2, 2, 2, 2, 2],\n        [3, 3, 3, 3, 3],\n        [4, 4, 4, 4, 4],\n    ]);\n    public readonly RESPIN_FAKE_REELS: BehaviorSubject<number[][]> = new BehaviorSubject([\n        [0, 0, 0, 0, 0],\n        [1, 1, 1, 1, 1],\n        [2, 2, 2, 2, 2],\n        [3, 3, 3, 3, 3],\n        [4, 4, 4, 4, 4],\n    ]);\n    public readonly FREE_SPINS_FAKE_REELS: BehaviorSubject<number[][]> = new BehaviorSubject([\n        [0, 0, 0, 0, 0],\n        [1, 1, 1, 1, 1],\n        [2, 2, 2, 2, 2],\n        [3, 3, 3, 3, 3],\n        [4, 4, 4, 4, 4],\n    ]);\n\n    public readonly BUY_BONUS_FAKE_REELS: BehaviorSubject<number[][]> = new BehaviorSubject([\n        [0, 0, 0, 0, 0],\n        [1, 1, 1, 1, 1],\n        [2, 2, 2, 2, 2],\n        [3, 3, 3, 3, 3],\n        [4, 4, 4, 4, 4],\n    ]);\n\n    public REELS_POSITION: BehaviorSubject<DynamicPositionObject<IReelPositionDefault> & IReelPositionDefault>;\n    public UNIVERSAL_REELS_POSITION: BehaviorSubject<\n        DynamicPositionObject<IUniversalReelPosition> & IUniversalReelPosition\n    >;\n    public UNIVERSAL_SYMBOLS_PER_REEL: BehaviorSubject<number[]> = new BehaviorSubject([3, 4, 3]);\n    //@ts-ignore\n    public CELLS_POSITIONS: BehaviorSubject<DynamicPositionObject<ICellPosition>> = new BehaviorSubject(null);\n    public BELL_LINK_REELS_DEFAULT_POSITION: BehaviorSubject<\n        DynamicPositionObject<IReelPositionDefault> & IReelPositionDefault\n    >;\n    public BELL_LINK_REELS_BOOST_POSITION: BehaviorSubject<\n        DynamicPositionObject<IReelPositionDefault> & IReelPositionDefault\n    >;\n    public REELS_DEFAULT_POSITION: BehaviorSubject<DynamicPositionObject<IReelPositionDefault> & IReelPositionDefault>;\n    public REELS_BOOST_POSITION: BehaviorSubject<DynamicPositionObject<IReelPositionDefault> & IReelPositionDefault>;\n    public REELS_SCALE_FACTOR: BehaviorSubject<number> = new BehaviorSubject(1);\n    public PORTRAIT_FIRST: BehaviorSubject<boolean> = new BehaviorSubject(true);\n    public NUMBER_OF_REELS: BehaviorSubject<number> = new BehaviorSubject(5);\n    public VISIBLE_SYMBOLS_PER_REEL: BehaviorSubject<number> = new BehaviorSubject(3);\n    public TRANSPARENT_REELS: BehaviorSubject<boolean> = new BehaviorSubject(false);\n    public REEL_START_BOUNCE_TIME: BehaviorSubject<number> = new BehaviorSubject(0);\n    public REEL_STOP_BOUNCE_TIME: BehaviorSubject<number> = new BehaviorSubject(0.3);\n    public REEL_STOP_BOUNCE_PERCENT: BehaviorSubject<number> = new BehaviorSubject(30);\n    public REEL_ROTATION_SPEED: BehaviorSubject<number> = new BehaviorSubject(55);\n    public REEL_ROTATION_DIRECTION: BehaviorSubject<number> = new BehaviorSubject(-1);\n    public REELS_MINIMUM_SPIN_TIME: BehaviorSubject<number> = new BehaviorSubject(0);\n    public REELS_FORCE_STOP: BehaviorSubject<boolean> = new BehaviorSubject(false);\n    public GAME_INITIAL_REEL_ROTATION_TIME: BehaviorSubject<number> = new BehaviorSubject(340);\n    public GAME_INITIAL_REEL_ROTATION_TIME_IN_QUICK_SPIN: BehaviorSubject<number> = new BehaviorSubject(250);\n    public GAME_BETWEEN_REELS_DELAY: BehaviorSubject<number> = new BehaviorSubject(320);\n    public GAME_BETWEEN_REELS_DELAY_IN_QUICK_SPIN: BehaviorSubject<number> = new BehaviorSubject(150);\n    public MIN_TIME_REELS_PERCENT_DELAY: BehaviorSubject<number> = new BehaviorSubject(50);\n    public MIN_TIME_ROLL: BehaviorSubject<boolean> = new BehaviorSubject(false);\n    public GAME_ANTICIPATION_REELS_DELAY: BehaviorSubject<number> = new BehaviorSubject(2050);\n    public NUMBER_OF_GUARD_SYMBOLS: BehaviorSubject<number> = new BehaviorSubject(2);\n    public PORTRAIT_SCALE: BehaviorSubject<number> = new BehaviorSubject(0.72);\n    public readonly IS_ANIMATION_FLOW_FREE: BehaviorSubject<boolean> = new BehaviorSubject(true);\n\n    public readonly BLITZ_RESTORE: BehaviorSubject<{\n        val: boolean;\n        response: BetResponse | RestoreResponse | null;\n        lastBonusType: string | null;\n    }> = new BehaviorSubject({\n        val: false,\n        response: null,\n        lastBonusType: null,\n    });\n\n    public readonly SPECIAL_STOP_CONDITION_REACHED: BehaviorSubject<boolean> = new BehaviorSubject(false);\n\n    // GIFT SPINS SUBJECTS\n    public readonly FIRST_BET_CLICKED = new Subject();\n    public readonly SWITCH_BET_BUTTONS: BehaviorSubject<{ fromIndex: number; toIndex: number }> = new BehaviorSubject({\n        fromIndex: 0,\n        toIndex: 0,\n    });\n\n    // LINES\n    public LINES_CONFIG: BehaviorSubject<DynamicPositionObject<ILinesConfig> & ILinesConfig>;\n    public FULL_LINE_SOUND_PLAYED: BehaviorSubject<string> = new BehaviorSubject('');\n\n    // MULTILAYERED BACKGROUND SOUND\n    public readonly BG_SOUND_LAYER: BehaviorSubject<BackgroundMusic> = new BehaviorSubject<BackgroundMusic>(\n        'backgroundMusic',\n    );\n    public readonly CHANGE_BACKGROUND_SOUND_LAYER: BehaviorSubject<IChangeBackgroundMusicLayerCommand> =\n        new BehaviorSubject<IChangeBackgroundMusicLayerCommand>({ action: 'increase' });\n    public readonly RESET_BG_LAYER_TIMER: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n    public readonly ENABLE_MULTILAYERED_BG_SOUND_COMPONENT: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(\n        false,\n    );\n    public readonly REELS_RUNNING: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n\n    public destroy(): void {\n        Object.keys(this).forEach((key: string) => {\n            if (this[key]) {\n                this[key].complete();\n                this[key] = null;\n            }\n        });\n    }\n    // FRAME EXPAND SUBJECTS\n    public readonly SHOW_EXPAND_FRAME = new Subject();\n    public readonly EXPAND_FRAME_SHOWN = new Subject();\n    public readonly HIDE_FRAME_EXPAND_ANIMATION = new Subject();\n\n    // ONE DENOMINATION\n    public readonly IS_ONE_DENOMINATION: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n\n    // BET PROGRESS\n    public readonly EXPOSE_BET_PROGRESS: BehaviorSubject<any> = new BehaviorSubject<any>(null);\n    public readonly BET_PROGRESS_BEFORE_SPIN = new Subject();\n\n    // Custom tool\n    public readonly IS_CUSTOM_SHOWN: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n}\n","import ServerState from '../data/ServerState';\n\nconst AnalyticsState: any = [];\nAnalyticsState[ServerState.WIN] = 'Win';\nAnalyticsState[ServerState.FREESPIN] = 'Free Spin';\nAnalyticsState[ServerState.HOLDSPIN] = 'Bell Link';\nAnalyticsState[ServerState.IDLE] = 'Normal Spin';\nAnalyticsState[ServerState.BONUS_SUMMARY] = 'Gift Spins End';\nAnalyticsState[ServerState.WHEEL_SPIN] = 'Free Spin';\nAnalyticsState[ServerState.BONUS_IDLE] = 'Gift Spin';\nAnalyticsState[ServerState.MYSTERY] = 'Mystery';\nAnalyticsState[ServerState.PICK] = 'Pick Me Bonus';\nAnalyticsState[ServerState.FREERESPIN] = 'Respin in Freespin';\nAnalyticsState[ServerState.RESPIN] = 'Respin';\nAnalyticsState[ServerState.WHEEL_SPIN] = 'Wheel Spin';\n\nexport default AnalyticsState;\n","const enum CentralWinActions {\n    NONE = 'NONE',\n    DONT_UPDATE_BEFORE_NEXT_SPIN = 'DONT_UPDATE_BEFORE_NEXT_SPIN',\n    USE_PICK_VALUE = 'USE_PICK_VALUE',\n}\n\nexport default CentralWinActions;\n","const enum RootElementsAnimationTypes {\n    ZOOM = 'ZOOM',\n    BOUNCE = 'BOUNCE',\n    CUSTOM = 'CUSTOM',\n    CUSTOMBIGWIN = 'CUSTOMBIGWIN',\n}\n\nexport default RootElementsAnimationTypes;\n","const enum SlotComponents {\n    DEFAULT = 'DEFAULT',\n    BACKGROUND_SOUND = 'BACKGROUND_SOUND',\n    UI_MAIN_PANEL = 'UI_MAIN_PANEL',\n    UI_VIEW = 'UI_VIEW',\n    CLOCK = 'CLOCK',\n    CHANGE_GAME_MODE = 'CHANGE_GAME_MODE',\n    DOWNLOAD = 'DOWNLOAD',\n    REELS = 'REELS',\n    NON_PROPORTIONAL_REELS = 'NON_PROPORTIONAL_REELS',\n    UNIVERSAL_REELS = 'UNIVERSAL_REELS',\n    CASCADE_REELS = 'CASCADE_REELS',\n    CASCADE_WAYS_REELS = 'CASCADE_WAYS_REELS',\n    MESSAGE_BAR = 'MESSAGE_BAR',\n    MESSAGE_ALERT = 'MESSAGE_ALERT',\n    MATCH_ID = 'MATCH_ID',\n    REELS_OVERLAY = 'REELS_OVERLAY',\n    GAME_LOGO = 'GAME_LOGO',\n    DEMO_MODE = 'DEMO_MODE',\n    MODAL_LAYER = 'MODAL_LAYER',\n    GAME_TITLE = 'GAME_TITLE',\n    LINE_BUTTON = 'LINE_BUTTON',\n    BACKGROUND = 'BACKGROUND',\n    STAGE_MASK = 'STAGE_MASK',\n    BET_BUTTONS = 'BET_BUTTONS',\n    FLOATING_TEXT = 'FLOATING_TEXT',\n    BG_ANIMATION = 'BG_ANIMATION',\n    BUY_BONUS = 'BUY_BONUS',\n    CHARACTERS_ANIMATION = 'CHARACTERS_ANIMATION',\n    FRAME = 'FRAME',\n    PORTRAIT_LOGOS = 'PORTRAIT_LOGOS',\n    HIGH_CASH_ANTICIPATION = 'HIGH_CASH_ANTICIPATION',\n    HIGH_CASH_TRANSITION = 'HIGH_CASH_TRANSITION',\n    HIGH_CASH_JACKPOT_LOGO = 'HIGH_CASH_JACKPOT_LOGO',\n    AUTOPLAY_POPUP = 'AUTOPLAY_POPUP',\n    DENOMINATION_POPUP = 'DENOMINATION_POPUP',\n    // EXTENDED_DENOMINATION_POPUP = 'EXTENDED_DENOMINATION_POPUP',\n    // EXTENDED_AUTOPLAY_POPUP = 'EXTENDED_AUTOPLAY_POPUP',\n    // AUTOPLAY_NUMERIC_INPUT_POPUP = 'AUTOPLAY_NUMERIC_INPUT_POPUP',\n    SETTINGS_POPUP = 'SETTINGS_POPUP',\n    FG_ANIMATION = 'FG_ANIMATION',\n    MULTI_REELS_MASK = 'MULTI_REELS_MASK',\n    CASH_HEAT_LOGO = 'CASH_HEAT_LOGO',\n    PORTRAIT_GRADIENT = 'PORTRAIT_GRADIENT',\n    WAYS_COUNTER = 'WAYS_COUNTER',\n    CASCADE_WAYS_COUNTER = 'CASCADE_WAYS_COUNTER',\n    HOME_BUTTON = 'HOME_BUTTON',\n    REEL_ANTICIPATION_ANIM = 'REEL_ANTICIPATION_ANIM',\n    JACKPOT_STATS = 'JACKPOT_STATS',\n    STAGE_BLOCKER = 'STAGE_BLOCKER',\n    CASCADE_REEL_MULTIPLIER = 'CASCADE_REEL_MULTIPLIER',\n    CONTAINER_REELS = 'CONTAINER_REELS',\n    HORIZONTAL_REEL = 'HORIZONTAL_REEL',\n    MULTILAYERED_BG_SOUND = 'MULTILAYERED_BG_SOUND',\n    CASCADE_IDLE_ANIMATIONS = 'CASCADE_IDLE_ANIMATIONS',\n    CASCADE_ANTICIPATION_ANIMATION = 'CASCADE_ANTICIPATION_ANIMATION',\n    WIN = 'WIN',\n    FOOTER_BACKGROUND = 'FOOTER_BACKGROUND',\n    FLOATING_AMOUNT = 'FLOATING_AMOUNT',\n    BET_CALCULATOR = 'BET_CALCULATOR',\n    BET_PROGRESS = 'BET_PROGRESS',\n    HIGH_RTP_BADGE = 'HIGH_RTP_BADGE',\n    MAX_WIN_PROBABILITY = 'MAX_WIN_PROBABILITY',\n    SYMBOL_FRAMES = 'SYMBOL_FRAMES',\n    VLT = 'VLT',\n    BL_BOOST_SPECIAL_BELLS_ANIMATIONS = 'BL_BOOST_SPECIAL_BELLS_ANIMATIONS',\n}\nexport default SlotComponents;\n","enum ZOrders {\n    // ----------------------------------------------\n    STAGE_MASK = 0,\n    BASE_LEVEL = 10,\n    REELS_LEVEL = 20,\n    VIDEOS_LEVEL = 30,\n    LINES_LEVEL = 40,\n    MODAL_LEVEL = 50,\n    // -----------------------------------------------\n    UI_LEVEL = 100,\n    // -----------------------------------------------\n    SPIN_BUTTONS_LEVEL = 200,\n    MESSAGES_LEVEL = 290,\n    // -----------------------------------------------\n    POPUP_LEVEL = 300,\n\n    COIN_LEVEL = 310,\n    // -----------------------------------------------\n    STAGE_BLOCK_LEVEL = 400,\n}\n\nexport default ZOrders;\n","import Core, { BaseController, ErrorTypes, IErrorData, PostMessageDispatcher } from '@egt/core';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport BonusTypes from '../data/BonusTypes';\nimport InitialSettings from '../data/InitialSettings';\nimport PriorityList from '../data/PriorityList';\nimport PriorityTypes from '../data/PriorityTypes';\nimport ServerState from '../data/ServerState';\nimport RootStore from '../root/RootStore';\n\n@injectable()\nexport default class FeatureController extends BaseController {\n    private _giftSpinsType: BonusTypes | null = null;\n    constructor(\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('InitialSettings') protected settings: InitialSettings,\n        @inject('PriorityMap') private priorityMap?: any,\n    ) {\n        super(undefined);\n        this.setPriorities();\n        this.rootStore.uiStore.COLLECT_CLICKED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onCollectBtnClicked.bind(this),\n        );\n\n        // this.rootStore.uiStore.SPIN_BTN_CLICKED.pipe(takeUntil(this.DESTROY)).subscribe(\n        //     this.onSpinBtnClicked.bind(this),\n        // );\n        this.rootStore.domainStore.SERVER_STATE.next(settings.state);\n        this.rootStore.subjects.RESTORE.pipe(takeUntil(this.DESTROY)).subscribe(this.onRestore.bind(this));\n\n        this.rootStore.subjects.REELS_STOPPED.pipe(takeUntil(this.DESTROY)).subscribe(this.onReelsStopped.bind(this));\n        this.rootStore.subjects.PROCESS_CURRENT_SPIN_RESULT.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.processCurrentSpinResult.bind(this),\n        );\n        this.rootStore.domainStore.SPIN_MODE.pipe(takeUntil(this.DESTROY)).subscribe(this.onModeChanged.bind(this));\n\n        Core.SHOW_ERROR.pipe(takeUntil(this.DESTROY)).subscribe(this.onErrorWithInsifitionsFunds.bind(this));\n    }\n\n    public get isFeatureMode(): boolean {\n        return (\n            [\n                ServerState.FREESPIN,\n                ServerState.FREESPIN_PICK,\n                ServerState.FREESPIN_SCATTERS,\n                ServerState.CHOICE,\n                ServerState.SCATTERCHOICE,\n                ServerState.FREERESPIN,\n                ServerState.RESPIN_WHEEL,\n                ServerState.CREDIT_WHEEL,\n                ServerState.RESPIN,\n                ServerState.HOLDSPIN,\n                ServerState.PICK,\n                ServerState.GAMBLE,\n                ServerState.HIGH_CASH_FREE_RESPIN,\n                ServerState.RESPIN_FROM_WHEEL,\n                ServerState.JACKPOT_PICK,\n                ServerState.WHEEL_SPIN,\n                ServerState.MYSTERY,\n                ServerState.BONUS_CHANCE,\n            ].indexOf(this.rootStore.domainStore.SERVER_STATE.value as ServerState) > -1\n        );\n    }\n\n    public get isControlInFeature(): boolean {\n        return this.isFeatureMode || this.isInGiftSpins;\n    }\n\n    public get disableSpecialSpinSpeedForFeature(): boolean {\n        return (\n            [\n                ServerState.FREESPIN,\n                ServerState.FREESPIN_SCATTERS,\n                ServerState.FREERESPIN,\n                ServerState.RESPIN,\n                ServerState.HOLDSPIN,\n            ].indexOf(this.rootStore.domainStore.SERVER_STATE.value as ServerState) > -1\n        );\n    }\n\n    public set giftSpinsType(value: BonusTypes | null) {\n        this._giftSpinsType = value;\n    }\n\n    public get giftSpinsType(): BonusTypes | null {\n        return this._giftSpinsType;\n    }\n\n    public get isInGiftSpins(): boolean {\n        return this._giftSpinsType !== null;\n    }\n\n    public destroy(): void {\n        // @ts-ignore\n        this.rootStore.subjects.REELS_STOPPED.destroy();\n        // @ts-ignore\n        this.rootStore.subjects.REELS_STOPPED = null;\n\n        // @ts-ignore\n        this.rootStore.subjects.PROCESS_CURRENT_SPIN_RESULT.destroy();\n        // @ts-ignore\n        this.rootStore.subjects.PROCESS_CURRENT_SPIN_RESULT = null;\n        // if (this.rootStore.uiStore.SPIN_BTN_CLICKED) {\n        //     this.rootStore.uiStore.SPIN_BTN_CLICKED.destroy();\n        //     // @ts-ignore\n        //     this.rootStore.uiStore.SPIN_BTN_CLICKED = null;\n        // }\n        if (this.rootStore.subjects.RESTORE) {\n            this.rootStore.subjects.RESTORE.destroy();\n            // @ts-ignore\n            this.rootStore.subjects.RESTORE = null;\n        }\n        if (this.rootStore) {\n            // @ts-ignore\n            this.rootStore = null;\n        }\n        super.destroy();\n    }\n\n    protected setPriorities(): void {\n        // This Add Spin mode value on end of the priority list\n        this.priorityMap.REELS_STOPPED.push(this.rootStore.domainStore.SPIN_MODE.value);\n        this.priorityMap.PROCESS_CURRENT_SPIN_RESULT.push(this.rootStore.domainStore.SPIN_MODE.value);\n        this.priorityMap.COLLECT_CLICKED.push(this.rootStore.domainStore.SPIN_MODE.value);\n        // this.priorityMap.SPIN_BTN_CLICKED.push(this.rootStore.domainStore.SPIN_MODE.value);\n\n        this.rootStore.subjects.REELS_STOPPED.priorities = new PriorityList(\n            this.priorityMap.REELS_STOPPED,\n            PriorityTypes.REEL_STOPPED,\n        );\n        this.rootStore.subjects.PROCESS_CURRENT_SPIN_RESULT.priorities = new PriorityList(\n            this.priorityMap.PROCESS_CURRENT_SPIN_RESULT,\n            PriorityTypes.PROCESS_CURRENT_SPIN_RESULT,\n        );\n        this.rootStore.uiStore.COLLECT_CLICKED.priorities = new PriorityList(\n            this.priorityMap.COLLECT_CLICKED,\n            PriorityTypes.COLLECT_CLICKED,\n        );\n        // this.rootStore.uiStore.SPIN_BTN_CLICKED.priorities = new PriorityList(this.priorityMap.SPIN_BTN_CLICKED);\n        this.rootStore.subjects.RESTORE.priorities = new PriorityList(this.priorityMap.RESTORE, PriorityTypes.RESTORE);\n    }\n\n    protected onCollectBtnClicked(): void {\n        this.rootStore.uiStore.COLLECT_CLICKED.executorComplete();\n    }\n\n    // protected onSpinBtnClicked(): void {\n    //     this.rootStore.uiStore.SPIN_BTN_CLICKED.executorComplete();\n    // }\n\n    protected onRestore(): void {\n        this.rootStore.subjects.RESTORE.executorComplete();\n    }\n\n    protected onReelsStopped(): void {\n        if (\n            this.isFeatureMode ||\n            (this.rootStore.domainStore.SERVER_STATE.value === ServerState.BONUS_IDLE && !this.isInGiftSpins)\n        ) {\n            if (\n                this.rootStore.domainStore.SPIN_MODE.value === 'AUTO_PLAY' ||\n                this.rootStore.domainStore.SPIN_MODE.prevValue === 'AUTO_PLAY'\n            ) {\n                // init auto play settings\n                this.rootStore.subjects.STOP_AUTOPLAY.next();\n            }\n            //  // init auto play settings\n            //  this.rootStore.subjects.STOP_AUTOPLAY.next();\n            this.rootStore.subjects.STOP_FAST_PLAY.next();\n        }\n        this.rootStore.uiStore.disableSpecialSpinSpeedForCurrentState = this.disableSpecialSpinSpeedForFeature\n            ? true\n            : false;\n\n        this.rootStore.subjects.REELS_STOPPED.executorComplete();\n    }\n\n    protected processCurrentSpinResult(): void {\n        if (\n            this.isFeatureMode ||\n            (this.rootStore.domainStore.SERVER_STATE.value === ServerState.BONUS_IDLE && !this.isInGiftSpins)\n        ) {\n            // init auto play settings\n            this.rootStore.subjects.STOP_AUTOPLAY.next();\n            this.rootStore.subjects.STOP_FAST_PLAY.next();\n        }\n\n        this.rootStore.uiStore.disableSpecialSpinSpeedForCurrentState = this.disableSpecialSpinSpeedForFeature\n            ? true\n            : false;\n\n        this.rootStore.subjects.PROCESS_CURRENT_SPIN_RESULT.executorComplete();\n    }\n\n    protected onModeChanged(): void {\n        // console.log(\"*********SPIN_MODE:\", this.rootStore.domainStore.SPIN_MODE.value)\n        this.rootStore.subjects.REELS_STOPPED.priorities.changeLastPriorities(\n            this.rootStore.domainStore.SPIN_MODE.value,\n        );\n\n        this.rootStore.subjects.PROCESS_CURRENT_SPIN_RESULT.priorities.changeLastPriorities(\n            this.rootStore.domainStore.SPIN_MODE.value,\n        );\n\n        this.rootStore.uiStore.COLLECT_CLICKED.priorities.changeLastPriorities(\n            this.rootStore.domainStore.SPIN_MODE.value,\n        );\n\n        this.rootStore.uiStore.disableSpecialSpinSpeedForCurrentState = this.disableSpecialSpinSpeedForFeature\n            ? true\n            : false;\n        // this.rootStore.uiStore.SPIN_BTN_CLICKED.priorities.changeLastPriorities(\n        //     this.rootStore.domainStore.SPIN_MODE.value,\n        // );\n        // console.log('********Changed', this.rootStore.subjects.REELS_STOPPED.priorities);\n        if (this.rootStore.domainStore.SPIN_MODE.prevValue !== this.rootStore.domainStore.SPIN_MODE.value) {\n            PostMessageDispatcher.playModeUpdate(this.rootStore.domainStore.SPIN_MODE.value);\n        }\n        if (\n            this.rootStore.domainStore.SPIN_MODE.prevValue === 'AUTO_PLAY' &&\n            this.rootStore.domainStore.SPIN_MODE.value !== 'AUTO_PLAY'\n        ) {\n            PostMessageDispatcher.autoPlayStopped();\n        }\n    }\n\n    private onErrorWithInsifitionsFunds(error: IErrorData): void {\n        if (error.code.toString() === '4813' && this.isInGiftSpins && error.type === ErrorTypes.GAME_ERROR) {\n            error.type = ErrorTypes.GAME_LOCK_ERROR;\n            Core.SHOW_ERROR.next(error);\n        }\n    }\n}\n","const enum Features {\n    EXPAND = 'EXPAND',\n    PICK_ME_BONUS = 'PICK_ME_BONUS',\n    MULTIPLIER = 'MULTIPLIER',\n    BL_JACKPOT_WON = 'BL_JACKPOT_WON',\n    VIDEOS = 'VIDEOS',\n    LINES = 'LINES',\n    COIN = 'COIN',\n    DEMO = 'DEMO',\n    GAMBLE = 'GAMBLE',\n    TOURNAMENTS = 'TOURNAMENTS',\n    // Backend load/wire identity for the prize-pop campaign (settings.feature, externalFeatures).\n    PRIZE_POPS = 'PRIZE_POPS',\n    // SPINE_VIDEOS = 'SPINE_VIDEOS',\n    // The always-on CampaignManager feature: its load key (venom slug campaign-manager) and the\n    // campaign chain slot (featuresPriority, chainSubscribe, FEATURE_COMPLETE/SPIN_MODE).\n    // Campaigns themselves load under their own keys, e.g. PRIZE_POPS.\n    CAMPAIGN_MANAGER = 'CAMPAIGN_MANAGER',\n    HORIZONTAL_REEL = 'HORIZONTAL_REEL',\n    FRAME_EXPAND = 'FRAME_EXPAND',\n    WHEEL = 'WHEEL',\n\n    // SPIN MODS\n    MANUAL_SPIN = 'MANUAL_SPIN',\n    AUTO_PLAY = 'AUTO_PLAY',\n    FREE_SPINS = 'FREE_SPINS',\n    FREE_SPINS_PICK = 'FREE_SPINS_PICK',\n    RESPIN = 'RESPIN',\n    HOLD_RESPIN = 'HOLD_RESPIN',\n    BL_JACKPOT = 'BL_JACKPOT',\n    SG_JACKPOT = 'SG_JACKPOT',\n    MYSTERY_JACKPOT = 'MYSTERY_JACKPOT',\n    PREMIUM_LINK_JACKPOT = 'PREMIUM_LINK_JACKPOT',\n    GAKL_JACKPOT_V1 = 'GAKL_JACKPOT_V1',\n    GAKL_JACKPOT_BASE = 'GAKL_JACKPOT_BASE',\n    GAKL_JACKPOT_WON = 'GAKL_JACKPOT_WON',\n    GAKL_FEATURE_CHANCE = 'GAKL_FEATURE_CHANCE',\n    GIFT_SPINS = 'GIFT_SPINS',\n    HOLD_AND_WIN = 'HOLD_AND_WIN',\n    BL_BOOST_JACKPOT = 'BL_BOOST_JACKPOT',\n    BL_BOOST_JACKPOT_WON = 'BL_BOOST_JACKPOT_WON',\n    BLITZ_PLAY = 'BLITZ_PLAY',\n\n    // RESTORE\n    RESTORE = 'RESTORE',\n    NONE = 'NONE',\n\n    // HIGH CASH\n    HIGH_CASH_RESPIN = 'HIGH_CASH_RESPIN',\n    HIGH_CASH_COUNTERS = 'HIGH_CASH_COUNTERS',\n    HIGH_CASH_PICKER = 'HIGH_CASH_PICKER',\n    HIGH_CASH_WHEEL = 'HIGH_CASH_WHEEL',\n    HIGH_CASH_RESPIN_CREDIT_WHEEL = 'HIGH_CASH_RESPIN_CREDIT_WHEEL',\n    HIGH_CASH_FREE_SPINS = 'HIGH_CASH_FREE_SPINS',\n    HIGH_CASH_JACKPOT_WON = 'HIGH_CASH_JACKPOT_WON',\n    HIGH_CASH_BALL = 'HIGH_CASH_BALL',\n    HIGH_CASH_COIN = 'HIGH_CASH_COIN',\n    HIGH_CASH_CHOICE = 'HIGH_CASH_CHOICE',\n    HIGH_CASH_MANAGER = 'HIGH_CASH_MANAGER',\n\n    HIGH_CASH_EXPAND = 'HIGH_CASH_EXPAND',\n\n    BASE_FREE_SPINS = 'BASE_FREE_SPINS',\n    BIG_WIN = 'BIG_WIN',\n    SMALL_WIN = 'SMALL_WIN',\n    MAX_WIN = 'MAX_WIN',\n\n    // CASCADE_VIDEOS = 'CASCADE_VIDEOS',\n    // CASCADE_WAYS_VIDEOS = 'CASCADE_WAYS_VIDEOS',\n    CASCADE_SPINE_VIDEOS = 'CASCADE_SPINE_VIDEOS',\n    CASCADE_RESPIN = 'CASCADE_RESPIN',\n    CASCADE_GLOBAL_MULTIPLIER = 'CASCADE_GLOBAL_MULTIPLIER',\n    EXPLOSION = 'EXPLOSION',\n    BRANDING = 'BRANDING',\n    BL_CHRISTMAS = 'BL_CHRISTMAS',\n    CHARACTER_ANIMATIONS = 'CHARACTER_ANIMATIONS',\n    CHARACTER_ANIMATIONS_FS = 'CHARACTER_ANIMATIONS_FS',\n    // WAYS\n    WAYS_MYSTERY = 'WAYS_MYSTERY',\n    CASCADE_MULTIPLIER = 'CASCADE_MULTIPLIER',\n    CASCADE_TOTAL_MULTIPLIER = 'CASCADE_TOTAL_MULTIPLIER',\n    // MULTI REELS\n    MULTI_REELS = 'MULTI_REELS',\n    MULTI_REELS_ANIMATIONS = 'MULTI_REELS_ANIMATIONS',\n\n    // CASH HEAT\n    CASH_HEAT = 'CASH_HEAT',\n\n    MAX_WIN_LIMIT = 'MAX_WIN_LIMIT',\n\n    SYMBOL_POP_VIDEO = 'SYMBOL_POP_VIDEO',\n    SYMBOL_REPLACE_VIDEO = 'SYMBOL_REPLACE_VIDEO',\n\n    // CHOICE\n    CHOICE = 'CHOICE',\n    SYMBOL_ANTICIPATION_ANIM = 'SYMBOL_ANTICIPATION_ANIM',\n\n    ROOT_ELEMENTS_ANIMATION = 'ROOT_ELEMENTS_ANIMATION',\n    FULL_LINE_ANIMATION = 'FULL_LINE_ANIMATION',\n\n    INTRO_ANIMATION = 'INTRO_ANIMATION',\n\n    REPLAYER = 'REPLAYER',\n    ACTIVATOR = 'ACTIVATOR',\n    WILD_REPLACE = 'WILD_REPLACE',\n    WIN_ANIMATIONS_PREVIEW = 'WIN_ANIMATIONS_PREVIEW',\n}\n\nexport default Features;\n","import LineMode from './LineMode';\n\nexport default class Line {\n    public static isLine(line: any): line is Line {\n        if (line === undefined || line === null || Array.isArray(line) || typeof line !== 'object') {\n            return false;\n        }\n        if ('symbol' in line === false) {\n            return false;\n        }\n        if ('cells' in line === false) {\n            return false;\n        }\n        return true;\n    }\n\n    constructor(\n        private _symbol: number,\n        private _cells: number[],\n        private _line: number,\n        private _multiplier: number,\n        private _occurs: number,\n        private _win: number,\n        private _winAmount: number,\n        private _mode: LineMode,\n        private _winsJackpot: boolean,\n        private _symbols: number[] = [],\n        private _message: string = '',\n        private _ways?: number,\n    ) {}\n\n    public get message(): string {\n        return this._message;\n    }\n\n    public get symbol(): number {\n        return this._symbol;\n    }\n\n    public get cells(): number[] {\n        return this._cells;\n    }\n\n    public get line(): number {\n        return this._line;\n    }\n\n    public get multiplier(): number {\n        return this._multiplier;\n    }\n\n    public get occurs(): number {\n        return this._occurs;\n    }\n\n    public get win(): number {\n        return this._win;\n    }\n\n    public get winAmount(): number {\n        return this._winAmount;\n    }\n\n    public get mode(): LineMode {\n        return this._mode;\n    }\n\n    public get winsJackpot(): boolean {\n        return this._winsJackpot;\n    }\n\n    public get symbols(): number[] {\n        return this._symbols;\n    }\n\n    public set symbols(value: number[]) {\n        this._symbols = value;\n    }\n\n    public get ways(): number | undefined {\n        return this._ways;\n    }\n}\n","const enum LineMode {\n    LINE = 'line',\n    EXPAND = 'expand',\n    SCATTER = 'scatter',\n    MESSAGE = 'message',\n    CASCADE = 'cascade',\n    WAYS = 'ways',\n    OVERFLOW = 'overflow',\n    CLUSTER = 'cluster',\n}\nexport default LineMode;\n","import Core, { IVideoPlayer, Timers } from '@egt/core';\nimport { ViewContainer } from '@egt/ui-lib';\nimport { Sprite } from 'pixi.js';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { ISlotConfiguration } from '../../slot-configuration/ISlotConfiguration';\nimport SpinAnalyzer from '../data/SpinAnalyzer';\nimport RootStore from '../root/RootStore';\nimport UIState from '../ui/UIState';\nimport { ILinesView } from './ILinesView';\nimport Line from './Line';\nimport LineMode from './LineMode';\n\n@injectable()\nexport default class LinesView extends ViewContainer implements ILinesView {\n    public linesCleared: boolean = true;\n    public fastCycleEnabled: boolean = false;\n    public showAllWinLinesTogether: boolean = true;\n    public showAllWinLinesDelay: number = 1500;\n\n    protected animType: string = 'Landscape';\n    protected linesXPosition: number = 527;\n    protected linesYPosition: number = 305;\n    private lines: any[] = [];\n    private squares: any[] = [];\n    private timeScale: number = 1;\n    private vp: IVideoPlayer;\n\n    constructor(\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('SpinAnalyzer') protected spinAnalyzer: SpinAnalyzer,\n    ) {\n        super();\n\n        this.rootStore.uiStore.ACTIVE_LINE.pipe(takeUntil(this.DESTROY)).subscribe(this.onActiveLineChanged.bind(this));\n\n        this.rootStore.uiStore.FAST_CYCLE.pipe(takeUntil(this.DESTROY)).subscribe(this.onFastCycleChanged.bind(this));\n\n        this.rootStore.uiStore.SHOW_ALL_LINES.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onShowAllLinesChanged.bind(this),\n        );\n\n        const spineAnim = Core.assets.getAsset('spineSquares');\n        if (!spineAnim) {\n            const symbolTextures = Core.assets.getAnimationAssets('squareFrames', 'winFrame');\n\n            const videoConfig = {\n                id: 'squareFrames',\n                fps: symbolTextures.length / 2,\n                width: this.rootStore.subjects.REELS_POSITION.value.symbolWidth,\n                height: this.rootStore.subjects.REELS_POSITION.value.symbolHeight,\n                length: symbolTextures.length,\n                loop: false,\n            };\n            this.vp = Core.createVideoPlayer();\n            this.vp.config = videoConfig;\n            this.vp.frames = Object.keys(symbolTextures).map((personNamedIndex) => {\n                return symbolTextures[personNamedIndex];\n            });\n        }\n    }\n\n    public showLineFirstTime(lineNumber: number): void {\n        this.createLineSpine(lineNumber, true);\n    }\n\n    public showWinLines(): void {\n        //\n    }\n\n    // biome-ignore lint/correctness/noUnusedVariables: <explanation>\n    public showHideAllLines(val): void {\n        //\n    }\n\n    public destroy(): void {\n        super.destroy.apply(this, arguments);\n        if (this.vp) {\n            Core.destroyVideoPlayer(this.vp);\n            // @ts-ignore\n            this.vp = null;\n        }\n    }\n\n    public clearSquares(): void {\n        if (this.vp) {\n            this.vp.stop();\n            Core.destroyVideoPlayer(this.vp);\n        }\n        for (const square of this.squares) {\n            this.removeChild(square);\n        }\n        this.squares = [];\n    }\n\n    public clearLines(clearWhenSwitchLines: boolean = false): void {\n        for (const line of this.lines) {\n            this.removeChild(line);\n        }\n        this.lines = [];\n\n        this.linesCleared = !clearWhenSwitchLines;\n    }\n\n    protected createSquareSpine(row: number, col: number): void {\n        if (this.linesCleared || this.rootStore.uiStore.fastSpinMode || this.rootStore.uiStore.turboModeEnabled) {\n            return;\n        }\n\n        const symbolFrame = Core.spineAnimations.createSpineAnimations('spineSquares');\n        this.addChild(symbolFrame);\n        this.squares.push(symbolFrame);\n\n        let xOffset: number = 6;\n        if (this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value === 4) {\n            xOffset = 0;\n        }\n\n        symbolFrame.x =\n            this.rootStore.subjects.REELS_POSITION.value.reelWidth / 2 +\n            (this.rootStore.subjects.REELS_POSITION.value.reelWidth +\n                this.rootStore.subjects.REELS_POSITION.value.reelSpacing) *\n                row +\n            xOffset;\n        symbolFrame.y =\n            this.rootStore.subjects.REELS_POSITION.value.symbolHeight / 2 +\n            this.rootStore.subjects.REELS_POSITION.value.symbolHeight * col;\n        symbolFrame.state.timeScale = this.timeScale;\n        symbolFrame.state.setAnimation(0, ((window as any).__SLN=('frameAnimation' + this.animType), ((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"spine:packages/slot/src/egt/slots/components/lines/LinesView.ts:130:9\",(window as any).__SLN]), (window as any).__SLN), false);\n    }\n\n    protected createSquareAnim(row: number, col: number): void {\n        if (this.linesCleared || this.rootStore.uiStore.fastSpinMode || this.rootStore.uiStore.turboModeEnabled) {\n            return;\n        }\n\n        const frame: Sprite = new Sprite();\n        frame.anchor.set(0.5);\n        frame.x =\n            (this.rootStore.subjects.REELS_POSITION.value.symbolWidth / 2) * (row + 1) +\n            (this.rootStore.subjects.REELS_POSITION.value.reelSpacing +\n                this.rootStore.subjects.REELS_POSITION.value.symbolWidth / 2) *\n                row;\n        frame.y =\n            (this.rootStore.subjects.REELS_POSITION.value.symbolHeight / 2) * (col + 1) +\n            (this.rootStore.subjects.REELS_POSITION.value.symbolHeight / 2) * col;\n        this.addChild(frame);\n        this.squares.push(frame);\n\n        this.vp.addInstance(frame);\n        this.vp.play();\n    }\n\n    protected createLineSpine(line: number, showAll: boolean = false): void {\n        if ((this.linesCleared && !showAll) || !line) {\n            return;\n        }\n\n        if (!showAll) {\n            this.clearLines(true);\n        }\n        // if (!this.lines[0] || showAll) {\n        // const symbolFrameAsset = Core.assets.getAsset('spineLines');\n        // lineAnimation = new PIXI.spine.Spine(symbolFrameAsset.spineData);\n        const lineAnimation = Core.spineAnimations.createSpineAnimations('spineLines');\n        this.addChild(lineAnimation);\n        this.lines.push(lineAnimation);\n\n        lineAnimation.x = this.linesXPosition;\n        lineAnimation.y = this.linesYPosition;\n        // } else {\n        //     lineAnimation = this.lines[0];\n        //     lineAnimation.state.getCurrent(0).trackTime = 0;\n        // }\n\n        lineAnimation.state.timeScale = this.timeScale;\n        lineAnimation.state.setAnimation(0, ((window as any).__SLN=('lineAnimation' + this.animType + line), ((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"spine:packages/slot/src/egt/slots/components/lines/LinesView.ts:178:9\",(window as any).__SLN]), (window as any).__SLN), false);\n    }\n\n    private onFastCycleChanged(fastCycle: boolean): void {\n        if (fastCycle) {\n            this.timeScale = 2;\n        } else {\n            this.timeScale = 1;\n        }\n    }\n\n    private onShowAllLinesChanged(show: boolean): void {\n        if (show) {\n            this.showAllLines();\n        }\n    }\n\n    private onCellsChanged(activeLine: Line): void {\n        this.clearSquares();\n        for (let i = 0; i < activeLine.cells.length; i += 2) {\n            Timers.setTimeout(\n                () => {\n                    const row = activeLine.cells[i];\n                    const col = activeLine.cells[i + 1];\n\n                    this.createSquareAnimation(row, col);\n                },\n                (100 * i) / this.timeScale,\n            );\n        }\n    }\n\n    private createSquareAnimation(row: number, col: number): void {\n        const spineAnim = Core.assets.getAsset('spineSquares');\n        if (spineAnim) {\n            this.createSquareSpine(row, col);\n        } else {\n            this.createSquareAnim(row, col);\n        }\n    }\n\n    private onActiveLineChanged(activeLine: Line | number): void {\n        if (Line.isLine(activeLine)) {\n            if (activeLine.mode === LineMode.LINE || activeLine.mode === LineMode.EXPAND) {\n                this.createLineSpine(activeLine.line + 1);\n            }\n            this.onCellsChanged(activeLine);\n        }\n    }\n\n    private showAllLines(): void {\n        // show all lines only if we are in state idle\n        if (this.rootStore.uiStore.STATE.value !== UIState.IDLE) {\n            return;\n        }\n        for (let i: number = 0; i < this.slotConfiguration.lines.length; i++) {\n            this.createLineSpine(i + 1, true);\n        }\n    }\n}\n","import { inject, injectable } from 'tsyringe';\nimport { ISlotConfiguration } from '../../slot-configuration/ISlotConfiguration';\nimport SpinAnalyzer from '../data/SpinAnalyzer';\nimport RootStore from '../root/RootStore';\nimport LinesView from './LinesView';\n\n@injectable()\nexport default class LinesViewDesktop extends LinesView {\n    constructor(\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('RootStore') protected rootStore: RootStore,\n        @inject('SpinAnalyzer') protected spinAnalyzer: SpinAnalyzer,\n    ) {\n        super(slotConfiguration, rootStore, spinAnalyzer);\n        this.linesXPosition = 502;\n        this.linesYPosition = 289;\n\n        this.animType = 'Desktop';\n    }\n\n    // protected assemblyLinesImages(): void {\n    //     super.assemblyLinesImages();\n    //     this.linesLayer.scale = new Point(this.slotConfiguration.linesScale, this.slotConfiguration.linesScale);\n    //     this.linesLayer.x += 6;\n    //     this.squaresLayer.scale = new Point(this.slotConfiguration.symbolScale, this.slotConfiguration.symbolScale);\n    //     this.lightsLayer.scale = new Point(this.slotConfiguration.symbolScale, this.slotConfiguration.symbolScale);\n    // }\n\n    // protected createSymbolSprite(row: number, col: number): Sprite {\n    //     const symbolSprite: Sprite = new Sprite();\n    //     const offsetX: number = -8;\n    //     const offsetY: number = -8;\n    //     symbolSprite.x =\n    //         (offsetX + (this.rootStore.subjects.REELS_POSITION.value.reelWidth + this.rootStore.subjects.REELS_POSITION.value.reelSpacing) * row) *\n    //         (1.006 + (1 - this.slotConfiguration.symbolScale));\n    //     symbolSprite.y =\n    //         (offsetY + this.rootStore.subjects.REELS_POSITION.value.symbolHeight * col) * (1.004 + (1 - this.slotConfiguration.symbolScale));\n    //     return symbolSprite;\n    // }\n\n    // protected getAnimationType():string\n    // {\n    //     return 'Desktop';\n    // }\n}\n","import { BaseController } from '@egt/core';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport RestoreResponse from '../data/RestoreResponse';\nimport Features from '../feature/Features';\nimport RootStore from '../root/RootStore';\n\n@injectable()\nexport default class RestoreController extends BaseController {\n    protected restoreResponse: any;\n\n    constructor(@inject('RootStore') protected rootStore: RootStore) {\n        super(undefined);\n        this.rootStore.subjects.FEATURE_FINISHED.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onFeatureFinishedHandler.bind(this),\n        );\n        this.rootStore.subjects.RESTORE_BET.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.onBetChangedHandler.bind(this),\n        );\n\n        this.rootStore.subjects.RESTORE.chainSubscribe(Features.RESTORE, this.onRestore.bind(this));\n    }\n    protected onFeatureFinishedHandler(feature: Features): void {\n        if (this.restoreResponse && feature !== Features.CASCADE_TOTAL_MULTIPLIER) {\n            this.rootStore.subjects.RESTORE.priorities.resetPointer();\n            this.rootStore.subjects.RESTORE.next({\n                entries: this.restoreResponse.entries,\n                reels: this.restoreResponse.reels,\n            });\n        }\n    }\n\n    protected onRestore(): void {\n        if (this.restoreResponse) {\n            this.rootStore.uiStore.drawNow = true;\n            this.rootStore.uiStore.REAL_REELS.next(this.restoreResponse.reels);\n        }\n        this.restoreResponse = undefined;\n        this.rootStore.subjects.TINT_REELS.next(false);\n        this.rootStore.domainStore.SPIN_MODE.next(Features.MANUAL_SPIN);\n        if (\n            this.rootStore.domainStore.betResponse &&\n            this.rootStore.domainStore.betResponse.restoreResponse &&\n            !this.rootStore.domainStore.betResponse.restoreResponse.alreadyRestored\n        ) {\n            this.rootStore.domainStore.betResponse.restoreResponse.alreadyRestored = true;\n        }\n        this.rootStore.subjects.RESTORE.executorComplete();\n    }\n\n    protected onBetChangedHandler(response: RestoreResponse): void {\n        //  window.console.log(\"********CONTROLLER REELS STOPPED\", response)\n\n        this.restoreResponse = response;\n    }\n}\n","import Core, { BaseStore, BusMessage, ErrorTypes, FeatureFlags, Timers } from '@egt/core';\r\nimport { FEATURE_FLAG_GROUPS } from 'core/features/custom-react/src/egt/feature-flags/featureFlagGroups';\r\nimport { resolveFlagDescription } from 'core/features/custom-react/src/egt/feature-flags/resolveFlagDescription';\r\nimport { resolveFlagState } from 'core/features/custom-react/src/egt/feature-flags/resolveFlagState';\r\nimport { Howl } from 'howler';\r\nimport { SpineParser, TextureAtlas } from 'pixi-spine';\r\nimport { BaseTexture, Loader, LoaderResource, RenderTexture, Sprite, Spritesheet, Texture } from 'pixi.js';\r\nimport { BehaviorSubject } from 'rxjs';\r\nimport { filter } from 'rxjs/operators';\r\nimport { Logger } from 'unicorn.console-logger';\r\nimport { ISlotConfiguration } from '../../slot-configuration/ISlotConfiguration';\r\nimport ServerState from '../data/ServerState';\r\nimport SlotComponents from '../enums/SlotComponents';\r\nimport UIState from '../ui/UIState';\r\nimport RootStore from './RootStore';\r\n\r\nexport default class CustomResultStore extends BaseStore {\r\n    public readonly isActive: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\r\n    public readonly isRngActive: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\r\n    public readonly rngValues: BehaviorSubject<number[]> = new BehaviorSubject<number[]>([]);\r\n    public readonly selectedImageIndex: BehaviorSubject<number> = new BehaviorSubject<number>(0);\r\n    public readonly isDrag: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\r\n    public readonly isGuardSymbolsAvailableForChange: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\r\n    public readonly reelImageIndexes: BehaviorSubject<number[][]> = new BehaviorSubject<number[][]>([]);\r\n    public readonly horizontalReelImageIndex: BehaviorSubject<number[]> = new BehaviorSubject<number[]>([]);\r\n    public readonly isInfinityPlayButtonActive: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\r\n    public readonly isDebugSounds: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\r\n    public readonly isMultilayeredBackgroundSoundsPanelEnabled: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(\r\n        false,\r\n    );\r\n    public readonly isScenarioButtonActive: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\r\n    public readonly isSpeedButtonShown: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\r\n    public readonly isDRGRespin: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\r\n    public readonly isDRGPick: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\r\n    public readonly isHighCashFreespinsChoice: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\r\n    public readonly isHighCashWheelChoice: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\r\n    public readonly highCashRespinWheelValue: BehaviorSubject<number> = new BehaviorSubject<number>(-1);\r\n    public readonly isHighCashRespinWheelRetrigger: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\r\n    public readonly multislamValue: BehaviorSubject<number> = new BehaviorSubject<number>(-1);\r\n    public readonly isCustomGamble: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\r\n    public readonly scenarioImageIndexes: BehaviorSubject<number[][][]> = new BehaviorSubject<number[][][]>([]); // pages of reels\r\n    public readonly scenarioNextPage: BehaviorSubject<number> = new BehaviorSubject<number>(0); // current page index in request\r\n    public readonly isAutoPlayFeatures: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);\r\n    public readonly isFreeSpinsChoiceResult: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);\r\n    public readonly isGAKLJackpotFeatureResult: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\r\n    public readonly isBLBoostJackpotTrigger: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\r\n    public readonly isCustomDemoFeatureResult: BehaviorSubject<{ feature: string; customValue: boolean }> =\r\n        new BehaviorSubject<{ feature: string; customValue: boolean }>({ feature: '', customValue: false });\r\n    public readonly symbolsPerReel: BehaviorSubject<number[]> = new BehaviorSubject<number[]>([]);\r\n    public readonly scenarioSymbolsPerReel: BehaviorSubject<number[][]> = new BehaviorSubject<number[][]>([]);\r\n    public readonly leprechaunWheelFeatures: BehaviorSubject<any[]> = new BehaviorSubject<any[]>([false, false]);\r\n\r\n    // DIFF ADDED LATER////////////////////////////////////////\r\n    public readonly copyLastResponseActive: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\r\n    public readonly areShieldValuesActive: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\r\n    public readonly shieldValues: BehaviorSubject<number[]> = new BehaviorSubject<number[]>([]);\r\n    public readonly isDisconnectButtonAdded: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\r\n    public readonly isConsoleButtonAdded: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\r\n    public readonly isFpsToggled: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\r\n    public readonly isSoundReplaceAdded: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\r\n    public readonly isMediaInfoShown: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\r\n    public readonly isBonusButtonActive: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\r\n    public readonly isFpsShown: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\r\n    public readonly isMystery: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\r\n    public readonly isDownloadPaytableButtonShown: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\r\n\r\n    // DIFF ADDED LATER ENDS//////////////////////////////////\r\n\r\n    public readonly pearlyBeachFeatures: BehaviorSubject<{\r\n        activator?: boolean;\r\n        wildReplace?: boolean;\r\n        potSymbol?: boolean;\r\n        coolerSymbol?: boolean;\r\n        characterMarks?: boolean;\r\n        maxWin?: boolean;\r\n    }> = new BehaviorSubject<{\r\n        activator?: boolean;\r\n        wildReplace?: boolean;\r\n        potSymbol?: boolean;\r\n        coolerSymbol?: boolean;\r\n        characterMarks?: boolean;\r\n        maxWin?: boolean;\r\n    }>({\r\n        activator: false,\r\n        wildReplace: false,\r\n        potSymbol: false,\r\n        coolerSymbol: false,\r\n        characterMarks: false,\r\n        maxWin: false,\r\n    });\r\n    public readonly advancedLogging: BehaviorSubject<boolean>;\r\n    // ===== Win Animations Preview (dev tool) START =====\r\n    public readonly WIN_ANIMATIONS_PREVIEW_ACTIVE: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\r\n    public readonly WIN_ANIMATIONS_EXPAND_PREVIEW_ACTIVE: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(\r\n        false,\r\n    );\r\n    // ===== Win Animations Preview (dev tool) END =====\r\n    public scenarioAllPage = 0; // page count\r\n    public scenarioIndexPage = 0; // current page index in custom\r\n    public scenarioName: string = '';\r\n    public scenarioPageSymbols: number[] = []; // symbols per reel\r\n    public scenarioID = -1;\r\n    public mysteryType = 'MINI';\r\n    public scenarioList: any[] = [];\r\n    public scenarioListIndex: number = -1;\r\n\r\n    // BOT SETTINGS//////\r\n    public playGamble: number = 50;\r\n    public gambleRedBlack: number = 50;\r\n    public gambleCollect: number = 50;\r\n    public changeBet: number = 50;\r\n    public fastStop: number = 50;\r\n    public betSpeed: number = 50;\r\n\r\n    //////////////////////\r\n\r\n    // ANIMATION STATE\r\n    private animationObjectsArray: any[] = [];\r\n    private selectedVideoConfig: any = null;\r\n    private selectedVideoIdInAssets: string = '';\r\n    private selectedVideoExportName: string = '';\r\n\r\n    // SPINE STATE\r\n    private selectedSpineName: string = '';\r\n    private selectedSpineResource: any = null;\r\n    private selectedSpineUrl: string = '';\r\n\r\n    // SPRITESHEET STATE\r\n    private selectedSpritesheetAssetId: string = '';\r\n    private selectedSpritesheetResource: any = null;\r\n\r\n    // BOT STATE\r\n    // Bot wait between two actions, in ms. Bet Speed (0-100%) maps linearly onto this range:\r\n    // 0% waits BOT_MAX_WAIT_MS, 100% waits BOT_MIN_WAIT_MS. Bounded on purpose - the previous\r\n    // `600 + 800 / betSpeed` grew without limit at low speeds and never fired at 0.\r\n    private static readonly BOT_MIN_WAIT_MS: number = 300;\r\n    private static readonly BOT_MAX_WAIT_MS: number = 3000;\r\n    // How long the bot waits after a click for the game to react (state change or server message)\r\n    // before it re-evaluates what to do. See botDoClick.\r\n    private static readonly BOT_STALL_WAIT_MS: number = 2000;\r\n    private botTimer: any;\r\n    private botMysteryIndexes: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];\r\n    private botActiveButton: any;\r\n    private botCurrentBetIndex: number = 1;\r\n    private botStateSubscription: any = null;\r\n    private botMessageSubscription: any = null;\r\n    private botView: any = null;\r\n    private botSpinButton: any = null;\r\n    private botStopButton: any = null;\r\n\r\n    constructor(\r\n        private rootStore: RootStore,\r\n        private slotConfiguration: ISlotConfiguration,\r\n    ) {\r\n        super();\r\n        const urlParams = new URLSearchParams(window.location.href);\r\n        const enableAdvancedLog = urlParams.get('advancedLog') === 'true';\r\n        this.advancedLogging = new BehaviorSubject<boolean>(enableAdvancedLog);\r\n        this.enableLogging();\r\n        const reelImageIndexes: number[][] = [[]];\r\n        const symbolsPerReel: number[] = [];\r\n        let horizontalReelImageIndex: number[] = [];\r\n        const length: number = this.getDefaultSymbolsLength();\r\n\r\n        for (let reel = 0; reel < this.rootStore.subjects.NUMBER_OF_REELS.value; reel++) {\r\n            reelImageIndexes.push([]);\r\n            for (let i = 0; i < length; i++) {\r\n                reelImageIndexes[reel].push(0);\r\n                symbolsPerReel.push(0);\r\n            }\r\n        }\r\n\r\n        this.scenarioPageSymbols[0] = this.getDefaultSymbolsLength();\r\n        this.reelImageIndexes.next(reelImageIndexes);\r\n        this.symbolsPerReel.next(symbolsPerReel);\r\n        if (Core.hasComponent(SlotComponents.HORIZONTAL_REEL)) {\r\n            horizontalReelImageIndex = [0, 0, 0, 0, 0, 0];\r\n        }\r\n        this.horizontalReelImageIndex.next(horizontalReelImageIndex);\r\n    }\r\n\r\n    get rngRequest(): any {\r\n        if (!this.isRngActive.value) {\r\n            return null;\r\n        }\r\n        return this.rngValues.value;\r\n    }\r\n\r\n    get request(): any {\r\n        if (!this.isActive.value) {\r\n            return null;\r\n        }\r\n        this.scenarioNextPage.next(this.scenarioNextPage.value + 1);\r\n\r\n        if (this.scenarioListIndex > -1 && this.scenarioList.length > 0) {\r\n            if (this.scenarioID === -1) {\r\n                this.loadScenarioFromList(this.scenarioListIndex);\r\n            } else if (\r\n                this.scenarioListIndex < this.scenarioList.length - 1 &&\r\n                this.scenarioNextPage.value > this.scenarioAllPage\r\n            ) {\r\n                this.scenarioListIndex++;\r\n                this.loadScenarioFromList(this.scenarioListIndex);\r\n            } else if (this.scenarioListIndex === this.scenarioList.length - 1) {\r\n                this.scenarioListIndex = -1;\r\n                this.scenarioList = [];\r\n                this.scenarioID = -1;\r\n            }\r\n        }\r\n        // If all pages passed return custom result\r\n        if (this.isScenarioButtonActive.value && this.scenarioNextPage.value > this.scenarioAllPage) {\r\n            this.isActive.next(false);\r\n            this.isScenarioButtonActive.next(false);\r\n            this.sendScenarioStateUpdate();\r\n\r\n            return null;\r\n        }\r\n\r\n        // Fill scenario data\r\n        if (this.isScenarioButtonActive.value && this.scenarioImageIndexes.value.length > 0) {\r\n            const pageIndex = this.scenarioNextPage.value - 1;\r\n            const pageReels = this.scenarioImageIndexes.value[pageIndex];\r\n            const pageSymbolsPerReel = this.scenarioSymbolsPerReel.value\r\n                ? this.scenarioSymbolsPerReel.value[pageIndex]\r\n                : null;\r\n            if (pageReels && pageSymbolsPerReel) {\r\n                this.symbolsPerReel.next(pageSymbolsPerReel);\r\n                const result = this.enforceLengthConstraints(pageReels, this.symbolsPerReel.value);\r\n                this.reelImageIndexes.next(result);\r\n            }\r\n        }\r\n        let sendArr: number[][] = JSON.parse(JSON.stringify(this.reelImageIndexes.value));\r\n\r\n        const spr = this.symbolsPerReel.value;\r\n        if (spr.length > 0) {\r\n            sendArr = this.enforceLengthConstraints(sendArr, spr);\r\n        }\r\n\r\n        if (!this.slotConfiguration.customSendGuards) {\r\n            sendArr.forEach((arr) => {\r\n                arr.shift();\r\n                arr.pop();\r\n            });\r\n        }\r\n        return sendArr;\r\n    }\r\n\r\n    public enforceLengthConstraints(arrayOfIndexes, lengthConstraints) {\r\n        // Ensure both arrays are of the same length\r\n        if (arrayOfIndexes.length !== lengthConstraints.length) {\r\n            throw new Error('Both input arrays must have the same length.');\r\n        }\r\n\r\n        // Iterate through each subarray in arrayOfIndexes\r\n        for (let i = 0; i < arrayOfIndexes.length; i++) {\r\n            const maxLength = lengthConstraints[i]; // Get the max length for the current subarray\r\n\r\n            if (Array.isArray(arrayOfIndexes[i])) {\r\n                // Truncate the subarray to the maximum length\r\n                arrayOfIndexes[i] = arrayOfIndexes[i].slice(0, maxLength);\r\n\r\n                // Pad with 0 at the front to match the reel grid (new symbols are added above)\r\n                while (arrayOfIndexes[i].length < maxLength) {\r\n                    arrayOfIndexes[i].unshift(0);\r\n                }\r\n            }\r\n        }\r\n\r\n        return arrayOfIndexes;\r\n    }\r\n\r\n    private static readonly VARIABLE_REEL_GAME_TYPES = ['CASCADE_WAYS_SLOT', 'JUMBO_WAYS_SLOT'];\r\n    private static readonly MIN_VISIBLE_SYMBOLS = 2;\r\n\r\n    private isVariableReelGame(): boolean {\r\n        return CustomResultStore.VARIABLE_REEL_GAME_TYPES.includes(this.slotConfiguration.gameType);\r\n    }\r\n\r\n    private getDefaultSymbolsLength(): number {\r\n        const guardSymbols = this.rootStore.subjects.NUMBER_OF_GUARD_SYMBOLS.value;\r\n        if (this.isVariableReelGame()) {\r\n            return CustomResultStore.MIN_VISIBLE_SYMBOLS + guardSymbols;\r\n        }\r\n        return this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value + guardSymbols;\r\n    }\r\n\r\n    //this is necessary for uneven reels cases - e.g. 3x4x3 matrix and using the universal reels component so that the custom symbols are displayed properly\r\n    private getNumberOfSymbols(reelIndex: number): number {\r\n        if (this.isVariableReelGame()) {\r\n            return CustomResultStore.MIN_VISIBLE_SYMBOLS + this.rootStore.subjects.NUMBER_OF_GUARD_SYMBOLS.value;\r\n        }\r\n        let res = 0;\r\n        if (Core.hasComponent(SlotComponents.UNIVERSAL_REELS)) {\r\n            res = this.rootStore.subjects.UNIVERSAL_SYMBOLS_PER_REEL.value[reelIndex];\r\n        } else {\r\n            res = this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value;\r\n        }\r\n        return res + this.rootStore.subjects.NUMBER_OF_GUARD_SYMBOLS.value;\r\n    }\r\n\r\n    // Restore default reels\r\n    public restoreReels(): void {\r\n        const reelImageIndexes: number[][] = [];\r\n        const horizontalReelImageIndex: number[] = [];\r\n        const symbolsPerReel: number[] = [];\r\n        this.scenarioPageSymbols[this.scenarioIndexPage] = this.getDefaultSymbolsLength();\r\n\r\n        for (let reel = 0; reel < this.rootStore.subjects.NUMBER_OF_REELS.value; reel++) {\r\n            reelImageIndexes[reel] = [];\r\n            symbolsPerReel.push(this.getNumberOfSymbols(reel));\r\n\r\n            for (let i = 0; i < this.getNumberOfSymbols(reel); i++) {\r\n                reelImageIndexes[reel][i] = 0;\r\n            }\r\n        }\r\n        if (Core.hasComponent(SlotComponents.HORIZONTAL_REEL)) {\r\n            for (let i = 0; i < this.horizontalReelImageIndex.value.length; i++) {\r\n                horizontalReelImageIndex.push(0);\r\n            }\r\n\r\n            reelImageIndexes.push(horizontalReelImageIndex);\r\n        }\r\n        this.reelImageIndexes.next(reelImageIndexes);\r\n        this.symbolsPerReel.next(symbolsPerReel);\r\n    }\r\n\r\n    public setStartCustom(): void {\r\n        this.scenarioAllPage = 1;\r\n        this.scenarioIndexPage = 0;\r\n        this.scenarioName = '';\r\n        this.scenarioPageSymbols = [];\r\n        this.scenarioID = -1;\r\n        this.scenarioList = [];\r\n        this.scenarioListIndex = -1;\r\n        this.scenarioPageSymbols[0] = this.getDefaultSymbolsLength();\r\n        this.restoreReels();\r\n    }\r\n\r\n    // Set custom number of reels per page - In case of BellLink for example\r\n    public setScenarioSymbolsPerPage(val: number): void {\r\n        this.scenarioPageSymbols[this.scenarioIndexPage] = val + this.rootStore.subjects.NUMBER_OF_GUARD_SYMBOLS.value;\r\n\r\n        const newReelImages: number[][] = [];\r\n        const symbolsPerReel: number[] = [];\r\n\r\n        for (let i = 0; i < this.rootStore.subjects.NUMBER_OF_REELS.value; i++) {\r\n            newReelImages[i] = [];\r\n            for (let j = 0; j < this.scenarioPageSymbols[this.scenarioIndexPage]; j++) {\r\n                newReelImages[i][j] = 0;\r\n            }\r\n            symbolsPerReel.push(this.scenarioPageSymbols[this.scenarioIndexPage]);\r\n        }\r\n        const scenario = this.scenarioImageIndexes.value;\r\n        scenario[this.scenarioIndexPage] = newReelImages;\r\n        this.scenarioImageIndexes.next(scenario);\r\n        const scenarioSymbolsPerReel = this.scenarioSymbolsPerReel.value;\r\n        scenarioSymbolsPerReel[this.scenarioIndexPage] = newReelImages[this.scenarioIndexPage];\r\n        this.scenarioSymbolsPerReel.next(scenarioSymbolsPerReel);\r\n\r\n        this.reelImageIndexes.next(newReelImages);\r\n    }\r\n\r\n    // Scenario next page\r\n    public scenarioNext(): void {\r\n        this.scenarioIndexPage += 1;\r\n\r\n        if (this.scenarioImageIndexes.value.length > this.scenarioIndexPage) {\r\n            this.reelImageIndexes.next(this.scenarioImageIndexes.value[this.scenarioIndexPage]);\r\n            this.symbolsPerReel.next(this.scenarioSymbolsPerReel.value[this.scenarioIndexPage]);\r\n        } else {\r\n            this.scenarioPageSymbols[this.scenarioIndexPage] = this.getDefaultSymbolsLength();\r\n            this.restoreReels();\r\n            const scenario = this.scenarioImageIndexes.value;\r\n            scenario[this.scenarioIndexPage] = this.reelImageIndexes.value;\r\n            this.scenarioImageIndexes.next(scenario);\r\n\r\n            const scenarioSymbolsPerReel = this.scenarioSymbolsPerReel.value;\r\n            scenarioSymbolsPerReel[this.scenarioIndexPage] = this.symbolsPerReel.value;\r\n            this.scenarioSymbolsPerReel.next(scenarioSymbolsPerReel);\r\n            this.scenarioAllPage += 1;\r\n        }\r\n    }\r\n\r\n    // Scenario prev page\r\n    public scenarioPrev(): void {\r\n        if (this.scenarioIndexPage > 0) {\r\n            this.scenarioIndexPage -= 1;\r\n            this.reelImageIndexes.next(this.scenarioImageIndexes.value[this.scenarioIndexPage]);\r\n\r\n            this.symbolsPerReel.next(this.scenarioSymbolsPerReel.value[this.scenarioIndexPage]);\r\n        }\r\n    }\r\n    public copyStep(): void {\r\n        this.scenarioIndexPage += 1;\r\n\r\n        const currStep = this.scenarioImageIndexes.value[this.scenarioIndexPage - 1];\r\n        const scenario = this.scenarioImageIndexes.value;\r\n        scenario.splice(this.scenarioIndexPage + 1, 0, currStep);\r\n        this.scenarioImageIndexes.next(scenario);\r\n\r\n        const currScenarioStep = this.scenarioSymbolsPerReel.value[this.scenarioIndexPage - 1];\r\n        const scenarioSymbolsPerReel = this.scenarioSymbolsPerReel.value;\r\n        scenarioSymbolsPerReel.splice(this.scenarioIndexPage + 1, 0, currScenarioStep);\r\n        this.scenarioAllPage += 1;\r\n\r\n        this.scenarioPageSymbols.splice(\r\n            this.scenarioIndexPage + 1,\r\n            0,\r\n            this.scenarioPageSymbols[this.scenarioIndexPage],\r\n        );\r\n\r\n        this.symbolsPerReel.next(this.symbolsPerReel.value);\r\n    }\r\n\r\n    public deleteStep(): void {\r\n        if (this.scenarioAllPage === 1) {\r\n            return;\r\n        }\r\n        this.scenarioAllPage -= 1;\r\n        if (this.scenarioIndexPage > -1) {\r\n            this.scenarioPageSymbols.splice(this.scenarioIndexPage, 1);\r\n\r\n            const scenario = this.scenarioImageIndexes.value;\r\n            scenario.splice(this.scenarioIndexPage, 1);\r\n\r\n            this.scenarioImageIndexes.next(scenario);\r\n            this.reelImageIndexes.next(this.scenarioImageIndexes.value[this.scenarioIndexPage]);\r\n            this.symbolsPerReel.next(this.scenarioSymbolsPerReel.value[this.scenarioIndexPage]);\r\n        } else {\r\n            this.newScenario();\r\n        }\r\n    }\r\n\r\n    // Set new scenario\r\n    public newScenario(): void {\r\n        this.restoreReels();\r\n        this.scenarioPageSymbols = [this.getDefaultSymbolsLength()];\r\n        this.scenarioImageIndexes.next([this.reelImageIndexes.value]);\r\n        this.scenarioSymbolsPerReel.next([this.symbolsPerReel.value]);\r\n        this.scenarioName = 'Custom';\r\n        this.scenarioIndexPage = 0;\r\n        this.scenarioAllPage = 1;\r\n        this.scenarioNextPage.next(0);\r\n        this.scenarioID = -1;\r\n        this.isActive.next(true);\r\n    }\r\n\r\n    public escape(val): string {\r\n        return val.replace(/[\\\"]/g, '/\"').replace(/[\\/]/g, '\\\\');\r\n    }\r\n\r\n    public unescape(val): string {\r\n        return val.replace(/[\\\\]/g, '');\r\n    }\r\n\r\n    // Load scenario to edit\r\n    public loadTextScenario(file): void {\r\n        const rawFile = new XMLHttpRequest();\r\n        rawFile.overrideMimeType('application/json');\r\n        rawFile.open(\r\n            'GET',\r\n            Core.configuration.scenarioHost +\r\n                'casinos/' +\r\n                Core.configuration.casinoId +\r\n                '/games/' +\r\n                Core.configuration.gameKey +\r\n                '/scenarios/' +\r\n                file,\r\n            true,\r\n        );\r\n        rawFile.onreadystatechange = (e: any) => {\r\n            if (e.target.readyState === 4 && e.target.status === 200) {\r\n                // this.isScenarioButtonActive.next(true);\r\n                const responseStr = unescape(e.target.responseText);\r\n                const jsonData = JSON.parse(responseStr);\r\n                const scenarioData = JSON.parse(jsonData.data.replace('/\\\\', ''));\r\n                this.scenarioImageIndexes.next(scenarioData.scenarioImageIndexes);\r\n                this.scenarioSymbolsPerReel.next(scenarioData.scenarioSymbolsPerReel);\r\n\r\n                this.scenarioAllPage = scenarioData.scenarioAllPage;\r\n                this.scenarioPageSymbols = scenarioData.scenarioPageSymbols;\r\n                this.scenarioName = scenarioData.scenarioName;\r\n                this.isActive.next(true);\r\n                this.scenarioNextPage.next(0);\r\n                this.scenarioID = file;\r\n                this.reelImageIndexes.next(this.scenarioImageIndexes.value[0]);\r\n                this.symbolsPerReel.next(this.scenarioSymbolsPerReel.value[0]);\r\n            }\r\n        };\r\n        rawFile.send();\r\n    }\r\n\r\n    // Load scenario to edit\r\n    public addScenarioToList(file): void {\r\n        const rawFile = new XMLHttpRequest();\r\n        rawFile.overrideMimeType('application/json');\r\n        rawFile.open(\r\n            'GET',\r\n            Core.configuration.scenarioHost +\r\n                'casinos/' +\r\n                Core.configuration.casinoId +\r\n                '/games/' +\r\n                Core.configuration.gameKey +\r\n                '/scenarios/' +\r\n                file,\r\n            true,\r\n        );\r\n        rawFile.onreadystatechange = (e: any) => {\r\n            if (e.target.readyState === 4 && e.target.status === 200) {\r\n                // this.isScenarioButtonActive.next(true);\r\n                const responseStr = unescape(e.target.responseText);\r\n                const jsonData = JSON.parse(responseStr);\r\n                const scenarioData = JSON.parse(jsonData.data.replace('/\\\\', ''));\r\n                scenarioData.id = file;\r\n\r\n                this.scenarioList.push(scenarioData);\r\n                this.isActive.next(true);\r\n                this.scenarioListIndex = 0;\r\n            }\r\n        };\r\n        rawFile.send();\r\n    }\r\n\r\n    public removeScenarioFromList(id): void {\r\n        this.scenarioList.forEach((scenario, index) => {\r\n            if (scenario.id === id) {\r\n                this.scenarioList.splice(index, 1);\r\n            }\r\n        });\r\n        if (this.scenarioList.length === 0) {\r\n            this.scenarioListIndex = -1;\r\n        }\r\n    }\r\n\r\n    public loadScenarioFromList(index): void {\r\n        const scenarioData = this.scenarioList[index];\r\n        this.scenarioImageIndexes.next(scenarioData.scenarioImageIndexes);\r\n        this.scenarioSymbolsPerReel.next(scenarioData.scenarioSymbolsPerReel);\r\n        this.scenarioAllPage = scenarioData.scenarioAllPage;\r\n        this.scenarioPageSymbols = scenarioData.scenarioPageSymbols;\r\n        this.scenarioName = scenarioData.scenarioName;\r\n        this.isActive.next(true);\r\n        this.scenarioNextPage.next(1);\r\n        this.scenarioID = scenarioData.id;\r\n        this.scenarioIndexPage = 0;\r\n        this.reelImageIndexes.next(this.scenarioImageIndexes.value[0]);\r\n        this.symbolsPerReel.next(this.scenarioSymbolsPerReel.value[0]);\r\n    }\r\n\r\n    // ── Custom-app message listeners ──\r\n\r\n    private customAppUnsubscribes: (() => void)[] = [];\r\n\r\n    public initCustomAppListeners(): void {\r\n        this.destroyCustomAppListeners();\r\n\r\n        // Load stored reels once on init — sessionStorage is scoped per window/tab,\r\n        // so each game window keeps its own stored symbols\r\n        let storedReels: number[][] | null = null;\r\n        try {\r\n            const raw = window.sessionStorage.getItem(Core.configuration.gameKey);\r\n            storedReels = raw === null ? null : JSON.parse(raw);\r\n        } catch (_e) {\r\n            storedReels = null;\r\n        }\r\n        if (storedReels !== null) {\r\n            this.reelImageIndexes.next(storedReels);\r\n            this.isActive.next(true);\r\n            const symbolsPerReel: number[] = [];\r\n            storedReels.forEach((reel: number[]) => symbolsPerReel.push(reel.length));\r\n            this.symbolsPerReel.next(symbolsPerReel);\r\n        }\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('REQUEST_SYMBOLS', () => {\r\n                const symbolsData = this.slotConfiguration.symbolsConfig\r\n                    .filter((sym: any) => !sym.hiddenForCustom)\r\n                    .map((sym: any) => {\r\n                        const spriteID = sym.spriteID || 'symbols';\r\n                        let imageUrl = '';\r\n                        try {\r\n                            imageUrl = Core.assets.getAsset(spriteID).children[0].url;\r\n                        } catch {\r\n                            /* asset not loaded yet */\r\n                        }\r\n\r\n                        let frame: any = null;\r\n                        let topFrame: any = null;\r\n                        try {\r\n                            const spriteFrame = sym.texture\r\n                                ? Core.assets.getHTMLSpriteImage(spriteID, sym.texture)\r\n                                : null;\r\n                            if (spriteFrame) {\r\n                                frame = {\r\n                                    x: spriteFrame.frame.x,\r\n                                    y: spriteFrame.frame.y,\r\n                                    width: spriteFrame.frame.width,\r\n                                    height: spriteFrame.frame.height,\r\n                                    rotate: spriteFrame.rotate || 0,\r\n                                };\r\n                            }\r\n                            const topTextureName = sym.topTexture || sym.onTopTexture;\r\n                            const topSpriteFrame = topTextureName\r\n                                ? Core.assets.getHTMLSpriteImage(spriteID, topTextureName)\r\n                                : null;\r\n                            if (topSpriteFrame) {\r\n                                topFrame = {\r\n                                    x: topSpriteFrame.frame.x,\r\n                                    y: topSpriteFrame.frame.y,\r\n                                    width: topSpriteFrame.frame.width,\r\n                                    height: topSpriteFrame.frame.height,\r\n                                    rotate: topSpriteFrame.rotate || 0,\r\n                                };\r\n                            }\r\n                        } catch {\r\n                            /* no texture */\r\n                        }\r\n\r\n                        return {\r\n                            index: sym.index,\r\n                            texture: sym.texture,\r\n                            topTexture: sym.topTexture || sym.onTopTexture,\r\n                            spriteID,\r\n                            imageUrl,\r\n                            frame,\r\n                            topFrame,\r\n                            value: sym.value,\r\n                        };\r\n                    });\r\n                Core.customAppService.send('SYMBOLS_DATA', symbolsData);\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('REQUEST_REELS_CONFIG', () => {\r\n                const numberOfReels = this.rootStore.subjects.NUMBER_OF_REELS.value;\r\n                const visibleSymbolsPerReel = this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value;\r\n                const guardSymbols = this.rootStore.subjects.NUMBER_OF_GUARD_SYMBOLS.value;\r\n\r\n                Core.customAppService.send('REELS_CONFIG', {\r\n                    numberOfReels,\r\n                    visibleSymbolsPerReel,\r\n                    guardSymbols,\r\n                    symbolsPerReel: this.symbolsPerReel.value,\r\n                    reelImageIndexes: this.reelImageIndexes.value,\r\n                    gameType: this.slotConfiguration.gameType,\r\n                    maxSymbolsPerReel: visibleSymbolsPerReel + guardSymbols,\r\n                    horizontalReelImageIndex: this.horizontalReelImageIndex.value,\r\n                    hasStoredResult: this.isActive.value,\r\n                    gameKey: Core.configuration.gameKey,\r\n                });\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('STORE_SYMBOLS', () => {\r\n                try {\r\n                    window.sessionStorage.setItem(\r\n                        Core.configuration.gameKey,\r\n                        JSON.stringify(this.reelImageIndexes.value),\r\n                    );\r\n                } catch (_e) {\r\n                    /* session storage unavailable */\r\n                }\r\n                Core.customAppService.send('STORE_SYMBOLS_RESULT', {\r\n                    success: true,\r\n                    message: 'Symbols stored successfully.',\r\n                });\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('RESET_REELS', () => {\r\n                try {\r\n                    window.sessionStorage.removeItem(Core.configuration.gameKey);\r\n                } catch (_e) {\r\n                    /* session storage unavailable */\r\n                }\r\n                // Also clear any stored reels for this game from localStorage\r\n                // (e.g. entries left over from before the per-window storage change)\r\n                Core.localStorage.removeSetting(Core.configuration.gameKey);\r\n                this.restoreReels();\r\n                this.isActive.next(false);\r\n\r\n                const numberOfReels = this.rootStore.subjects.NUMBER_OF_REELS.value;\r\n                const visibleSymbolsPerReel = this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value;\r\n                const guardSymbols = this.rootStore.subjects.NUMBER_OF_GUARD_SYMBOLS.value;\r\n\r\n                Core.customAppService.send('REELS_CONFIG', {\r\n                    numberOfReels,\r\n                    visibleSymbolsPerReel,\r\n                    guardSymbols,\r\n                    symbolsPerReel: this.symbolsPerReel.value,\r\n                    reelImageIndexes: this.reelImageIndexes.value,\r\n                    gameType: this.slotConfiguration.gameType,\r\n                    maxSymbolsPerReel: visibleSymbolsPerReel + guardSymbols,\r\n                    gameKey: Core.configuration.gameKey,\r\n                });\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SET_CUSTOM_SETUP', (msg: BusMessage) => {\r\n                this.isActive.next(!!msg.payload);\r\n            }),\r\n        );\r\n\r\n        // The game itself can flip the custom setup (long-pressing the custom button),\r\n        // so push every change to the app to keep its Reels \"Activate\" toggle in sync\r\n        const isActiveSubscription = this.isActive.subscribe((active: boolean) => {\r\n            Core.customAppService.send('CUSTOM_SETUP_STATE', active);\r\n        });\r\n        this.customAppUnsubscribes.push(() => isActiveSubscription.unsubscribe());\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SET_CUSTOM_DRAG', (msg: BusMessage) => {\r\n                this.isDrag.next(!!msg.payload);\r\n            }),\r\n        );\r\n\r\n        // The app copies the response itself — a click inside the iframe leaves this\r\n        // window unfocused, so a clipboard write from here would be rejected. It is\r\n        // pushed after every bet so the app's Copy Bet click can write it at once.\r\n        const sendLastBetResponse = () => {\r\n            const serverBetResponse = this.rootStore.domainStore?.serverBetResponse;\r\n            const hasResponse = serverBetResponse && Object.keys(serverBetResponse).length > 0;\r\n            Core.customAppService.send('LAST_BET_RESPONSE', hasResponse ? JSON.stringify(serverBetResponse) : null);\r\n        };\r\n        this.customAppUnsubscribes.push(Core.customAppService.on('REQUEST_LAST_BET_RESPONSE', sendLastBetResponse));\r\n        const betSubscription = this.rootStore.domainStore?.BET.subscribe(sendLastBetResponse);\r\n        this.customAppUnsubscribes.push(() => betSubscription?.unsubscribe());\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('UPDATE_REEL_CELL', (msg: BusMessage) => {\r\n                const { reel, row, symbolIndex } = msg.payload;\r\n                const newReelImages = this.reelImageIndexes.value.slice();\r\n                if (newReelImages[reel]) {\r\n                    newReelImages[reel] = [...newReelImages[reel]];\r\n                    newReelImages[reel][row] = symbolIndex;\r\n                    this.reelImageIndexes.next(newReelImages);\r\n                }\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('UPDATE_HORIZONTAL_REEL_CELL', (msg: BusMessage) => {\r\n                const { row, symbolIndex } = msg.payload;\r\n                const newHorizontal = [...this.horizontalReelImageIndex.value];\r\n                if (row >= 0 && row < newHorizontal.length) {\r\n                    newHorizontal[row] = symbolIndex;\r\n                    this.horizontalReelImageIndex.next(newHorizontal);\r\n                    // Also update the extra column in reelImageIndexes\r\n                    const reelIdx = this.rootStore.subjects.NUMBER_OF_REELS.value;\r\n                    const newReelImages = this.reelImageIndexes.value.slice();\r\n                    if (newReelImages[reelIdx]) {\r\n                        newReelImages[reelIdx] = [...newHorizontal];\r\n                        this.reelImageIndexes.next(newReelImages);\r\n                    }\r\n                }\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('UPDATE_FULL_REELS', (msg: BusMessage) => {\r\n                const reelImageIndexes = msg.payload as number[][];\r\n                if (Array.isArray(reelImageIndexes)) {\r\n                    this.reelImageIndexes.next(reelImageIndexes.map((reel) => [...reel]));\r\n                }\r\n            }),\r\n        );\r\n\r\n        // Push factor + selectedBet on every bet change and on initial load\r\n        const sendSettings = () => {\r\n            Core.customAppService.send('SETTINGS_DATA', {\r\n                factor: this.rootStore.settings.factor,\r\n                selectedBet: this.rootStore.uiStore.SELECTED_BET.value,\r\n            });\r\n        };\r\n\r\n        const betSub = this.rootStore.uiStore.SELECTED_BET.subscribe(() => {\r\n            sendSettings();\r\n        });\r\n        this.customAppUnsubscribes.push(() => betSub.unsubscribe());\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('REQUEST_SETTINGS', () => {\r\n                sendSettings();\r\n            }),\r\n        );\r\n\r\n        // ── Settings tab handlers ──\r\n\r\n        const sendSettingsState = () => {\r\n            Core.customAppService.send('SETTINGS_STATE', {\r\n                isDownloadActive: Core.IS_DOWNLOAD_BUTTON_ACTIVE.value,\r\n                isAnimSpeedShown: this.isSpeedButtonShown.value,\r\n                isAdvancedLogging: this.advancedLogging.value,\r\n                isSlotGame: true,\r\n            });\r\n        };\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('REQUEST_SETTINGS_STATE', () => {\r\n                sendSettingsState();\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SETTING_DISCONNECT', (msg: BusMessage) => {\r\n                const errorCode = msg.payload as string;\r\n                if (errorCode && errorCode !== '') {\r\n                    (Core.connection as any)._transport.ws.close(\r\n                        Number(errorCode),\r\n                        'Test error code ' + Number(errorCode),\r\n                    );\r\n                } else {\r\n                    (Core.connection as any)._transport.ws.close(3000, 'Test disconnection');\r\n                }\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SETTING_TOGGLE_CONSOLE', () => {\r\n                Core.devTools?.toggleConsole(true);\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SETTING_TOGGLE_FPS', () => {\r\n                Core.devTools?.toggleFpsInfo(true);\r\n                const perfInfo = document.getElementById('perf-info');\r\n                if (perfInfo) {\r\n                    perfInfo.className = perfInfo.className.replace('hidden', '').trim();\r\n                }\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SETTING_TOGGLE_METRICS', () => {\r\n                Core.devTools?.toggleMetricsDebug(true);\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SETTING_TOGGLE_DOWNLOAD', () => {\r\n                Core.IS_DOWNLOAD_BUTTON_ACTIVE.next(!Core.IS_DOWNLOAD_BUTTON_ACTIVE.value);\r\n                sendSettingsState();\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SETTING_TOGGLE_ANIM_SPEED', () => {\r\n                this.isSpeedButtonShown.next(!this.isSpeedButtonShown.value);\r\n                sendSettingsState();\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SETTING_TOGGLE_ADVANCED_LOG', () => {\r\n                this.updateAdvancedLogging(!this.advancedLogging.value);\r\n                sendSettingsState();\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SETTING_OPEN_SCALER', () => {\r\n                Core.devTools?.OPEN_CUSTOM_SCALER.next();\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('REQUEST_MEDIA_INFO', () => {\r\n                Core.customAppService.send('MEDIA_INFO', {\r\n                    devicePixelRatio: window.devicePixelRatio,\r\n                    viewWidth: Core.display.view.width.toFixed(0),\r\n                    viewHeight: Core.display.view.height.toFixed(0),\r\n                    screenWidth: Core.display.screen.width.toFixed(0),\r\n                    screenHeight: Core.display.screen.height.toFixed(0),\r\n                    currentWidth: Core.display.stage.currentWidth.toFixed(0),\r\n                    currentHeight: Core.display.stage.currentHeight.toFixed(0),\r\n                    scaleX: Core.display.stage.scaleX,\r\n                    scaleY: Core.display.stage.scaleY,\r\n                    scaling: Core.display.stage.scaling,\r\n                    alignment: Core.display.stage.alignment,\r\n                    orientation: Core.ORIENTATION.value.orientation,\r\n                    browser: Core.environment.getBrowser().name + ' ' + Core.environment.getBrowser().major,\r\n                    fullScreen: Core.environment.isFullScreenSupported().toString(),\r\n                    os: Core.environment.getOS().name + ' ' + Core.environment.getOS().version,\r\n                });\r\n            }),\r\n        );\r\n\r\n        // ── Feature Flags tab handlers ──\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('REQUEST_FEATURE_FLAGS', () => {\r\n                const persisted = Core.flags.getConfiguredFlags();\r\n                const persistedRecord: Record<string, boolean> = {};\r\n                persisted.forEach((isActive, flag) => {\r\n                    persistedRecord[flag] = isActive;\r\n                });\r\n                Core.customAppService.send('FEATURE_FLAGS_DATA', {\r\n                    groups: FEATURE_FLAG_GROUPS.map((group) => ({\r\n                        label: group.label,\r\n                        flags: group.flags.map((flag) => {\r\n                            const state = resolveFlagState(flag);\r\n                            return {\r\n                                flag,\r\n                                // Same seed rule as the in-game Feature Flags tab: persisted config first, live value otherwise\r\n                                seed: persisted.has(flag) ? persisted.get(flag) : state.checked,\r\n                                errored: state.errored,\r\n                                description: resolveFlagDescription(flag),\r\n                            };\r\n                        }),\r\n                    })),\r\n                    persisted: persistedRecord,\r\n                });\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('FEATURE_FLAGS_APPLY', (msg: BusMessage) => {\r\n                const record = msg.payload as Record<FeatureFlags, boolean>;\r\n                Core.flags.setConfiguredFlags(new Map(Object.entries(record) as [FeatureFlags, boolean][]));\r\n                window.location.reload();\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('FEATURE_FLAGS_RESET', () => {\r\n                Core.flags.clearConfiguredFlags();\r\n                window.location.reload();\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('UPDATE_SYMBOLS_PER_REEL', (msg: BusMessage) => {\r\n                const newSymbolsPerReel = msg.payload as number[];\r\n                if (Array.isArray(newSymbolsPerReel)) {\r\n                    this.symbolsPerReel.next([...newSymbolsPerReel]);\r\n                    const newReelImages = this.reelImageIndexes.value.map((reel, idx) => {\r\n                        const target = newSymbolsPerReel[idx];\r\n                        if (target === undefined) return [...reel];\r\n                        if (reel.length === target) return [...reel];\r\n                        if (reel.length < target) {\r\n                            return [...Array(target - reel.length).fill(0), ...reel];\r\n                        }\r\n                        return reel.slice(0, target);\r\n                    });\r\n                    this.reelImageIndexes.next(newReelImages);\r\n                }\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('REQUEST_ANIMATION_DATA', () => {\r\n                const symbolsConfig =\r\n                    this.slotConfiguration.symbolsConfig.filter((asset: any) => asset.hasOwnProperty('video')) || [];\r\n                const otherAnimations =\r\n                    this.slotConfiguration.assets.filter((asset: any) => asset.hasOwnProperty('videoConfig')) || [];\r\n\r\n                let objectsArray: any[];\r\n                if (otherAnimations.length) {\r\n                    const lastIndex = symbolsConfig.length > 0 ? symbolsConfig[symbolsConfig.length - 1].index : -1;\r\n                    const mapped = otherAnimations.map((asset: any, i: number) => ({\r\n                        ...asset,\r\n                        index: lastIndex + 1 + i,\r\n                        name: asset.id,\r\n                    }));\r\n                    objectsArray = [...symbolsConfig, ...mapped];\r\n                } else {\r\n                    objectsArray = symbolsConfig;\r\n                }\r\n\r\n                const animationEntries: any[] = [];\r\n                objectsArray.forEach((obj: any) => {\r\n                    animationEntries.push({ name: obj.name, type: 'video' });\r\n                    if (obj.videoOn) {\r\n                        animationEntries.push({ name: obj.videoOn.id, type: 'videoOn' });\r\n                    }\r\n                    if (obj.expandVideo) {\r\n                        animationEntries.push({ name: obj.expandVideo.id, type: 'expandVideo' });\r\n                    }\r\n                    if (obj.videoBonusWin) {\r\n                        animationEntries.push({ name: obj.videoBonusWin.id, type: 'videoBonusWin' });\r\n                    }\r\n                    if (obj.anticipationAnim) {\r\n                        animationEntries.push({ name: obj.anticipationAnim.id, type: 'anticipationAnim' });\r\n                    }\r\n                    if (obj.idleAnim) {\r\n                        animationEntries.push({ name: obj.idleAnim.id, type: 'idleAnim' });\r\n                    }\r\n                    if (obj.triggerVideo) {\r\n                        animationEntries.push({ name: obj.triggerVideo.id, type: 'triggerVideo' });\r\n                    }\r\n                });\r\n\r\n                Core.customAppService.send('ANIMATION_DATA', animationEntries);\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SELECT_ANIMATION', (msg: BusMessage) => {\r\n                const selectedName = msg.payload as string;\r\n                if (!selectedName) {\r\n                    this.selectedVideoConfig = null;\r\n                    this.selectedVideoIdInAssets = '';\r\n                    this.selectedVideoExportName = '';\r\n                    Core.customAppService.send('ANIMATION_CONFIG', null);\r\n                    return;\r\n                }\r\n\r\n                this.buildAnimationObjectsArray();\r\n\r\n                const video = this.animationObjectsArray.find(\r\n                    (obj: any) => obj.name === selectedName || obj.videoOn?.id === selectedName,\r\n                );\r\n                const expandVideo = this.animationObjectsArray.find((obj: any) => obj.expandVideo?.id === selectedName);\r\n                const videoBonusWin = this.animationObjectsArray.find(\r\n                    (obj: any) => obj.videoBonusWin?.id === selectedName,\r\n                );\r\n                const idleAnim = this.animationObjectsArray.find((obj: any) => obj.idleAnim?.id === selectedName);\r\n                const anticipationAnim = this.animationObjectsArray.find(\r\n                    (obj: any) => obj.anticipationAnim?.id === selectedName,\r\n                );\r\n                const triggerVideo = this.animationObjectsArray.find(\r\n                    (obj: any) => obj.triggerVideo?.id === selectedName,\r\n                );\r\n\r\n                if (videoBonusWin?.videoBonusWin) {\r\n                    this.selectedVideoConfig = videoBonusWin.videoBonusWin;\r\n                } else if (expandVideo?.expandVideo) {\r\n                    this.selectedVideoConfig = expandVideo.expandVideo;\r\n                } else if (idleAnim) {\r\n                    this.selectedVideoConfig = idleAnim.idleAnim;\r\n                } else if (video) {\r\n                    this.selectedVideoConfig =\r\n                        video.videoConfig ?? (video.videoOn?.id === selectedName ? video.videoOn : video.video);\r\n                } else if (anticipationAnim) {\r\n                    this.selectedVideoConfig = anticipationAnim.anticipationAnim;\r\n                } else if (triggerVideo) {\r\n                    this.selectedVideoConfig = triggerVideo.triggerVideo;\r\n                } else {\r\n                    this.selectedVideoConfig = null;\r\n                }\r\n\r\n                if (!this.selectedVideoConfig) {\r\n                    Core.customAppService.send('ANIMATION_CONFIG', null);\r\n                    return;\r\n                }\r\n\r\n                const videoId = this.selectedVideoConfig.id;\r\n                this.selectedVideoIdInAssets = videoId;\r\n\r\n                let exportName = '';\r\n                try {\r\n                    const asset = Core.assets.getAsset(videoId);\r\n                    const singleOrArray = asset.length !== undefined ? asset[0] : asset;\r\n                    exportName =\r\n                        singleOrArray.data?.meta?.image?.replace(/\\.(png|webp)$/i, '').replace(/-\\d+$/, '') || videoId;\r\n                } catch {\r\n                    /* asset not loaded yet */\r\n                }\r\n                this.selectedVideoExportName = exportName;\r\n\r\n                this.sendAnimationConfig();\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('UPDATE_VIDEO_CONFIG', (msg: BusMessage) => {\r\n                if (!this.selectedVideoConfig) return;\r\n                const { field, value } = msg.payload;\r\n                (this.selectedVideoConfig as any)[field] = value;\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('REPLACE_ANIMATION_TEXTURES', async (msg: BusMessage) => {\r\n                const { imageDataUrls } = msg.payload as { imageDataUrls: string[] };\r\n                if (!imageDataUrls?.length || !this.selectedVideoIdInAssets) {\r\n                    Core.customAppService.send('ANIMATION_OPERATION_RESULT', {\r\n                        operation: 'replace',\r\n                        success: false,\r\n                        message: 'No images or no animation selected.',\r\n                    });\r\n                    return;\r\n                }\r\n\r\n                try {\r\n                    const images: HTMLImageElement[] = [];\r\n                    for (const dataUrl of imageDataUrls) {\r\n                        const img = await this.loadImageFromDataUrl(dataUrl);\r\n                        images.push(img);\r\n                    }\r\n\r\n                    // Update video config to match uploaded frames\r\n                    if (this.selectedVideoConfig) {\r\n                        this.selectedVideoConfig.length = images.length;\r\n                        this.selectedVideoConfig.width = images[0].width;\r\n                        this.selectedVideoConfig.height = images[0].height;\r\n                    }\r\n\r\n                    const spritesheetData = this.generateSpritesheet(images, 2048);\r\n                    const selectedVideoAsset = this.slotConfiguration.assets.filter(\r\n                        (item: any) => item.id === this.selectedVideoIdInAssets,\r\n                    );\r\n\r\n                    if (Array.isArray(spritesheetData)) {\r\n                        const loader = new Loader();\r\n                        spritesheetData.forEach(({ spritesheet }, index) => {\r\n                            loader.add(`spritesheet${index}`, spritesheet);\r\n                        });\r\n                        const tempURL: string[] = [];\r\n                        loader.load((_loader, resources) => {\r\n                            const spritesheetResources: any[] = [];\r\n                            spritesheetData.forEach(({ data }, index) => {\r\n                                const resource = resources[`spritesheet${index}`];\r\n                                if (resource && resource.texture) {\r\n                                    const sheet = new Spritesheet(resource.texture.baseTexture, data as any);\r\n                                    sheet.parse(() => {\r\n                                        resource.data = sheet.data;\r\n                                        resource.textures = sheet.textures;\r\n                                        resource.spritesheet = sheet;\r\n                                        spritesheetResources.push(resource);\r\n                                        if (spritesheetResources.length === spritesheetData.length) {\r\n                                            Core.assets.loadedAssets.set(\r\n                                                this.selectedVideoIdInAssets,\r\n                                                spritesheetResources,\r\n                                            );\r\n                                            this.sendAnimationReplaceResult(true, 'Animation replaced successfully.');\r\n                                            this.sendAnimationConfig();\r\n                                        }\r\n                                    });\r\n                                }\r\n                                if (selectedVideoAsset?.length) {\r\n                                    const url0 = selectedVideoAsset[0].url;\r\n                                    if (typeof url0 === 'string') {\r\n                                        tempURL.push(url0.replace(/(\\.json)$/, `-${index}$1`));\r\n                                    } else {\r\n                                        const first = url0[0].replace('-0', '');\r\n                                        tempURL.push(first.replace(/(\\.json)$/, `-${index}$1`));\r\n                                    }\r\n                                }\r\n                            });\r\n                            if (selectedVideoAsset?.length) {\r\n                                selectedVideoAsset[0].url = tempURL;\r\n                            }\r\n                        });\r\n                    } else {\r\n                        const { spritesheet, data } = spritesheetData;\r\n                        const loader = new Loader();\r\n                        loader.add('spritesheet', spritesheet);\r\n                        loader.load((_loader, resources) => {\r\n                            const spritesheetResource = resources.spritesheet;\r\n                            if (spritesheetResource && spritesheetResource.texture) {\r\n                                const sheet = new Spritesheet(spritesheetResource.texture.baseTexture, data as any);\r\n                                sheet.parse(() => {\r\n                                    resources.spritesheet.data = data;\r\n                                    resources.spritesheet.textures = sheet.textures;\r\n                                    resources.spritesheet.spritesheet = sheet;\r\n                                });\r\n                                // @ts-ignore\r\n                                Core.assets.loadedAssets.set(this.selectedVideoIdInAssets, resources.spritesheet);\r\n                            }\r\n                            if (selectedVideoAsset?.length && typeof selectedVideoAsset[0].url === 'object') {\r\n                                selectedVideoAsset[0].url = selectedVideoAsset[0].url[0].replace('-0', '');\r\n                            }\r\n                            this.sendAnimationReplaceResult(true, 'Animation replaced successfully.');\r\n                            this.sendAnimationConfig();\r\n                        });\r\n                    }\r\n                } catch (error) {\r\n                    Core.customAppService.send('ANIMATION_OPERATION_RESULT', {\r\n                        operation: 'replace',\r\n                        success: false,\r\n                        message: `Error: ${error}`,\r\n                    });\r\n                }\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('FTP_UPLOAD_ANIMATION', async () => {\r\n                if (!this.selectedVideoIdInAssets) {\r\n                    Core.customAppService.send('ANIMATION_OPERATION_RESULT', {\r\n                        operation: 'ftpUpload',\r\n                        success: false,\r\n                        message: 'No animation selected.',\r\n                    });\r\n                    return;\r\n                }\r\n                try {\r\n                    if (!this.selectedVideoExportName) {\r\n                        const asset = Core.assets.getAsset(this.selectedVideoIdInAssets);\r\n                        const singleAsset = Array.isArray(asset) ? asset[0] : asset;\r\n                        this.selectedVideoExportName = singleAsset.data.meta.image\r\n                            .replace(/\\.(png|webp)$/i, '')\r\n                            .replace(/-\\d+$/, '');\r\n                    }\r\n\r\n                    // Collect textures from all spritesheets (handles both single resource and array of resources)\r\n                    const loadedAsset: any = Core.assets.loadedAssets.get(this.selectedVideoIdInAssets);\r\n                    let textures: Record<string, any> = {};\r\n                    if (Array.isArray(loadedAsset)) {\r\n                        for (const resource of loadedAsset) {\r\n                            if (resource.textures) {\r\n                                Object.assign(textures, resource.textures);\r\n                            }\r\n                        }\r\n                    } else if (loadedAsset && loadedAsset.textures) {\r\n                        textures = loadedAsset.textures;\r\n                    }\r\n\r\n                    const blobs = await this.texturesToBlobs(textures);\r\n                    const entries = Object.entries(textures);\r\n                    const formData = new FormData();\r\n                    blobs.forEach((blob: Blob, index: number) => {\r\n                        const [key] = entries[index];\r\n                        formData.append('images[]', blob, key);\r\n                    });\r\n                    const temp = (window as any).ssi.CustomResourcesHost.split('/');\r\n                    const taskPath = temp[temp.length - 2];\r\n                    formData.append(\r\n                        'customurl',\r\n                        `/sounds/${taskPath}/assets/${Core.configuration.gameKey}/animations/`,\r\n                    );\r\n                    formData.append('filename', this.selectedVideoExportName);\r\n\r\n                    const response = await Core.requestManager.post(\r\n                        Core.configuration.assetPackHost + 'generateSpritesheetMulti',\r\n                        formData,\r\n                    );\r\n                    if (response && response.status >= 200 && response.status < 300) {\r\n                        Core.customAppService.send('ANIMATION_OPERATION_RESULT', {\r\n                            operation: 'ftpUpload',\r\n                            success: true,\r\n                            message: `Success: ${response.data.message}`,\r\n                        });\r\n                    } else {\r\n                        Core.customAppService.send('ANIMATION_OPERATION_RESULT', {\r\n                            operation: 'ftpUpload',\r\n                            success: false,\r\n                            message: 'FTP upload failed.',\r\n                        });\r\n                    }\r\n                } catch (error) {\r\n                    Core.customAppService.send('ANIMATION_OPERATION_RESULT', {\r\n                        operation: 'ftpUpload',\r\n                        success: false,\r\n                        message: `Fetch error: ${error}`,\r\n                    });\r\n                }\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('FTP_UPLOAD_VIDEO_CONFIG', async () => {\r\n                this.buildAnimationObjectsArray();\r\n                try {\r\n                    const configText = JSON.stringify(this.animationObjectsArray);\r\n                    const formData = new FormData();\r\n                    const textBlob = new Blob([configText], { type: 'text/plain' });\r\n                    const fileName = Core.configuration.gameKey + 'VideosConfig.json';\r\n                    const temp = (window as any).ssi.CustomResourcesHost.split('/');\r\n                    const taskPath = temp[temp.length - 2];\r\n                    formData.append(\r\n                        'customurl',\r\n                        `/sounds/${taskPath}/assets/${Core.configuration.gameKey}/animations/`,\r\n                    );\r\n                    formData.append('files[]', textBlob, fileName);\r\n\r\n                    const response = await Core.requestManager.post(\r\n                        Core.configuration.assetPackHost + 'uploadToFTP',\r\n                        formData,\r\n                    );\r\n                    if (response && response.status >= 200 && response.status < 300) {\r\n                        Core.customAppService.send('ANIMATION_OPERATION_RESULT', {\r\n                            operation: 'ftpUploadConfig',\r\n                            success: true,\r\n                            message: `Success: ${response.data.message}`,\r\n                        });\r\n                    } else {\r\n                        Core.customAppService.send('ANIMATION_OPERATION_RESULT', {\r\n                            operation: 'ftpUploadConfig',\r\n                            success: false,\r\n                            message: 'FTP config upload failed.',\r\n                        });\r\n                    }\r\n                } catch (error) {\r\n                    Core.customAppService.send('ANIMATION_OPERATION_RESULT', {\r\n                        operation: 'ftpUploadConfig',\r\n                        success: false,\r\n                        message: `Fetch error: ${error}`,\r\n                    });\r\n                }\r\n            }),\r\n        );\r\n\r\n        // ── Feature handlers ──\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('REQUEST_FEATURES_DATA', () => {\r\n                const availableFeatures: string[] = [];\r\n                const featureStates: Record<string, any> = {};\r\n\r\n                // Always-available features\r\n                availableFeatures.push('autoplay');\r\n                featureStates.autoplay = this.isAutoPlayFeatures.value;\r\n\r\n                availableFeatures.push('rng');\r\n                featureStates.rng = {\r\n                    enabled: this.isRngActive.value,\r\n                    values: this.rngValues.value,\r\n                };\r\n\r\n                // Conditional features\r\n                if (Core.hasFeature('GAMBLE')) {\r\n                    availableFeatures.push('gamble');\r\n                    featureStates.gamble = this.isCustomGamble.value;\r\n                }\r\n\r\n                if (Core.hasFeature('MYSTERY_JACKPOT') || Core.hasFeature('SCRATCH_MYSTERY_JACKPOT')) {\r\n                    availableFeatures.push('mystery');\r\n                    featureStates.mystery = { levelId: 4 };\r\n                }\r\n                if (Core.hasFeature('PREMIUM_LINK_JACKPOT')) {\r\n                    availableFeatures.push('premiumLink');\r\n                    featureStates.premiumLink = { levelId: 3 };\r\n                }\r\n\r\n                if (Core.hasFeature('MULTI_REELS_ANIMATIONS')) {\r\n                    availableFeatures.push('multislam');\r\n                    featureStates.multislam = this.multislamValue.value;\r\n                }\r\n\r\n                if (Core.hasFeature('ACTIVATOR')) {\r\n                    availableFeatures.push('pearlyBeach');\r\n                    featureStates.pearlyBeach = this.pearlyBeachFeatures.value;\r\n                }\r\n\r\n                if (Core.hasFeature('HIGH_CASH_PICKER')) {\r\n                    availableFeatures.push('highCashPick');\r\n                    featureStates.highCashPick = this.isDRGPick.value;\r\n                }\r\n\r\n                if (Core.hasFeature('HIGH_CASH_RESPIN')) {\r\n                    availableFeatures.push('highCashRespin');\r\n                    featureStates.highCashRespin = this.isDRGRespin.value;\r\n                }\r\n\r\n                if (Core.hasFeature('HIGH_CASH_RESPIN_CREDIT_WHEEL')) {\r\n                    availableFeatures.push('highCashMSHC');\r\n                    featureStates.highCashMSHC = {\r\n                        freeSpins: this.isHighCashFreespinsChoice.value,\r\n                        wheelChoice: this.isHighCashWheelChoice.value,\r\n                        wheelRetrigger: this.isHighCashRespinWheelRetrigger.value,\r\n                        wheelValue: this.highCashRespinWheelValue.value,\r\n                    };\r\n                }\r\n\r\n                if (Core.hasFeature('WHEEL')) {\r\n                    availableFeatures.push('leprechaunWheel');\r\n                    featureStates.leprechaunWheel = this.leprechaunWheelFeatures.value;\r\n                }\r\n\r\n                if (Core.hasFeature('BL_BOOST_JACKPOT')) {\r\n                    availableFeatures.push('blBoostJackpot');\r\n                    featureStates.blBoostJackpot = this.isBLBoostJackpotTrigger.value;\r\n                }\r\n\r\n                // Game-key specific features\r\n                const gameKey = Core.configuration.gameKey;\r\n                if (['ALGKLSlot', 'ALGKLVSlot'].includes(gameKey)) {\r\n                    availableFeatures.push('algklPickACoin');\r\n                    featureStates.algklPickACoin = {\r\n                        freeSpins: this.isFreeSpinsChoiceResult.value,\r\n                        gaklJackpot: this.isGAKLJackpotFeatureResult.value,\r\n                    };\r\n                }\r\n\r\n                if (['PRRJWSlot'].includes(gameKey)) {\r\n                    availableFeatures.push('raFeature');\r\n                    featureStates.raFeature = this.isCustomDemoFeatureResult.value.customValue;\r\n                }\r\n\r\n                // RNG presets from config\r\n                let rngPresets: Array<{ name: string; values: string }> = [];\r\n                try {\r\n                    if (Core.gameDependencyContainer.isRegistered('ISlotConfiguration')) {\r\n                        const config: any = Core.gameDependencyContainer.resolve('ISlotConfiguration');\r\n                        rngPresets = config?.rngPresets || [];\r\n                    }\r\n                } catch {\r\n                    /* no config */\r\n                }\r\n\r\n                Core.customAppService.send('FEATURES_DATA', {\r\n                    availableFeatures,\r\n                    featureStates,\r\n                    gameKey,\r\n                    rngPresets,\r\n                });\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('UPDATE_FEATURE', (msg: BusMessage) => {\r\n                const { feature, value } = msg.payload as { feature: string; value: any };\r\n\r\n                switch (feature) {\r\n                    case 'autoplay':\r\n                        this.isAutoPlayFeatures.next(value);\r\n                        break;\r\n                    case 'gamble':\r\n                        this.isCustomGamble.next(value);\r\n                        break;\r\n                    case 'multislam':\r\n                        this.multislamValue.next(Number(value));\r\n                        break;\r\n                    case 'rngEnabled':\r\n                        this.isRngActive.next(value);\r\n                        if (!value) {\r\n                            this.rngValues.next([]);\r\n                        }\r\n                        break;\r\n                    case 'rngValues':\r\n                        this.rngValues.next(value);\r\n                        break;\r\n                    case 'pearlyBeach':\r\n                        this.pearlyBeachFeatures.next(value);\r\n                        break;\r\n                    case 'highCashPick': {\r\n                        this.isDRGPick.next(value);\r\n                        if (value) this.isDRGRespin.next(false);\r\n                        break;\r\n                    }\r\n                    case 'highCashRespin': {\r\n                        this.isDRGRespin.next(value);\r\n                        if (value) this.isDRGPick.next(false);\r\n                        break;\r\n                    }\r\n                    case 'highCashFreeSpins': {\r\n                        this.isHighCashFreespinsChoice.next(value);\r\n                        if (value) this.isHighCashWheelChoice.next(false);\r\n                        break;\r\n                    }\r\n                    case 'highCashWheelChoice': {\r\n                        this.isHighCashWheelChoice.next(value);\r\n                        if (value) this.isHighCashFreespinsChoice.next(false);\r\n                        break;\r\n                    }\r\n                    case 'highCashWheelRetrigger':\r\n                        this.isHighCashRespinWheelRetrigger.next(value);\r\n                        break;\r\n                    case 'highCashWheelValue':\r\n                        this.highCashRespinWheelValue.next(Number(value));\r\n                        break;\r\n                    case 'leprechaunWheel':\r\n                        this.leprechaunWheelFeatures.next(value);\r\n                        break;\r\n                    case 'blBoostJackpot':\r\n                        this.isBLBoostJackpotTrigger.next(value);\r\n                        break;\r\n                    case 'algklFreeSpins': {\r\n                        this.isFreeSpinsChoiceResult.next(value);\r\n                        this.isGAKLJackpotFeatureResult.next(!value);\r\n                        break;\r\n                    }\r\n                    case 'algklGaklJackpot': {\r\n                        this.isGAKLJackpotFeatureResult.next(value);\r\n                        this.isFreeSpinsChoiceResult.next(!value);\r\n                        break;\r\n                    }\r\n                    case 'raFeature':\r\n                        this.isCustomDemoFeatureResult.next({\r\n                            feature: 'demo.raFeature',\r\n                            customValue: value,\r\n                        });\r\n                        break;\r\n                    default:\r\n                        break;\r\n                }\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('TRIGGER_MYSTERY', (msg: BusMessage) => {\r\n                const { levelId } = msg.payload as { levelId: number };\r\n                try {\r\n                    let apiUrl = Core.configuration.host.split('/')[0];\r\n                    const appArr = apiUrl.split('-');\r\n                    const appindex = appArr.findIndex((element) => element === 'game');\r\n                    appArr[appindex] = 'jackpot';\r\n                    apiUrl = Core.configuration.protocol + '://' + appArr.join('-') + '/api/mystery/trigger/hit';\r\n\r\n                    const settings = this.rootStore.settings;\r\n                    const fullUrl =\r\n                        apiUrl +\r\n                        '?gameKey=' +\r\n                        Core.configuration.gameKey +\r\n                        '&currency=' +\r\n                        settings.currency +\r\n                        '&denomination=' +\r\n                        settings.denomination +\r\n                        '&levelId=' +\r\n                        levelId;\r\n\r\n                    const xhr = new XMLHttpRequest();\r\n                    xhr.open('GET', fullUrl);\r\n                    xhr.onreadystatechange = () => {\r\n                        if (xhr.readyState === 4) {\r\n                            Core.customAppService.send('FEATURE_OPERATION_RESULT', {\r\n                                operation: 'mystery',\r\n                                success: xhr.status === 200,\r\n                                message:\r\n                                    xhr.status === 200\r\n                                        ? 'Mystery jackpot triggered successfully.'\r\n                                        : `Mystery trigger failed with status ${xhr.status}.`,\r\n                            });\r\n                        }\r\n                    };\r\n                    xhr.send();\r\n                } catch (error) {\r\n                    Core.customAppService.send('FEATURE_OPERATION_RESULT', {\r\n                        operation: 'mystery',\r\n                        success: false,\r\n                        message: `Error: ${error}`,\r\n                    });\r\n                }\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('TRIGGER_PREMIUM_LINK', (msg: BusMessage) => {\r\n                const { levelId } = msg.payload as { levelId: number };\r\n                try {\r\n                    let apiUrl = Core.configuration.host.split('/')[0];\r\n                    const appArr = apiUrl.split('-');\r\n                    const appindex = appArr.findIndex((element) => element === 'game');\r\n                    appArr[appindex] = 'jackpot';\r\n                    apiUrl = Core.configuration.protocol + '://' + appArr.join('-') + '/api/premiumlink/win';\r\n                    const settings = this.rootStore.settings;\r\n                    const params = new URLSearchParams({\r\n                        gameKey: Core.configuration.gameKey,\r\n                        currency: settings.currency,\r\n                        denomination: settings.denomination.toString(),\r\n                        levelId: levelId.toString(),\r\n                    });\r\n                    const xhr = new XMLHttpRequest();\r\n                    xhr.open('GET', `${apiUrl}?${params.toString()}`);\r\n                    xhr.onreadystatechange = () => {\r\n                        if (xhr.readyState === 4) {\r\n                            Core.customAppService.send('FEATURE_OPERATION_RESULT', {\r\n                                operation: 'premiumLink',\r\n                                success: xhr.status === 200,\r\n                                message:\r\n                                    xhr.status === 200\r\n                                        ? 'Premium Link jackpot triggered successfully.'\r\n                                        : `Premium Link trigger failed with status ${xhr.status}.`,\r\n                            });\r\n                        }\r\n                    };\r\n                    xhr.send();\r\n                } catch (error) {\r\n                    Core.customAppService.send('FEATURE_OPERATION_RESULT', {\r\n                        operation: 'premiumLink',\r\n                        success: false,\r\n                        message: `Error: ${error}`,\r\n                    });\r\n                }\r\n            }),\r\n        );\r\n\r\n        // ── Bot handlers ──\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('REQUEST_BOT_DATA', () => {\r\n                Core.customAppService.send('BOT_DATA', {\r\n                    botActive: this.isInfinityPlayButtonActive.value,\r\n                    gambleRedBlack: this.gambleRedBlack,\r\n                    gambleCollect: this.gambleCollect,\r\n                    playGamble: this.playGamble,\r\n                    changeBet: this.changeBet,\r\n                    fastStop: this.fastStop,\r\n                    betSpeed: this.betSpeed,\r\n                });\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('UPDATE_BOT_SETTING', (msg: BusMessage) => {\r\n                const { setting, value } = msg.payload as { setting: string; value: number };\r\n                switch (setting) {\r\n                    case 'gambleRedBlack':\r\n                        this.gambleRedBlack = value;\r\n                        break;\r\n                    case 'gambleCollect':\r\n                        this.gambleCollect = value;\r\n                        break;\r\n                    case 'playGamble':\r\n                        this.playGamble = value;\r\n                        break;\r\n                    case 'changeBet':\r\n                        this.changeBet = value;\r\n                        break;\r\n                    case 'fastStop':\r\n                        this.fastStop = value;\r\n                        break;\r\n                    case 'betSpeed':\r\n                        this.betSpeed = value;\r\n                        break;\r\n                    default:\r\n                        break;\r\n                }\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('TOGGLE_BOT', () => {\r\n                const next = !Core.isReplayer && !this.isInfinityPlayButtonActive.value;\r\n                this.isInfinityPlayButtonActive.next(next);\r\n                if (next) {\r\n                    this.startBot();\r\n                } else {\r\n                    this.stopBot();\r\n                }\r\n            }),\r\n        );\r\n\r\n        // ── Sound handlers ──\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('REQUEST_SOUND_DATA', async () => {\r\n                const soundGroups = Core.sounds.getAllSounds().map((sg: any) => ({\r\n                    id: sg.id,\r\n                    sprites: sg.sprite ? (Array.isArray(sg.sprite) ? sg.sprite : Object.keys(sg.sprite)) : [],\r\n                }));\r\n\r\n                const hasMultilayeredBgSound = Core.hasComponent(SlotComponents.MULTILAYERED_BG_SOUND);\r\n\r\n                const bgSoundConfig = Core.sounds.getBGSoundConfiguration();\r\n                const fadeConfig = Core.sounds.getBGSoundFadeConfiguration();\r\n                const inactivityConfig = Core.sounds.getBGInactivityTimeConfiguration();\r\n\r\n                let soundAssetGroupIds: string[] = [];\r\n                if (this.slotConfiguration && (this.slotConfiguration as any).assets) {\r\n                    soundAssetGroupIds = (this.slotConfiguration as any).assets\r\n                        .filter((a: any) => a.type === 'sound')\r\n                        .map((a: any) => a.id);\r\n                }\r\n\r\n                const hasSSI = Core.customResourcesHost;\r\n                const gameKey = Core.configuration.gameKey;\r\n\r\n                let lineSounds: string[] = [];\r\n                if (this.slotConfiguration && this.slotConfiguration.symbolsConfig) {\r\n                    const winSounds = new Set<string>();\r\n                    const expandSounds = new Set<string>();\r\n                    const fullLineSounds = new Set<string>();\r\n                    for (const s of this.slotConfiguration.symbolsConfig) {\r\n                        if (s.winSound) winSounds.add(s.winSound);\r\n                        if (s.expandSound) expandSounds.add(s.expandSound);\r\n                        if (s.fullLineSound) fullLineSounds.add(s.fullLineSound);\r\n                    }\r\n                    lineSounds = [...Array.from(winSounds), ...Array.from(expandSounds), ...Array.from(fullLineSounds)];\r\n                }\r\n\r\n                let versions: string[] = [];\r\n                let loopSounds: string[] = [];\r\n\r\n                if (hasSSI) {\r\n                    try {\r\n                        const host = this.getWindowSSIPath();\r\n                        const vRoute = Core.configuration.assetPackHost + 'getAllSoundVersions';\r\n                        const vResp = await Core.requestManager.post(vRoute, {\r\n                            customurl: `/sounds/${host}/assets/${gameKey}/sounds/`,\r\n                        });\r\n                        if (vResp && vResp.status >= 200 && vResp.status < 300 && vResp.data.versions) {\r\n                            versions = vResp.data.versions;\r\n                        }\r\n                    } catch (_e) {\r\n                        /* ignore */\r\n                    }\r\n\r\n                    try {\r\n                        const host = this.getWindowSSIPath();\r\n                        const lRoute = Core.configuration.assetPackHost + 'getLoopedSounds';\r\n                        const lResp = await Core.requestManager.post(lRoute, {\r\n                            customurl: `/sounds/${host}/assets/loopedSounds/`,\r\n                        });\r\n                        if (lResp && lResp.status >= 200 && lResp.status < 300 && lResp.data.loopedSounds) {\r\n                            loopSounds = lResp.data.loopedSounds;\r\n                        }\r\n                    } catch (_e) {\r\n                        /* ignore */\r\n                    }\r\n                }\r\n\r\n                const bgSoundDefaults = bgSoundConfig?.positionData?.defaults || null;\r\n\r\n                Core.customAppService.send('SOUND_DATA', {\r\n                    soundGroups,\r\n                    debugSounds: this.isDebugSounds.value,\r\n                    multiPanelEnabled: this.isMultilayeredBackgroundSoundsPanelEnabled.value,\r\n                    hasMultilayeredBgSound,\r\n                    bgSoundDefaults,\r\n                    hasBgSoundConfig: !!bgSoundConfig,\r\n                    fadeConfig,\r\n                    inactivityConfig,\r\n                    soundAssetGroupIds,\r\n                    hasSSI,\r\n                    gameKey,\r\n                    lineSounds,\r\n                    versions,\r\n                    loopSounds,\r\n                });\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SOUND_PLAY', (msg: BusMessage) => {\r\n                const soundName = msg.payload as string;\r\n                Core.sounds.stopAll();\r\n                Core.sounds.play(soundName);\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SOUND_STOP', (msg: BusMessage) => {\r\n                const soundName = msg.payload as string;\r\n                Core.sounds.stop(soundName);\r\n                Core.sounds.replaceSound(soundName, undefined);\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SOUND_REPLACE', (msg: BusMessage) => {\r\n                const { soundName, dataUrl, format } = msg.payload as {\r\n                    soundName: string;\r\n                    dataUrl: string;\r\n                    format: string;\r\n                };\r\n                const soundHowl = new Howl({\r\n                    src: dataUrl,\r\n                    format: format,\r\n                });\r\n                Core.sounds.replaceSound(soundName, soundHowl as any);\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SOUND_SET_VOLUME', (msg: BusMessage) => {\r\n                const { soundName, volume } = msg.payload as { soundName: string; volume: number };\r\n                Core.sounds.changeSoundVolume.set(soundName, volume);\r\n                Core.sounds.setVolume(soundName, volume);\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SOUND_TOGGLE_DEBUG', () => {\r\n                this.isDebugSounds.next(!this.isDebugSounds.value);\r\n                Core.sounds.debug = this.isDebugSounds.value;\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SOUND_TOGGLE_MULTI_PANEL', () => {\r\n                this.isMultilayeredBackgroundSoundsPanelEnabled.next(\r\n                    !this.isMultilayeredBackgroundSoundsPanelEnabled.value,\r\n                );\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SOUND_EXPORT_VOLUME_CONFIG', () => {\r\n                let configText = '';\r\n                Core.sounds.changeSoundVolume.forEach((key, value) => {\r\n                    configText += value + ': ' + key * 100 + '\\n';\r\n                });\r\n                Core.customAppService.send('SOUND_OPERATION_RESULT', {\r\n                    operation: 'exportVolumeConfig',\r\n                    success: true,\r\n                    data: configText,\r\n                    fileName: Core.configuration.gameKey + 'VolumeConfig.txt',\r\n                });\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SOUND_SET_BG_LINE_CONFIG', (msg: BusMessage) => {\r\n                const { bgSound, lineSound, soundConfig } = msg.payload as any;\r\n                if (lineSound === 'default') {\r\n                    Core.sounds.updateBgAllLinesSoundConfiguration({ bgSound, soundConfig });\r\n                } else {\r\n                    Core.sounds.updateBgSingleLineSoundConfiguration({ bgSound, lineSound, soundConfig });\r\n                }\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SOUND_SAVE_BG_CONFIG', () => {\r\n                const bgSoundsConfig = Core.sounds.getBGSoundConfiguration();\r\n                const configText = JSON.stringify(bgSoundsConfig?.positionData?.defaults || {});\r\n                Core.customAppService.send('SOUND_OPERATION_RESULT', {\r\n                    operation: 'saveBgConfig',\r\n                    success: true,\r\n                    data: configText,\r\n                    fileName: Core.configuration.gameKey + 'BackgroundConfig.json',\r\n                });\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SOUND_REPLACE_BG_CONFIG', (msg: BusMessage) => {\r\n                const jsonContent = msg.payload as string;\r\n                try {\r\n                    const config = JSON.parse(jsonContent);\r\n                    for (const bgSound in config) {\r\n                        const bgSoundConfig = config[bgSound];\r\n                        Core.sounds.updateBGSoundConfiguration({ bgSound, bgSoundConfig });\r\n                    }\r\n                    Core.customAppService.send('SOUND_OPERATION_RESULT', {\r\n                        operation: 'replaceBgConfig',\r\n                        success: true,\r\n                        message: 'BG config replaced successfully',\r\n                    });\r\n                } catch (e) {\r\n                    Core.customAppService.send('SOUND_OPERATION_RESULT', {\r\n                        operation: 'replaceBgConfig',\r\n                        success: false,\r\n                        message: `Error parsing config: ${e}`,\r\n                    });\r\n                }\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SOUND_FTP_UPLOAD_BG_CONFIG', async () => {\r\n                try {\r\n                    const bgSoundsConfig = Core.sounds.getBGSoundConfiguration();\r\n                    const configText = JSON.stringify(bgSoundsConfig?.positionData?.defaults || {});\r\n                    const textBlob = new Blob([configText], { type: 'text/plain' });\r\n                    const fileName = Core.configuration.gameKey + 'BackgroundConfig.json';\r\n\r\n                    const formData = new FormData();\r\n                    formData.append('files[]', textBlob, fileName);\r\n                    const host = this.getWindowSSIPath();\r\n                    formData.append(\r\n                        'customurl',\r\n                        `/sounds/${host}/assets/${Core.configuration.gameKey}/sounds/configuration/`,\r\n                    );\r\n\r\n                    const response = await Core.requestManager.post(\r\n                        Core.configuration.assetPackHost + 'uploadToFTP',\r\n                        formData,\r\n                    );\r\n                    const success = response && response.status >= 200 && response.status < 300;\r\n                    Core.customAppService.send('SOUND_OPERATION_RESULT', {\r\n                        operation: 'ftpUploadBgConfig',\r\n                        success,\r\n                        message: success ? `Success: ${response.data}` : 'Server error',\r\n                    });\r\n                } catch (e) {\r\n                    Core.customAppService.send('SOUND_OPERATION_RESULT', {\r\n                        operation: 'ftpUploadBgConfig',\r\n                        success: false,\r\n                        message: `Error: ${e}`,\r\n                    });\r\n                }\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SOUND_SET_BG_FADE', (msg: BusMessage) => {\r\n                const { fadeOut, fadeIn } = msg.payload as { fadeOut: number; fadeIn: number };\r\n                Core.sounds.updateBgSoundFadeDuration({\r\n                    backgroundMusicFadeOutDurationNew: fadeOut,\r\n                    backgroundNoPlayFadeInDurationNew: fadeIn,\r\n                });\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SOUND_SET_BG_INACTIVITY', (msg: BusMessage) => {\r\n                const duration = msg.payload as number;\r\n                Core.sounds.updateBGInactivityTimeConfiguration(duration);\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SOUND_UPLOAD_TO_FTP', async (msg: BusMessage) => {\r\n                const { files, soundGroup, version, loopSounds } = msg.payload as any;\r\n                try {\r\n                    const formData = new FormData();\r\n                    for (const f of files) {\r\n                        const resp = await fetch(f.dataUrl);\r\n                        const blob = await resp.blob();\r\n                        formData.append('sounds[]', blob, f.name);\r\n                    }\r\n                    const host = this.getWindowSSIPath();\r\n                    formData.append('customurl', `/sounds/${host}/assets/${Core.configuration.gameKey}/sounds/`);\r\n                    formData.append('filename', soundGroup);\r\n                    formData.append('loopSounds', JSON.stringify(loopSounds));\r\n                    if (version) {\r\n                        formData.append('version', version);\r\n                    }\r\n                    const route = Core.configuration.assetPackHost + 'generateAudioSprite';\r\n                    const response = await Core.requestManager.post(route, formData);\r\n                    const success = response && response.status >= 200 && response.status < 300;\r\n\r\n                    let updatedVersions: string[] = [];\r\n                    if (success && soundGroup === 'overrideSounds' && version) {\r\n                        try {\r\n                            const vRoute = Core.configuration.assetPackHost + 'getAllSoundVersions';\r\n                            const vResp = await Core.requestManager.post(vRoute, {\r\n                                customurl: `/sounds/${host}/assets/${Core.configuration.gameKey}/sounds/`,\r\n                            });\r\n                            if (vResp?.data?.versions) updatedVersions = vResp.data.versions;\r\n                        } catch (_e) {\r\n                            /* ignore */\r\n                        }\r\n                    }\r\n\r\n                    Core.customAppService.send('SOUND_OPERATION_RESULT', {\r\n                        operation: 'uploadToFtp',\r\n                        success,\r\n                        message: success ? 'Successfully uploaded to FTP server' : 'Server error',\r\n                        versions: updatedVersions.length > 0 ? updatedVersions : undefined,\r\n                    });\r\n                } catch (e) {\r\n                    Core.customAppService.send('SOUND_OPERATION_RESULT', {\r\n                        operation: 'uploadToFtp',\r\n                        success: false,\r\n                        message: `Error: ${e}`,\r\n                    });\r\n                }\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SOUND_CLEAR_FTP_ASSETS', async (msg: BusMessage) => {\r\n                const { specificDir, excludingDir } = msg.payload as { specificDir: string; excludingDir: string };\r\n                try {\r\n                    const host = this.getWindowSSIPath();\r\n                    const route = Core.configuration.assetPackHost + 'resetAllAudioSprites';\r\n                    const response = await Core.requestManager.post(route, {\r\n                        customurl: `/sounds/${host}/assets/${Core.configuration.gameKey}/sounds/`,\r\n                        specificDir,\r\n                        excludingDir,\r\n                    });\r\n                    const success = response && response.status >= 200 && response.status < 300;\r\n                    Core.customAppService.send('SOUND_OPERATION_RESULT', {\r\n                        operation: 'clearAssets',\r\n                        success,\r\n                        message: success ? 'Successfully cleared sound assets!' : 'Server error',\r\n                    });\r\n                } catch (e) {\r\n                    Core.customAppService.send('SOUND_OPERATION_RESULT', {\r\n                        operation: 'clearAssets',\r\n                        success: false,\r\n                        message: `Error: ${e}`,\r\n                    });\r\n                }\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SOUND_UPLOAD_CONFIG_FTP', async (msg: BusMessage) => {\r\n                const { files } = msg.payload as { files: Array<{ name: string; dataUrl: string }> };\r\n                try {\r\n                    const formData = new FormData();\r\n                    for (const f of files) {\r\n                        const resp = await fetch(f.dataUrl);\r\n                        const blob = await resp.blob();\r\n                        formData.append('files[]', blob, f.name);\r\n                    }\r\n                    const host = this.getWindowSSIPath();\r\n                    formData.append(\r\n                        'customurl',\r\n                        `/sounds/${host}/assets/${Core.configuration.gameKey}/sounds/configuration/`,\r\n                    );\r\n                    const route = Core.configuration.assetPackHost + 'uploadToFTP';\r\n                    const response = await Core.requestManager.post(route, formData);\r\n                    const success = response && response.status >= 200 && response.status < 300;\r\n                    Core.customAppService.send('SOUND_OPERATION_RESULT', {\r\n                        operation: 'uploadConfigFtp',\r\n                        success,\r\n                        message: success ? 'Successfully uploaded configs' : 'Server error',\r\n                    });\r\n                } catch (e) {\r\n                    Core.customAppService.send('SOUND_OPERATION_RESULT', {\r\n                        operation: 'uploadConfigFtp',\r\n                        success: false,\r\n                        message: `Error: ${e}`,\r\n                    });\r\n                }\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SOUND_UPDATE_LOOP_SOUNDS', async (msg: BusMessage) => {\r\n                const loopSounds = msg.payload as string[];\r\n                try {\r\n                    const host = this.getWindowSSIPath();\r\n                    const route = Core.configuration.assetPackHost + 'updateLoopSounds';\r\n                    const response = await Core.requestManager.post(route, {\r\n                        customurl: `/sounds/${host}/assets/loopedSounds/`,\r\n                        loopSounds: JSON.stringify(loopSounds),\r\n                    });\r\n                    const success = response && response.status >= 200 && response.status < 300;\r\n                    Core.customAppService.send('SOUND_OPERATION_RESULT', {\r\n                        operation: 'updateLoopSounds',\r\n                        success,\r\n                        message: success ? 'Loop sounds updated' : 'Server error',\r\n                    });\r\n                } catch (e) {\r\n                    Core.customAppService.send('SOUND_OPERATION_RESULT', {\r\n                        operation: 'updateLoopSounds',\r\n                        success: false,\r\n                        message: `Error: ${e}`,\r\n                    });\r\n                }\r\n            }),\r\n        );\r\n\r\n        // ── BigWin sound handlers ──\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SOUND_REQUEST_BIGWIN_DATA', () => {\r\n                try {\r\n                    if (!Core.gameDependencyContainer.isRegistered('BigWinFeatureConfiguration')) {\r\n                        Core.customAppService.send('SOUND_BIGWIN_DATA', { available: false });\r\n                        return;\r\n                    }\r\n                    const bigWinConfig = Core.gameDependencyContainer.resolve('BigWinFeatureConfiguration') as any;\r\n                    const winLinesSounds = bigWinConfig?.winLinesSounds?.bigWin || null;\r\n                    if (!winLinesSounds) {\r\n                        Core.customAppService.send('SOUND_BIGWIN_DATA', { available: false });\r\n                        return;\r\n                    }\r\n\r\n                    // Collect available line sound keys from symbolsConfig\r\n                    const bigWinLineSounds: string[] = [];\r\n                    if (this.slotConfiguration?.symbolsConfig) {\r\n                        for (const s of this.slotConfiguration.symbolsConfig) {\r\n                            const sound = s.winSound || s.expandSound;\r\n                            if (sound && winLinesSounds[sound] && !bigWinLineSounds.includes(sound)) {\r\n                                bigWinLineSounds.push(sound);\r\n                            }\r\n                        }\r\n                        // Also add fullLineSounds\r\n                        const fullLines: string[] = [];\r\n                        for (const s of this.slotConfiguration.symbolsConfig) {\r\n                            if (s.fullLineSound && !fullLines.includes(s.fullLineSound)) {\r\n                                fullLines.push(s.fullLineSound);\r\n                            }\r\n                        }\r\n                        bigWinLineSounds.push(...fullLines);\r\n                    }\r\n\r\n                    // Send the defaults for each sound\r\n                    const configMap: Record<string, any> = {};\r\n                    configMap['default'] = winLinesSounds['default'] || {\r\n                        fadeOut: { duration: 0, volume: 0 },\r\n                        delay: 0,\r\n                    };\r\n                    for (const key of bigWinLineSounds) {\r\n                        if (winLinesSounds[key]) {\r\n                            configMap[key] = winLinesSounds[key];\r\n                        }\r\n                    }\r\n\r\n                    Core.customAppService.send('SOUND_BIGWIN_DATA', {\r\n                        available: true,\r\n                        bigWinLineSounds,\r\n                        configMap,\r\n                    });\r\n                } catch (_e) {\r\n                    Core.customAppService.send('SOUND_BIGWIN_DATA', { available: false });\r\n                }\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SOUND_SET_BIGWIN_LINE_CONFIG', (msg: BusMessage) => {\r\n                const { lineSound, fadeOutDuration, fadeOutVolume, delay } = msg.payload as any;\r\n                try {\r\n                    const bigWinConfig = Core.gameDependencyContainer.resolve('BigWinFeatureConfiguration') as any;\r\n                    const winSoundsConfig = bigWinConfig.winLinesSounds;\r\n                    if (lineSound === 'default') {\r\n                        winSoundsConfig.bigWin.default.fadeOut.duration = Number(fadeOutDuration);\r\n                        winSoundsConfig.bigWin.default.fadeOut.volume = Number(fadeOutVolume);\r\n                        winSoundsConfig.bigWin.default.delay = Number(delay);\r\n                    } else {\r\n                        if (!winSoundsConfig.bigWin[lineSound].fadeOut) {\r\n                            winSoundsConfig.bigWin[lineSound].fadeOut = {\r\n                                duration: Number(fadeOutDuration),\r\n                                volume: Number(fadeOutVolume),\r\n                            };\r\n                            winSoundsConfig.bigWin[lineSound].delay = Number(delay);\r\n                        } else {\r\n                            winSoundsConfig.bigWin[lineSound].fadeOut.duration = Number(fadeOutDuration);\r\n                            winSoundsConfig.bigWin[lineSound].fadeOut.volume = Number(fadeOutVolume);\r\n                            winSoundsConfig.bigWin[lineSound].delay = Number(delay);\r\n                        }\r\n                    }\r\n                } catch (_e) {\r\n                    /* ignore */\r\n                }\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SOUND_SAVE_BIGWIN_CONFIG', () => {\r\n                try {\r\n                    const bigWinConfig = Core.gameDependencyContainer.resolve('BigWinFeatureConfiguration') as any;\r\n                    const configText = JSON.stringify(bigWinConfig.winLinesSounds.positionData.defaults);\r\n                    Core.customAppService.send('SOUND_OPERATION_RESULT', {\r\n                        operation: 'saveBigWinConfig',\r\n                        success: true,\r\n                        data: configText,\r\n                        fileName: Core.configuration.gameKey + 'BigWinConfig.json',\r\n                    });\r\n                } catch (e) {\r\n                    Core.customAppService.send('SOUND_OPERATION_RESULT', {\r\n                        operation: 'saveBigWinConfig',\r\n                        success: false,\r\n                        message: `Error: ${e}`,\r\n                    });\r\n                }\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SOUND_REPLACE_BIGWIN_CONFIG', (msg: BusMessage) => {\r\n                const jsonContent = msg.payload as string;\r\n                try {\r\n                    const config = JSON.parse(jsonContent);\r\n                    for (const bigWinSound in config) {\r\n                        const bigWinSoundConfig = config[bigWinSound];\r\n                        Core.sounds.updateBigWinConfiguration({ bigWinSound, bigWinSoundConfig });\r\n                    }\r\n                    Core.customAppService.send('SOUND_OPERATION_RESULT', {\r\n                        operation: 'replaceBigWinConfig',\r\n                        success: true,\r\n                        message: 'BigWin config replaced successfully',\r\n                    });\r\n                } catch (e) {\r\n                    Core.customAppService.send('SOUND_OPERATION_RESULT', {\r\n                        operation: 'replaceBigWinConfig',\r\n                        success: false,\r\n                        message: `Error parsing config: ${e}`,\r\n                    });\r\n                }\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SOUND_FTP_UPLOAD_BIGWIN_CONFIG', async () => {\r\n                try {\r\n                    const bigWinConfig = Core.gameDependencyContainer.resolve('BigWinFeatureConfiguration') as any;\r\n                    const configText = JSON.stringify(bigWinConfig.winLinesSounds.positionData.defaults);\r\n                    const textBlob = new Blob([configText], { type: 'text/plain' });\r\n                    const fileName = Core.configuration.gameKey + 'BigWinConfig.json';\r\n\r\n                    const formData = new FormData();\r\n                    formData.append('files[]', textBlob, fileName);\r\n                    const host = this.getWindowSSIPath();\r\n                    formData.append(\r\n                        'customurl',\r\n                        `/sounds/${host}/assets/${Core.configuration.gameKey}/sounds/configuration/`,\r\n                    );\r\n\r\n                    const response = await Core.requestManager.post(\r\n                        Core.configuration.assetPackHost + 'uploadToFTP',\r\n                        formData,\r\n                    );\r\n                    const success = response && response.status >= 200 && response.status < 300;\r\n                    Core.customAppService.send('SOUND_OPERATION_RESULT', {\r\n                        operation: 'ftpUploadBigWinConfig',\r\n                        success,\r\n                        message: success ? `Success: ${response.data}` : 'Server error',\r\n                    });\r\n                } catch (e) {\r\n                    Core.customAppService.send('SOUND_OPERATION_RESULT', {\r\n                        operation: 'ftpUploadBigWinConfig',\r\n                        success: false,\r\n                        message: `Error: ${e}`,\r\n                    });\r\n                }\r\n            }),\r\n        );\r\n\r\n        // ── Scenario handlers ──\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('REQUEST_SCENARIO_DATA', () => {\r\n                const symbols = this.slotConfiguration.symbolsConfig.map((s: any) => ({\r\n                    index: s.index,\r\n                    name: s.name,\r\n                    hiddenForCustom: !!s.hiddenForCustom,\r\n                }));\r\n\r\n                const numberOfReels = this.rootStore.subjects.NUMBER_OF_REELS.value;\r\n                const visibleSymbolsPerReel = this.rootStore.subjects.VISIBLE_SYMBOLS_PER_REEL.value;\r\n                const guardSymbolsCount = this.rootStore.subjects.NUMBER_OF_GUARD_SYMBOLS.value;\r\n                const isDesktop = Core.isDesktopMode;\r\n                const gameType = this.slotConfiguration.gameType;\r\n\r\n                Core.customAppService.send('SCENARIO_DATA', {\r\n                    symbols,\r\n                    numberOfReels,\r\n                    visibleSymbolsPerReel,\r\n                    guardSymbolsCount,\r\n                    isDesktop,\r\n                    gameType,\r\n                    maxSymbolsPerReel: visibleSymbolsPerReel + guardSymbolsCount,\r\n                    reelImageIndexes: this.reelImageIndexes.value,\r\n                    symbolsPerReel: this.symbolsPerReel.value,\r\n                    scenarioActive: this.isScenarioButtonActive.value,\r\n                    isDrag: this.isDrag.value,\r\n                    isGuardChange: this.isGuardSymbolsAvailableForChange.value,\r\n                    scenarioIndexPage: this.scenarioIndexPage,\r\n                    scenarioAllPage: this.scenarioAllPage,\r\n                    scenarioID: this.scenarioID,\r\n                });\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SCENARIO_CREATE', () => {\r\n                this.newScenario();\r\n                this.sendScenarioStateUpdate();\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SCENARIO_LOAD_LIST', () => {\r\n                const xhr = new XMLHttpRequest();\r\n                xhr.open(\r\n                    'GET',\r\n                    Core.configuration.scenarioHost +\r\n                        'casinos/' +\r\n                        Core.configuration.casinoId +\r\n                        '/games/' +\r\n                        Core.configuration.gameKey +\r\n                        '/scenarios',\r\n                    true,\r\n                );\r\n                xhr.setRequestHeader('Content-Type', 'text/json');\r\n                xhr.onreadystatechange = (e: any) => {\r\n                    if (e.target.readyState === XMLHttpRequest.DONE && e.target.status === 200) {\r\n                        const scenarios = JSON.parse(e.target.response);\r\n                        Core.customAppService.send('SCENARIO_LIST', scenarios);\r\n                    }\r\n                };\r\n                xhr.onloadend = (e: any) => {\r\n                    if (e.target.status === 404) {\r\n                        Core.customAppService.send('SCENARIO_OPERATION_RESULT', {\r\n                            operation: 'loadList',\r\n                            success: false,\r\n                            message: 'No available scenarios for this game.',\r\n                        });\r\n                    }\r\n                };\r\n                xhr.send();\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SCENARIO_SELECT_SINGLE', (msg: BusMessage) => {\r\n                const scenarioId = msg.payload as string;\r\n                this.setStartCustom();\r\n                this.loadTextScenario(scenarioId);\r\n                this.isScenarioButtonActive.next(true);\r\n                // Send state update after loading completes (async via XHR)\r\n                const checkInterval = setInterval(() => {\r\n                    if (this.scenarioID === Number(scenarioId) || this.scenarioID === scenarioId) {\r\n                        clearInterval(checkInterval);\r\n                        this.sendScenarioStateUpdate();\r\n                    }\r\n                }, 100);\r\n                setTimeout(() => clearInterval(checkInterval), 5000);\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SCENARIO_SELECT_MULTIPLE', (msg: BusMessage) => {\r\n                const scenarioId = msg.payload as string;\r\n                this.addScenarioToList(scenarioId);\r\n                this.isScenarioButtonActive.next(true);\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SCENARIO_REMOVE_FROM_LIST', (msg: BusMessage) => {\r\n                const scenarioId = msg.payload as string;\r\n                this.removeScenarioFromList(scenarioId);\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SCENARIO_NEXT', () => {\r\n                this.scenarioNext();\r\n                this.sendScenarioStateUpdate();\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SCENARIO_PREV', () => {\r\n                this.scenarioPrev();\r\n                this.sendScenarioStateUpdate();\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SCENARIO_COPY_STEP', () => {\r\n                this.copyStep();\r\n                this.sendScenarioStateUpdate();\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SCENARIO_DELETE_STEP', () => {\r\n                this.deleteStep();\r\n                this.sendScenarioStateUpdate();\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SCENARIO_SAVE', (msg: BusMessage) => {\r\n                const scenarioName = msg.payload as string | null;\r\n                if (this.scenarioID > -1) {\r\n                    // Update existing\r\n                    const scenarioObject = {\r\n                        scenarioName: this.scenarioName,\r\n                        scenarioAllPage: this.scenarioAllPage,\r\n                        scenarioImageIndexes: this.scenarioImageIndexes.value,\r\n                        scenarioSymbolsPerReel: this.scenarioSymbolsPerReel.value,\r\n                        scenarioPageSymbols: this.scenarioPageSymbols,\r\n                    };\r\n                    const data = JSON.stringify(scenarioObject);\r\n                    const xhr = new XMLHttpRequest();\r\n                    xhr.open(\r\n                        'PUT',\r\n                        Core.configuration.scenarioHost +\r\n                            'casinos/' +\r\n                            Core.configuration.casinoId +\r\n                            '/games/' +\r\n                            Core.configuration.gameKey +\r\n                            '/scenarios/' +\r\n                            this.scenarioID,\r\n                        true,\r\n                    );\r\n                    xhr.setRequestHeader('Content-Type', 'application/json');\r\n                    xhr.onreadystatechange = (e: any) => {\r\n                        if (e.target.readyState === XMLHttpRequest.DONE && e.target.status === 200) {\r\n                            Core.customAppService.send('SCENARIO_OPERATION_RESULT', {\r\n                                operation: 'save',\r\n                                success: true,\r\n                                message: 'Scenario Replaced',\r\n                            });\r\n                        }\r\n                    };\r\n                    const sendParams =\r\n                        '{\"name\":\"' +\r\n                        this.scenarioName +\r\n                        '\",\"data\":\"' +\r\n                        this.escape(data) +\r\n                        '\",\"casino\":\"' +\r\n                        Core.configuration.casinoId +\r\n                        '\",\"game\":\"' +\r\n                        Core.configuration.gameKey +\r\n                        '\",\"player\":\"' +\r\n                        Core.configuration.playerId +\r\n                        '\"}';\r\n                    xhr.send(sendParams);\r\n                } else if (scenarioName) {\r\n                    // New scenario\r\n                    const scenarioObject = {\r\n                        scenarioName,\r\n                        scenarioAllPage: this.scenarioAllPage,\r\n                        scenarioImageIndexes: this.scenarioImageIndexes.value,\r\n                        scenarioSymbolsPerReel: this.scenarioSymbolsPerReel.value,\r\n                        scenarioPageSymbols: this.scenarioPageSymbols,\r\n                    };\r\n                    const data = JSON.stringify(scenarioObject);\r\n                    const xhr = new XMLHttpRequest();\r\n                    xhr.open('POST', Core.configuration.scenarioHost + 'scenarios', true);\r\n                    xhr.setRequestHeader('Content-Type', 'application/json');\r\n                    xhr.onreadystatechange = (e: any) => {\r\n                        if (e.target.readyState === XMLHttpRequest.DONE && e.target.status === 200) {\r\n                            const jsonResponse = JSON.parse(e.target.response);\r\n                            this.scenarioID = jsonResponse.id;\r\n                            this.scenarioName = scenarioName;\r\n                            this.scenarioIndexPage = 1;\r\n                            this.scenarioPrev();\r\n                            Core.customAppService.send('SCENARIO_OPERATION_RESULT', {\r\n                                operation: 'save',\r\n                                success: true,\r\n                                message: 'Scenario Saved',\r\n                                scenarioID: this.scenarioID,\r\n                            });\r\n                            this.sendScenarioStateUpdate();\r\n                        }\r\n                    };\r\n                    const sendParams =\r\n                        '{\"name\":\"' +\r\n                        scenarioName +\r\n                        '\",\"data\":\"' +\r\n                        this.escape(data) +\r\n                        '\",\"casino\":\"' +\r\n                        Core.configuration.casinoId +\r\n                        '\",\"game\":\"' +\r\n                        Core.configuration.gameKey +\r\n                        '\",\"player\":\"' +\r\n                        Core.configuration.playerId +\r\n                        '\"}';\r\n                    xhr.send(sendParams);\r\n                }\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SCENARIO_DELETE', () => {\r\n                if (this.scenarioID > -1) {\r\n                    const rawFile = new XMLHttpRequest();\r\n                    rawFile.overrideMimeType('application/json');\r\n                    rawFile.open(\r\n                        'DELETE',\r\n                        Core.configuration.scenarioHost +\r\n                            'casinos/' +\r\n                            Core.configuration.casinoId +\r\n                            '/games/' +\r\n                            Core.configuration.gameKey +\r\n                            '/scenarios/' +\r\n                            this.scenarioID,\r\n                        true,\r\n                    );\r\n                    rawFile.onreadystatechange = (e: any) => {\r\n                        if (e.target.readyState === 4 && e.target.status === 200) {\r\n                            this.scenarioID = -1;\r\n                            this.scenarioIndexPage++;\r\n                            this.scenarioPrev();\r\n                            Core.customAppService.send('SCENARIO_OPERATION_RESULT', {\r\n                                operation: 'delete',\r\n                                success: true,\r\n                                message: 'Scenario Removed from the server!',\r\n                            });\r\n                            this.sendScenarioStateUpdate();\r\n                        }\r\n                    };\r\n                    rawFile.send();\r\n                }\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SCENARIO_TOGGLE_SETUP', (msg: BusMessage) => {\r\n                const value = msg.payload as boolean;\r\n                this.isScenarioButtonActive.next(value);\r\n                if (value) {\r\n                    this.scenarioNextPage.next(0);\r\n                    this.isActive.next(true);\r\n                }\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SCENARIO_TOGGLE_DRAG', (msg: BusMessage) => {\r\n                const value = msg.payload as boolean;\r\n                this.isDrag.next(value);\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SCENARIO_TOGGLE_GUARD', (msg: BusMessage) => {\r\n                const value = msg.payload as boolean;\r\n                this.isGuardSymbolsAvailableForChange.next(value);\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SCENARIO_SELECT_SYMBOL', (msg: BusMessage) => {\r\n                const symbolIndex = msg.payload as number;\r\n                this.selectedImageIndex.next(symbolIndex);\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SCENARIO_SET_CELL', (msg: BusMessage) => {\r\n                const { reel, row, symbolIndex } = msg.payload as { reel: number; row: number; symbolIndex: number };\r\n                const newReelImages = this.reelImageIndexes.value.map((col) => [...col]);\r\n                newReelImages[reel][row] = symbolIndex;\r\n                this.reelImageIndexes.next(newReelImages);\r\n\r\n                const scenario = this.scenarioImageIndexes.value;\r\n                scenario[this.scenarioIndexPage] = newReelImages;\r\n                this.scenarioImageIndexes.next(scenario);\r\n\r\n                this.sendScenarioStateUpdate();\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SCENARIO_SET_SYMBOLS_PER_REEL', (msg: BusMessage) => {\r\n                const newGrid = msg.payload as number[][];\r\n                if (!Array.isArray(newGrid)) return;\r\n                const newSymbolsPerReel = newGrid.map((reel) => reel.length);\r\n                this.reelImageIndexes.next(newGrid);\r\n                this.symbolsPerReel.next(newSymbolsPerReel);\r\n\r\n                const scenario = this.scenarioImageIndexes.value;\r\n                scenario[this.scenarioIndexPage] = newGrid;\r\n                this.scenarioImageIndexes.next(scenario);\r\n\r\n                const scenarioSPR = this.scenarioSymbolsPerReel.value;\r\n                scenarioSPR[this.scenarioIndexPage] = newSymbolsPerReel;\r\n                this.scenarioSymbolsPerReel.next(scenarioSPR);\r\n\r\n                this.sendScenarioStateUpdate();\r\n            }),\r\n        );\r\n\r\n        // ── Spine animation handlers ──\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('REQUEST_SPINE_DATA', () => {\r\n                const criteria = (_key: string, value: any) => value.hasOwnProperty('spineData');\r\n                const spineKeys = this.filterLoadedAssetKeys(criteria);\r\n                Core.customAppService.send('SPINE_DATA', spineKeys);\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SELECT_SPINE', (msg: BusMessage) => {\r\n                const spineName = msg.payload as string;\r\n                if (!spineName) {\r\n                    this.selectedSpineName = '';\r\n                    this.selectedSpineResource = null;\r\n                    this.selectedSpineUrl = '';\r\n                    Core.customAppService.send('SPINE_CONFIG', null);\r\n                    return;\r\n                }\r\n\r\n                this.selectedSpineName = spineName;\r\n                this.selectedSpineResource = Core.assets.getAsset(spineName);\r\n                this.selectedSpineUrl = this.selectedSpineResource?.url || '';\r\n\r\n                if (!this.selectedSpineResource) {\r\n                    Core.customAppService.send('SPINE_CONFIG', null);\r\n                    return;\r\n                }\r\n\r\n                const animationNames = Object.keys(this.selectedSpineResource.data?.animations || {});\r\n\r\n                let textureBase64 = '';\r\n                let atlasContent = '';\r\n                let jsonContent = '';\r\n                const imageUrls: string[] = [];\r\n                try {\r\n                    const children = this.selectedSpineResource.children || [];\r\n                    const imageChild = children.find((c: any) => c.extension === 'png' || c.extension === 'webp');\r\n                    if (imageChild) {\r\n                        textureBase64 = imageChild.texture.baseTexture.resource.source.currentSrc;\r\n                    }\r\n                    atlasContent = children[0]?.data || '';\r\n                    jsonContent = JSON.stringify(this.selectedSpineResource.data);\r\n                    children\r\n                        .filter((c: any) => c.extension === 'png' || c.extension === 'webp')\r\n                        .forEach((c: any) => imageUrls.push(c.texture.baseTexture.resource.source.currentSrc));\r\n                } catch {\r\n                    /* texture not available */\r\n                }\r\n\r\n                Core.customAppService.send('SPINE_CONFIG', {\r\n                    name: spineName,\r\n                    animationNames,\r\n                    textureBase64,\r\n                    atlasContent,\r\n                    jsonContent,\r\n                    imageUrls,\r\n                    hasFtpAccess: !!(window as any).ssi?.CustomResourcesHost,\r\n                });\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('REPLACE_SPINE', async (msg: BusMessage) => {\r\n                const { atlasContent, jsonContent, imageDataUrls } = msg.payload as {\r\n                    atlasContent: string;\r\n                    jsonContent: string;\r\n                    imageDataUrls: string[];\r\n                };\r\n\r\n                if (!this.selectedSpineName || !atlasContent || !jsonContent || !imageDataUrls?.length) {\r\n                    Core.customAppService.send('SPINE_OPERATION_RESULT', {\r\n                        operation: 'replace',\r\n                        success: false,\r\n                        message: 'Missing required files or no spine selected.',\r\n                    });\r\n                    return;\r\n                }\r\n\r\n                try {\r\n                    const imageElements: HTMLImageElement[] = [];\r\n                    for (const dataUrl of imageDataUrls) {\r\n                        const img = await this.loadImageFromDataUrl(dataUrl);\r\n                        imageElements.push(img);\r\n                    }\r\n\r\n                    const spineData = await this.createSpineData(atlasContent, jsonContent, imageElements);\r\n\r\n                    const existingAsset: any = Array.from(Core.assets.loadedAssets.values()).find(\r\n                        (s: any) => s.name === this.selectedSpineName,\r\n                    );\r\n                    if (existingAsset?.spineData?.animations) {\r\n                        const initialAnims = existingAsset.spineData.animations\r\n                            .filter((a: any) => a.name)\r\n                            .map((a: any) => a.name);\r\n                        const replacedAnims = (spineData.spineData?.animations || []).map((a: any) => a.name);\r\n                        const missing = initialAnims.filter((n: string) => !replacedAnims.includes(n));\r\n                        if (missing.length > 0) {\r\n                            Core.customAppService.send('SPINE_OPERATION_RESULT', {\r\n                                operation: 'replace',\r\n                                success: true,\r\n                                message: `Spine replaced. Warning: missing animations in replacement: ${missing.join(', ')}`,\r\n                            });\r\n                        }\r\n                    }\r\n\r\n                    Core.assets.loadedAssets.set(this.selectedSpineName, spineData);\r\n                    this.selectedSpineResource = spineData;\r\n\r\n                    const selectedSpineAnimation = Core.spineAnimations?.spineAnimations?.find(\r\n                        (a: any) => a.name === spineData.name,\r\n                    );\r\n                    if (selectedSpineAnimation) {\r\n                        Core.spineAnimations.replaceAnimationsWithCustom(selectedSpineAnimation);\r\n                    }\r\n\r\n                    let textureBase64 = '';\r\n                    try {\r\n                        textureBase64 = imageDataUrls[0];\r\n                    } catch {\r\n                        /* ignore */\r\n                    }\r\n\r\n                    Core.customAppService.send('SPINE_OPERATION_RESULT', {\r\n                        operation: 'replace',\r\n                        success: true,\r\n                        message: 'Spine animation replaced successfully.',\r\n                        textureBase64,\r\n                        animationNames: Object.keys(spineData.data?.animations || {}),\r\n                    });\r\n                } catch (error) {\r\n                    Core.customAppService.send('SPINE_OPERATION_RESULT', {\r\n                        operation: 'replace',\r\n                        success: false,\r\n                        message: `Error replacing spine: ${error}`,\r\n                    });\r\n                }\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('FTP_UPLOAD_SPINE', async (msg: BusMessage) => {\r\n                const { atlasContent, atlasName, jsonContent, jsonName, imageDataUrls, imageNames } = msg.payload as {\r\n                    atlasContent: string;\r\n                    atlasName: string;\r\n                    jsonContent: string;\r\n                    jsonName: string;\r\n                    imageDataUrls: string[];\r\n                    imageNames: string[];\r\n                };\r\n\r\n                if (!this.selectedSpineResource || !atlasContent || !jsonContent || !imageDataUrls?.length) {\r\n                    Core.customAppService.send('SPINE_OPERATION_RESULT', {\r\n                        operation: 'ftpUpload',\r\n                        success: false,\r\n                        message: 'Missing required files or no spine selected.',\r\n                    });\r\n                    return;\r\n                }\r\n\r\n                try {\r\n                    const extractedPath = (this.selectedSpineUrl || this.selectedSpineResource.url || '').match(\r\n                        /assets\\/(?:[^\\/]+\\/)*?(?=[^\\/]+\\.json)/,\r\n                    );\r\n                    const temp = (window as any).ssi.CustomResourcesHost.split('/');\r\n                    const taskPath = temp[temp.length - 2];\r\n                    const formData = new FormData();\r\n                    formData.append('customurl', `/sounds/${taskPath}/${extractedPath}/`);\r\n\r\n                    for (let i = 0; i < imageDataUrls.length; i++) {\r\n                        const resp = await fetch(imageDataUrls[i]);\r\n                        const blob = await resp.blob();\r\n                        formData.append('files[]', blob, imageNames[i]);\r\n                    }\r\n\r\n                    const atlasBlob = new Blob([atlasContent], { type: 'text/plain' });\r\n                    formData.append('files[]', atlasBlob, atlasName);\r\n\r\n                    const jsonBlob = new Blob([jsonContent], { type: 'application/json' });\r\n                    formData.append('files[]', jsonBlob, jsonName);\r\n\r\n                    const response = await Core.requestManager.post(\r\n                        Core.configuration.assetPackHost + 'uploadToFTP',\r\n                        formData,\r\n                    );\r\n\r\n                    if (response && response.status >= 200 && response.status < 300) {\r\n                        Core.customAppService.send('SPINE_OPERATION_RESULT', {\r\n                            operation: 'ftpUpload',\r\n                            success: true,\r\n                            message: `Success: ${response.data.message}`,\r\n                        });\r\n                    } else {\r\n                        Core.customAppService.send('SPINE_OPERATION_RESULT', {\r\n                            operation: 'ftpUpload',\r\n                            success: false,\r\n                            message: 'FTP upload failed.',\r\n                        });\r\n                    }\r\n                } catch (error) {\r\n                    Core.customAppService.send('SPINE_OPERATION_RESULT', {\r\n                        operation: 'ftpUpload',\r\n                        success: false,\r\n                        message: `Fetch error: ${error}`,\r\n                    });\r\n                }\r\n            }),\r\n        );\r\n\r\n        // ── Spritesheet texture handlers ──\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('REQUEST_SPRITESHEET_ASSETS', () => {\r\n                const assets =\r\n                    (this.slotConfiguration as any).assets\r\n                        ?.concat((this.slotConfiguration as any).uiAssets ?? [])\r\n                        ?.filter((asset: any) => asset.type === 'texture' && !asset.url.includes('animations'))\r\n                        .map((asset: any) => ({ id: asset.id, url: asset.url })) || [];\r\n                Core.customAppService.send('SPRITESHEET_ASSETS', assets);\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('SELECT_SPRITESHEET_ASSET', (msg: BusMessage) => {\r\n                const assetId = msg.payload as string;\r\n                if (!assetId) {\r\n                    this.selectedSpritesheetAssetId = '';\r\n                    this.selectedSpritesheetResource = null;\r\n                    Core.customAppService.send('SPRITESHEET_SPRITES', null);\r\n                    return;\r\n                }\r\n\r\n                this.selectedSpritesheetAssetId = assetId;\r\n                this.selectedSpritesheetResource = Core.assets.loadedAssets.get(assetId);\r\n\r\n                if (!this.selectedSpritesheetResource?.spritesheet) {\r\n                    Core.customAppService.send('SPRITESHEET_SPRITES', null);\r\n                    return;\r\n                }\r\n\r\n                const frameData = this.selectedSpritesheetResource.spritesheet?.data?.frames;\r\n                const spriteNames = frameData ? Object.keys(frameData) : [];\r\n                Core.customAppService.send('SPRITESHEET_SPRITES', {\r\n                    spriteNames,\r\n                    hasFtpAccess: !!(window as any).ssi?.CustomResourcesHost,\r\n                });\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('REPLACE_SPRITESHEET_TEXTURE', async (msg: BusMessage) => {\r\n                const { spriteName, imageDataUrl } = msg.payload as {\r\n                    spriteName: string;\r\n                    imageDataUrl: string;\r\n                };\r\n\r\n                if (!this.selectedSpritesheetResource || !spriteName || !imageDataUrl) {\r\n                    Core.customAppService.send('SPRITESHEET_OPERATION_RESULT', {\r\n                        operation: 'replace',\r\n                        success: false,\r\n                        message: 'Missing required data or no asset selected.',\r\n                    });\r\n                    return;\r\n                }\r\n\r\n                try {\r\n                    const img = await this.loadImageFromDataUrl(imageDataUrl);\r\n                    const oldTexture = this.selectedSpritesheetResource.textures[spriteName];\r\n                    if (!oldTexture) {\r\n                        Core.customAppService.send('SPRITESHEET_OPERATION_RESULT', {\r\n                            operation: 'replace',\r\n                            success: false,\r\n                            message: `Sprite \"${spriteName}\" not found in spritesheet.`,\r\n                        });\r\n                        return;\r\n                    }\r\n\r\n                    const newTexture = Texture.from(img);\r\n                    this.replaceTextureInAllSprites(\r\n                        Core.stage.stage,\r\n                        oldTexture,\r\n                        newTexture,\r\n                        this.selectedSpritesheetAssetId,\r\n                    );\r\n\r\n                    Core.customAppService.send('SPRITESHEET_OPERATION_RESULT', {\r\n                        operation: 'replace',\r\n                        success: true,\r\n                        message: `Texture \"${spriteName}\" replaced successfully.`,\r\n                    });\r\n                } catch (error) {\r\n                    Core.customAppService.send('SPRITESHEET_OPERATION_RESULT', {\r\n                        operation: 'replace',\r\n                        success: false,\r\n                        message: `Error replacing texture: ${error}`,\r\n                    });\r\n                }\r\n            }),\r\n        );\r\n\r\n        this.customAppUnsubscribes.push(\r\n            Core.customAppService.on('FTP_UPLOAD_SPRITESHEET', async () => {\r\n                if (!this.selectedSpritesheetResource || !this.selectedSpritesheetAssetId) {\r\n                    Core.customAppService.send('SPRITESHEET_OPERATION_RESULT', {\r\n                        operation: 'ftpUpload',\r\n                        success: false,\r\n                        message: 'No spritesheet asset selected.',\r\n                    });\r\n                    return;\r\n                }\r\n\r\n                try {\r\n                    const textures = this.selectedSpritesheetResource.textures;\r\n                    const blobs = await this.texturesToBlobs(textures);\r\n                    const entries = Object.entries(textures);\r\n                    const formData = new FormData();\r\n\r\n                    blobs.forEach((blob: Blob, index: number) => {\r\n                        const [key] = entries[index];\r\n                        formData.append('images[]', blob, key);\r\n                    });\r\n\r\n                    const parts = this.selectedSpritesheetResource?.url?.split('/').filter(Boolean);\r\n                    const folder = parts && parts.length > 1 ? parts[parts.length - 2] : null;\r\n                    const temp = (window as any).ssi.CustomResourcesHost.split('/');\r\n                    const taskPath = temp[temp.length - 2];\r\n                    formData.append('customurl', `/sounds/${taskPath}/assets/${Core.configuration.gameKey}/${folder}/`);\r\n                    formData.append('filename', this.selectedSpritesheetAssetId);\r\n\r\n                    const response = await Core.requestManager.post(\r\n                        Core.configuration.assetPackHost + 'generateSpritesheet',\r\n                        formData,\r\n                    );\r\n\r\n                    if (response && response.status >= 200 && response.status < 300) {\r\n                        Core.customAppService.send('SPRITESHEET_OPERATION_RESULT', {\r\n                            operation: 'ftpUpload',\r\n                            success: true,\r\n                            message: `Success: ${response.data.message}`,\r\n                        });\r\n                    } else {\r\n                        Core.customAppService.send('SPRITESHEET_OPERATION_RESULT', {\r\n                            operation: 'ftpUpload',\r\n                            success: false,\r\n                            message: 'FTP upload failed.',\r\n                        });\r\n                    }\r\n                } catch (error) {\r\n                    Core.customAppService.send('SPRITESHEET_OPERATION_RESULT', {\r\n                        operation: 'ftpUpload',\r\n                        success: false,\r\n                        message: `Fetch error: ${error}`,\r\n                    });\r\n                }\r\n            }),\r\n        );\r\n\r\n        // ── Game connection status for custom-app badge ──\r\n\r\n        const errorSub = Core.SHOW_ERROR.pipe(\r\n            filter((errorData) => errorData.type !== ErrorTypes.CONFIRMATION),\r\n        ).subscribe((errorData) => {\r\n            // BroadcastChannel structured-clones the payload, so functions (e.g. callback) must not be sent\r\n            const { callback, ...error } = errorData;\r\n            Core.customAppService.send('GAME_CONNECTION_STATUS', { connected: false, error });\r\n        });\r\n        this.customAppUnsubscribes.push(() => errorSub.unsubscribe());\r\n\r\n        const restoreSub = Core.ON_CONNECTION_RESTORED.subscribe(() => {\r\n            Core.customAppService.send('GAME_CONNECTION_STATUS', { connected: true });\r\n        });\r\n        this.customAppUnsubscribes.push(() => restoreSub.unsubscribe());\r\n\r\n        // Preload custom-app iframe hidden so it opens instantly\r\n        Core.customAppService.preloadIframe();\r\n\r\n        // Notify custom-app that a (new) game has loaded so it can refresh its data\r\n        Core.customAppService.send('GAME_LOADED', { gameKey: Core.configuration.gameKey });\r\n    }\r\n\r\n    // ── Bot execution methods ──\r\n\r\n    private startBot(): void {\r\n        try {\r\n            this.botView = Core.gameDependencyContainer.resolve('RootView');\r\n        } catch {\r\n            return;\r\n        }\r\n        this.botSpinButton = this.botView.find('spinButton');\r\n        this.botStopButton = this.botView.find('autoPlayStopButton');\r\n        this.botMysteryIndexes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];\r\n        this.botCurrentBetIndex = 1;\r\n\r\n        this.botStateSubscription = this.rootStore.uiStore.STATE.pipe(\r\n            filter(() => this.isInfinityPlayButtonActive.value),\r\n        ).subscribe(() => this.botExecuteButtonFakeClick());\r\n\r\n        this.botMessageSubscription = Core.ON_SERVER_MESSAGE.pipe(\r\n            filter(() => this.isInfinityPlayButtonActive.value),\r\n        ).subscribe(() => this.botExecuteButtonFakeClick());\r\n    }\r\n\r\n    private stopBot(): void {\r\n        Timers.clearTimeout(this.botTimer);\r\n        this.botStateSubscription?.unsubscribe();\r\n        this.botMessageSubscription?.unsubscribe();\r\n        this.botStateSubscription = null;\r\n        this.botMessageSubscription = null;\r\n        this.botView = null;\r\n        this.botSpinButton = null;\r\n        this.botStopButton = null;\r\n    }\r\n\r\n    /** Random integer in [min, max], both inclusive. */\r\n    private botRandomInterval(min: number, max: number): number {\r\n        return Math.floor(Math.random() * (max - min + 1)) + min;\r\n    }\r\n\r\n    private botWaitForBetSpeed(): number {\r\n        const speed = Math.min(100, Math.max(0, Number(this.betSpeed) || 0));\r\n        const range = CustomResultStore.BOT_MAX_WAIT_MS - CustomResultStore.BOT_MIN_WAIT_MS;\r\n        return Math.round(CustomResultStore.BOT_MAX_WAIT_MS - (range * speed) / 100);\r\n    }\r\n\r\n    private botDoClick(): void {\r\n        Timers.clearTimeout(this.botTimer);\r\n        if (!this.isInfinityPlayButtonActive.value) {\r\n            return;\r\n        }\r\n        let interval: number;\r\n        if (this.rootStore.uiStore.turboModeEnabled) {\r\n            interval = this.botRandomInterval(200, 400);\r\n        } else if (this.rootStore.uiStore.quickSpinEnabled) {\r\n            interval = this.botRandomInterval(300, 600);\r\n        } else {\r\n            interval = this.botWaitForBetSpeed();\r\n        }\r\n        this.botTimer = Timers.setTimeout(() => {\r\n            if (this.botActiveButton && this.botActiveButton.visible && this.botActiveButton.enabled) {\r\n                this.botActiveButton.fakeClick();\r\n                // A click the game swallows (blocked UI, animation still running) produces neither a\r\n                // state change nor a server message, so nothing woke the bot until some unrelated push\r\n                // (jackpot stats, balance) arrived seconds later. Re-evaluate after a bounded pause\r\n                // instead; any real reaction clears this timer first.\r\n                this.botTimer = Timers.setTimeout(\r\n                    () => this.botExecuteButtonFakeClick(),\r\n                    CustomResultStore.BOT_STALL_WAIT_MS,\r\n                );\r\n            } else {\r\n                this.botDoClick();\r\n            }\r\n        }, interval);\r\n    }\r\n\r\n    private botExecuteButtonFakeClick(): void {\r\n        Timers.clearTimeout(this.botTimer);\r\n        if (!this.isInfinityPlayButtonActive.value) {\r\n            return;\r\n        }\r\n\r\n        if (this.rootStore.uiStore.STATE.value !== UIState.MYSTERY) {\r\n            this.botMysteryIndexes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];\r\n        }\r\n\r\n        this.botActiveButton = this.botSpinButton;\r\n        switch (this.rootStore.uiStore.STATE.value) {\r\n            case UIState.MYSTERY:\r\n                const chestHolder = this.botView.find('chestHolder');\r\n                if (chestHolder) {\r\n                    if (this.botMysteryIndexes.length === 15) {\r\n                        const random = Math.floor(Math.random() * this.botMysteryIndexes.length);\r\n                        const lastSelected = this.botMysteryIndexes[random];\r\n                        this.botMysteryIndexes.splice(random, 1);\r\n                        Timers.setTimeout(() => {\r\n                            const chest = this.botView.find('chest' + lastSelected);\r\n                            chest.openChest();\r\n                        }, 2000);\r\n                    } else {\r\n                        const backToGameBut = this.botView.find('backToGameBut') as Sprite;\r\n                        if (backToGameBut) {\r\n                            backToGameBut.emit('pointerup');\r\n                        }\r\n                    }\r\n                }\r\n                break;\r\n            case UIState.PICK_ME_BONUS:\r\n                if (this.rootStore.domainStore.SERVER_STATE.value !== ServerState.PICK) {\r\n                    return;\r\n                }\r\n                this.botActiveButton = this.botStopButton;\r\n                const scatterButton = this.botView.find('scatter0');\r\n                if (scatterButton && scatterButton.visible) {\r\n                    scatterButton.emit('pointerdown');\r\n                }\r\n                break;\r\n            case UIState.WAITING_FOR_STATE_CHANGE:\r\n                return;\r\n            case UIState.WAITING_FOR_RESPONSE:\r\n                const fastStop = this.botRandomInterval(1, 100) < Number(this.fastStop) ? true : false;\r\n                if (!fastStop) {\r\n                    return;\r\n                } else {\r\n                    this.botActiveButton = this.botView.find('stopButton');\r\n                    this.botActiveButton.emit('pointerdown');\r\n                }\r\n                break;\r\n            case UIState.FREESPIN:\r\n                const startFreeSpinButton = this.botView.find('freeSpinStartBtnClickableArea');\r\n                if (startFreeSpinButton && startFreeSpinButton.visible) {\r\n                    startFreeSpinButton.emit('pointerup');\r\n                    return;\r\n                }\r\n                this.botActiveButton = this.botStopButton;\r\n                break;\r\n            case UIState.GAMBLE:\r\n                if (this.rootStore.uiStore.gamblesLeft === 0) {\r\n                    return;\r\n                }\r\n                const chooseCollect = this.botRandomInterval(1, 100) < Number(this.gambleCollect) ? true : false;\r\n                if (chooseCollect) {\r\n                    this.botActiveButton = this.botView.find('collectButton');\r\n                } else {\r\n                    const chooseBlack = this.botRandomInterval(1, 100) < Number(this.gambleRedBlack) ? true : false;\r\n                    this.botActiveButton = chooseBlack\r\n                        ? this.botView.find('gambleBlackButton')\r\n                        : this.botView.find('gambleRedButton');\r\n                }\r\n                break;\r\n            case UIState.WAITING_FOR_RESPONSE_IN_FREESPIN:\r\n                this.botActiveButton = this.botStopButton;\r\n                break;\r\n            case UIState.WAITING_FOR_COLLECT:\r\n                let playGamble = false;\r\n                if (this.rootStore.uiStore.gamblesLeft > 0) {\r\n                    playGamble = this.botRandomInterval(1, 100) < Number(this.playGamble) ? true : false;\r\n                }\r\n                if (playGamble) {\r\n                    this.botActiveButton = this.botView.find('gambleButton');\r\n                } else {\r\n                    this.botActiveButton = this.botSpinButton;\r\n                }\r\n                break;\r\n            case UIState.IDLE:\r\n                const changeBet = this.botRandomInterval(1, 100) < Number(this.changeBet) ? true : false;\r\n                if (changeBet) {\r\n                    // Bet buttons are named bet1..betN after the game's bet list. A fixed 1-5 targeted\r\n                    // buttons that do not exist in games with fewer bets, and the bot then polled a\r\n                    // missing button until the next server push. Fall back to spinning if not found.\r\n                    const betCount = this.rootStore.uiStore.bets.length || 5;\r\n                    const betOptions = Array.from({ length: betCount }, (_, i) => i + 1).filter(\r\n                        (b) => b !== this.botCurrentBetIndex,\r\n                    );\r\n                    this.botCurrentBetIndex = betOptions[this.botRandomInterval(0, betOptions.length - 1)];\r\n                    this.botActiveButton = this.botView.find('bet' + this.botCurrentBetIndex) ?? this.botSpinButton;\r\n                } else {\r\n                    this.botActiveButton = this.botSpinButton;\r\n                }\r\n                break;\r\n            default:\r\n                this.botActiveButton = this.botSpinButton;\r\n        }\r\n        this.botDoClick();\r\n    }\r\n\r\n    private sendScenarioStateUpdate(): void {\r\n        Core.customAppService.send('SCENARIO_STATE_UPDATE', {\r\n            reelImageIndexes: this.reelImageIndexes.value,\r\n            symbolsPerReel: this.symbolsPerReel.value,\r\n            scenarioIndexPage: this.scenarioIndexPage,\r\n            scenarioAllPage: this.scenarioAllPage,\r\n            scenarioID: this.scenarioID,\r\n            scenarioActive: this.isScenarioButtonActive.value,\r\n        });\r\n    }\r\n\r\n    private getWindowSSIPath(): string {\r\n        try {\r\n            const host = (window as any).ssi.CustomResourcesHost;\r\n            const temp = host.split('/');\r\n            return temp[temp.length - 2];\r\n        } catch {\r\n            return '';\r\n        }\r\n    }\r\n\r\n    public destroyCustomAppListeners(): void {\r\n        Core.customAppService.send('GAME_UNLOADED', { gameKey: Core.configuration.gameKey });\r\n        this.customAppUnsubscribes.forEach((unsub) => unsub());\r\n        this.customAppUnsubscribes = [];\r\n    }\r\n\r\n    public destroy(): void {\r\n        this.stopBot();\r\n        this.destroyCustomAppListeners();\r\n        // @ts-ignore\r\n        delete this.rootStore;\r\n    }\r\n\r\n    // ── Animation helper methods ──\r\n\r\n    private buildAnimationObjectsArray(): void {\r\n        const symbolsConfig =\r\n            this.slotConfiguration.symbolsConfig.filter((asset: any) => asset.hasOwnProperty('video')) || [];\r\n        const otherAnimations =\r\n            this.slotConfiguration.assets.filter((asset: any) => asset.hasOwnProperty('videoConfig')) || [];\r\n\r\n        if (otherAnimations.length) {\r\n            const lastIndex = symbolsConfig.length > 0 ? symbolsConfig[symbolsConfig.length - 1].index : -1;\r\n            const mapped = otherAnimations.map((asset: any, i: number) => ({\r\n                ...asset,\r\n                index: lastIndex + 1 + i,\r\n                name: asset.id,\r\n            }));\r\n            this.animationObjectsArray = [...symbolsConfig, ...mapped];\r\n        } else {\r\n            this.animationObjectsArray = symbolsConfig;\r\n        }\r\n    }\r\n\r\n    private loadImageFromDataUrl(dataUrl: string): Promise<HTMLImageElement> {\r\n        return new Promise((resolve, reject) => {\r\n            const img = new Image();\r\n            img.onload = () => resolve(img);\r\n            img.onerror = reject;\r\n            img.src = dataUrl;\r\n        });\r\n    }\r\n\r\n    private generateSpritesheet(\r\n        images: HTMLImageElement[],\r\n        maxWidth: number,\r\n    ): { spritesheet: string; data: any } | { spritesheet: string; data: any }[] {\r\n        const spriteWidth = images[0].width;\r\n        const spriteHeight = images[0].height;\r\n        const exportName = this.selectedVideoExportName;\r\n\r\n        let canvasWidth = 0;\r\n        for (let i = 0; i < images.length; i++) {\r\n            if (canvasWidth + spriteWidth <= maxWidth) {\r\n                canvasWidth += spriteWidth;\r\n            } else break;\r\n        }\r\n        let canvasHeight = spriteHeight * Math.ceil((spriteWidth * images.length) / canvasWidth);\r\n        if (canvasHeight === 0) canvasHeight = spriteHeight;\r\n\r\n        if (canvasWidth <= 2048 && canvasHeight <= 2048) {\r\n            const canvas = document.createElement('canvas');\r\n            const ctx = canvas.getContext('2d')!;\r\n            canvas.width = canvasWidth;\r\n            canvas.height = canvasHeight;\r\n\r\n            const data: any = {\r\n                frames: {},\r\n                animations: { videoIdInAssets: [] as string[] },\r\n                meta: {\r\n                    app: 'https://www.codeandweb.com/texturepacker',\r\n                    version: '1.0',\r\n                    image: `${exportName}.png`,\r\n                    format: 'RGBA8888',\r\n                    size: { w: canvasWidth, h: canvasHeight },\r\n                    scale: '1',\r\n                },\r\n            };\r\n\r\n            let x = 0;\r\n            let y = 0;\r\n            images.forEach((img, index) => {\r\n                if (x + spriteWidth > maxWidth) {\r\n                    x = 0;\r\n                    y += spriteHeight;\r\n                }\r\n                ctx.drawImage(img, x, y);\r\n                const frameName = `${exportName}_${String(index + 1).padStart(2, '0')}.png`;\r\n                data.frames[frameName] = {\r\n                    frame: { x, y, w: spriteWidth, h: spriteHeight },\r\n                    rotated: false,\r\n                    trimmed: false,\r\n                    spriteSourceSize: { x: 0, y: 0, w: spriteWidth, h: spriteHeight },\r\n                    sourceSize: { w: spriteWidth, h: spriteHeight },\r\n                };\r\n                data.animations.videoIdInAssets.push(frameName);\r\n                x += spriteWidth;\r\n            });\r\n\r\n            return { spritesheet: canvas.toDataURL('image/png'), data };\r\n        } else {\r\n            const maxSheetSize = 2048;\r\n            let sheetIndex = 0;\r\n            const sheetData: {\r\n                canvas: HTMLCanvasElement;\r\n                ctx: CanvasRenderingContext2D;\r\n                frames: any;\r\n                image: string;\r\n            }[] = [];\r\n\r\n            const newCanvas = document.createElement('canvas');\r\n            newCanvas.width = maxSheetSize;\r\n            newCanvas.height = maxSheetSize;\r\n            sheetData.push({\r\n                canvas: newCanvas,\r\n                ctx: newCanvas.getContext('2d')!,\r\n                frames: {},\r\n                image: `${exportName}-${sheetIndex + 1}.png`,\r\n            });\r\n            sheetIndex++;\r\n            let x = 0;\r\n            let y = 0;\r\n\r\n            images.forEach((img) => {\r\n                if (x + spriteWidth > maxSheetSize) {\r\n                    x = 0;\r\n                    y += spriteHeight;\r\n                    if (y + spriteHeight > maxSheetSize) {\r\n                        const nc = document.createElement('canvas');\r\n                        nc.width = maxSheetSize;\r\n                        nc.height = maxSheetSize;\r\n                        sheetData.push({\r\n                            canvas: nc,\r\n                            ctx: nc.getContext('2d')!,\r\n                            frames: {},\r\n                            image: `${exportName}-${sheetIndex + 1}.png`,\r\n                        });\r\n                        sheetIndex++;\r\n                        x = 0;\r\n                        y = 0;\r\n                    }\r\n                }\r\n                const currentSheet = sheetData[sheetData.length - 1];\r\n                currentSheet.ctx.drawImage(img, x, y);\r\n                const frameName = `${exportName}_${String(images.indexOf(img) + 1).padStart(2, '0')}.png`;\r\n                currentSheet.frames[frameName] = {\r\n                    frame: { x, y, w: spriteWidth, h: spriteHeight },\r\n                    rotated: false,\r\n                    trimmed: false,\r\n                    spriteSourceSize: { x: 0, y: 0, w: spriteWidth, h: spriteHeight },\r\n                    sourceSize: { w: spriteWidth, h: spriteHeight },\r\n                };\r\n                x += spriteWidth;\r\n            });\r\n\r\n            return sheetData.map((sheet) => ({\r\n                spritesheet: sheet.canvas.toDataURL('image/png'),\r\n                data: {\r\n                    frames: sheet.frames,\r\n                    animations: { [exportName]: Object.keys(sheet.frames) },\r\n                    meta: {\r\n                        app: 'https://www.codeandweb.com/texturepacker',\r\n                        version: '1.0',\r\n                        image: sheet.image,\r\n                        format: 'RGBA8888',\r\n                        size: { w: maxSheetSize, h: maxSheetSize },\r\n                        scale: '1',\r\n                        related_multi_packs: [],\r\n                    },\r\n                },\r\n            }));\r\n        }\r\n    }\r\n\r\n    private async texturesToBlobs(textures: Record<string, Texture>): Promise<Blob[]> {\r\n        const { renderer, stage } = Core.stage;\r\n        const textureBlobs: Blob[] = [];\r\n        const originalResolution = renderer.resolution;\r\n        const originalScale = stage.scale.x;\r\n        const originalX = stage.x;\r\n        const originalY = stage.y;\r\n        stage.scale.set(1);\r\n        stage.y = 0;\r\n        stage.x = 0;\r\n        renderer.resolution = 1;\r\n\r\n        for (const texture of Object.values(textures)) {\r\n            const sprite = new Sprite(texture as Texture);\r\n            sprite.x = 0;\r\n            sprite.y = 0;\r\n            stage.addChild(sprite);\r\n            renderer.render(stage, texture as unknown as RenderTexture);\r\n\r\n            const blob = await new Promise<Blob | null>((resolve) => {\r\n                (renderer as any).extract.canvas(sprite).toBlob((b: Blob | null) => resolve(b));\r\n            });\r\n            if (blob) textureBlobs.push(blob);\r\n            stage.removeChild(sprite);\r\n        }\r\n\r\n        renderer.resolution = originalResolution;\r\n        stage.y = originalY;\r\n        stage.x = originalX;\r\n        stage.scale.set(originalScale);\r\n        return textureBlobs;\r\n    }\r\n\r\n    private sendAnimationConfig(): void {\r\n        if (!this.selectedVideoConfig) {\r\n            Core.customAppService.send('ANIMATION_CONFIG', null);\r\n            return;\r\n        }\r\n\r\n        let textureBase64 = '';\r\n        try {\r\n            const asset = Core.assets.getAsset(this.selectedVideoIdInAssets);\r\n            const singleOrArray = asset.length !== undefined ? asset[0] : asset;\r\n            textureBase64 = singleOrArray.spritesheet.baseTexture.resource.source.currentSrc;\r\n        } catch {\r\n            /* asset not loaded yet */\r\n        }\r\n\r\n        Core.customAppService.send('ANIMATION_CONFIG', {\r\n            fps: this.selectedVideoConfig.fps,\r\n            width: this.selectedVideoConfig.width,\r\n            height: this.selectedVideoConfig.height,\r\n            loopIndex: this.selectedVideoConfig.loopIndex,\r\n            specificFrame: this.selectedVideoConfig.specificFrame ?? 0,\r\n            length: this.selectedVideoConfig.length ?? 0,\r\n            loop: this.selectedVideoConfig.loop,\r\n            videoId: this.selectedVideoIdInAssets,\r\n            videoExportName: this.selectedVideoExportName,\r\n            textureBase64,\r\n            hasFtpAccess: !!(window as any).ssi?.CustomResourcesHost,\r\n        });\r\n    }\r\n\r\n    private sendAnimationReplaceResult(success: boolean, message: string): void {\r\n        let textureBase64 = '';\r\n        try {\r\n            const asset = Core.assets.getAsset(this.selectedVideoIdInAssets);\r\n            const singleOrArray = asset.length !== undefined ? asset[0] : asset;\r\n            textureBase64 = singleOrArray.spritesheet.baseTexture.resource.source.currentSrc;\r\n        } catch {\r\n            /* ignore */\r\n        }\r\n        Core.customAppService.send('ANIMATION_OPERATION_RESULT', {\r\n            operation: 'replace',\r\n            success,\r\n            message,\r\n            textureBase64,\r\n        });\r\n    }\r\n\r\n    // ── Spritesheet helper methods ──\r\n\r\n    private replaceTextureInAllSprites(\r\n        rootContainer: any,\r\n        oldTexture: Texture,\r\n        newTexture: Texture,\r\n        assetId: string,\r\n    ): void {\r\n        const textureId = oldTexture.textureCacheIds[0];\r\n\r\n        // Replace texture on all existing sprites on stage\r\n        const traverseAndReplace = (container: any) => {\r\n            container.children.forEach((child: any) => {\r\n                if (child instanceof Sprite && child.texture.textureCacheIds[0] === textureId) {\r\n                    child.texture = newTexture;\r\n                    child.texture.updateUvs();\r\n                } else if (child.children) {\r\n                    traverseAndReplace(child);\r\n                }\r\n            });\r\n        };\r\n\r\n        traverseAndReplace(rootContainer);\r\n\r\n        // Update spritesheet textures map so new sprites from spritesheet use the new texture\r\n        const asset: any = Core.assets.loadedAssets.get(assetId);\r\n        if (asset?.spritesheet?.textures) {\r\n            asset.spritesheet.textures[textureId] = newTexture;\r\n        }\r\n\r\n        // Also update the loadedAssets textures map (used when creating new sprites)\r\n        if (asset?.textures) {\r\n            asset.textures[textureId] = newTexture;\r\n        }\r\n\r\n        // Update rootStore texture maps used by reels to render symbols after spins\r\n        // Must be done BEFORE removeFromCache which may clear textureCacheIds\r\n        try {\r\n            this.updateTexturesMaps(textureId, newTexture);\r\n        } catch {\r\n            /* non-critical */\r\n        }\r\n\r\n        // Update pixi global texture cache so Texture.from(textureId) returns the new texture\r\n        Texture.removeFromCache(oldTexture);\r\n        Texture.addToCache(newTexture, textureId);\r\n    }\r\n\r\n    private updateTexturesMaps(textureId: string, newTexture: Texture): void {\r\n        // Update texturesMap entries by matching textureCacheIds\r\n        const maps: any[] = [\r\n            this.rootStore.texturesMap,\r\n            this.rootStore.topTexturesMap,\r\n            this.rootStore.blurredTexturesMap,\r\n        ];\r\n        maps.forEach((map) => {\r\n            if (!map) return;\r\n            map.forEach((tex: any, key: any) => {\r\n                if (tex && tex.textureCacheIds && tex.textureCacheIds.indexOf(textureId) !== -1) {\r\n                    map.set(key, newTexture);\r\n                }\r\n            });\r\n        });\r\n\r\n        // Also update the symbol config so symbol.texture() returns the new texture\r\n        try {\r\n            const symbols = (this.slotConfiguration as any).symbols;\r\n            if (symbols) {\r\n                symbols.forEach((sym: any) => {\r\n                    if (typeof sym.texture === 'function' && typeof sym.setTexture === 'function') {\r\n                        const t = sym.texture();\r\n                        if (t && t.textureCacheIds && t.textureCacheIds.indexOf(textureId) !== -1) {\r\n                            sym.setTexture(newTexture);\r\n                        }\r\n                    }\r\n                });\r\n            }\r\n        } catch {\r\n            /* non-critical */\r\n        }\r\n    }\r\n\r\n    // ── Spine helper methods ──\r\n\r\n    private filterLoadedAssetKeys(callback: (key: string, value: any) => boolean): string[] {\r\n        const keys: string[] = [];\r\n        // @ts-ignore\r\n        for (const [key, value] of Core.assets.loadedAssets) {\r\n            if (callback(key, value)) {\r\n                keys.push(key);\r\n            }\r\n        }\r\n        return keys;\r\n    }\r\n\r\n    private async createSpineData(\r\n        atlasContent: string,\r\n        jsonContent: string,\r\n        imageElements: HTMLImageElement[],\r\n    ): Promise<any> {\r\n        const canvasArr: Record<number, HTMLCanvasElement> = {};\r\n        const baseTextureArr: Record<number, BaseTexture> = {};\r\n        const textureArr: Record<number, Texture> = {};\r\n        let textureIndex = -1;\r\n\r\n        imageElements.forEach((imageElement, index) => {\r\n            canvasArr[index] = document.createElement('canvas');\r\n            const ctx = canvasArr[index].getContext('2d')!;\r\n            canvasArr[index].width = 3000;\r\n            canvasArr[index].height = 3000;\r\n            ctx.drawImage(imageElement, 0, 0);\r\n            baseTextureArr[index] = new BaseTexture(canvasArr[index]);\r\n            textureArr[index] = new Texture(baseTextureArr[index]);\r\n        });\r\n\r\n        const atlas = new TextureAtlas(atlasContent, (line, callback) => {\r\n            if (line) {\r\n                textureIndex += 1;\r\n            }\r\n            callback(textureArr[textureIndex]);\r\n        });\r\n\r\n        const spineParser = new SpineParser().createJsonParser();\r\n        const spineData = spineParser.readSkeletonData(atlas, JSON.parse(jsonContent));\r\n\r\n        const parentResource = new LoaderResource(this.selectedSpineName, '', {\r\n            spineData,\r\n        });\r\n\r\n        parentResource.spineData = spineData;\r\n        parentResource.spineAtlas = atlas;\r\n        parentResource.data = JSON.parse(jsonContent);\r\n\r\n        return parentResource;\r\n    }\r\n\r\n    public updateAdvancedLogging(enable: boolean): void {\r\n        Logger.logServiceMessage([`Advanced logging ${enable ? 'enabled' : 'disabled'}`], this.constructor.name);\r\n        if (!enable) {\r\n            // we need to close all existing log groups before disabling advanced loggig\r\n            Logger.closeAllGroups();\r\n        }\r\n        Logger.init({ allowLogs: enable });\r\n        this.advancedLogging.next(enable);\r\n    }\r\n}\r\n","import Core, { BaseController } from '@egt/core';\nimport { fromEvent } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { ISlotConfiguration } from '../../slot-configuration/ISlotConfiguration';\nimport FeatureController from '../feature/FeatureController';\nimport Features from '../feature/Features';\nimport RestoreController from '../restore/RestoreController';\nimport RootStore from './RootStore';\nimport RootView from './RootView';\n\n@injectable()\nexport default class RootController extends BaseController {\n    private loadingFinishedBinding: any;\n    private loadingOverlay: any;\n    // use this variable instead of DISABLE_KEYBOARD_EVENTS for blocking same time use for keyboards and mouse click\n    private preventKeyboardWhenClick: boolean = false;\n\n    constructor(\n        @inject('RootView') protected view: RootView,\n        @inject('FeatureController') protected featureController: FeatureController,\n        @inject('RestoreController') protected restoreController: RestoreController,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('RootStore') protected rootStore: RootStore,\n    ) {\n        super(view);\n        // this.attachEventListeners();\n\n        this.loadingOverlay = document.getElementById('loading-overlay');\n        if (this.loadingOverlay) {\n            this.loadingFinishedBinding = this.loadingFinished.bind(this);\n            this.loadingOverlay.addEventListener('animationend', this.loadingFinishedBinding);\n        } else {\n            this.loadingFinished();\n        }\n    }\n\n    public destroy(): void {\n        this.featureController.destroy();\n        this.restoreController.destroy();\n        this.rootStore.destroy();\n\n        // @ts-ignore\n        this.settingsController = null;\n\n        // @ts-ignore\n        this.view = null;\n        // @ts-ignore\n        this.featureController = null;\n        // @ts-ignore\n        this.restoreController = null;\n        // @ts-ignore\n        this.uiManualController = null;\n        // @ts-ignore\n        this.uiAutoPlayController = null;\n        // @ts-ignore\n        this.slotConfiguration = null;\n        // @ts-ignore\n        this.videoController = null;\n        // @ts-ignore\n        this.demoModeController = null;\n        // @ts-ignore\n        this.settingsController = null;\n        // @ts-ignore\n        this.denominationController = null;\n        // @ts-ignore\n        this.gambleControler = null;\n        // @ts-ignore\n        this.rootStore = null;\n        // @ts-ignore\n        this.loadingOverlay = null;\n        // @ts-ignore\n        this.loadingFinishedBinding = null;\n        super.destroy.apply(this, arguments);\n\n        Object.keys(this).forEach((key: string) => {\n            if (this[key] && !key.includes('_') && !(this[key] instanceof Function)) {\n                this[key] = null;\n            }\n        });\n    }\n\n    protected loadingFinished(): void {\n        if (Core.configuration.mode !== 'mobile') {\n            this.attachKeyboardEventListeners();\n            fromEvent(window, 'blur').pipe(takeUntil(this.DESTROY)).subscribe(this.resetKeyBoardEvents.bind(this));\n        }\n        if (this.loadingOverlay) {\n            this.loadingOverlay.removeEventListener('animationend', this.loadingFinishedBinding);\n        }\n    }\n\n    private resetKeyBoardEvents(): void {\n        if (this.rootStore.subjects.KEY_DOWN.value) {\n            const e = new KeyboardEvent('keyup', {\n                key: this.rootStore.subjects.KEY_DOWN.value.key,\n                code: this.rootStore.subjects.KEY_DOWN.value.code,\n            });\n            document.dispatchEvent(e);\n        }\n        this.rootStore.subjects.KEY_UP.next(null);\n        this.rootStore.subjects.KEY_DOWN.next(null);\n    }\n\n    private attachKeyboardEventListeners(): void {\n        fromEvent(document, 'keyup')\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe((e) => {\n                const keyUpEv: KeyboardEvent = e as KeyboardEvent;\n                if (this.rootStore.subjects.KEY_DOWN.value === null && Core.ON_RENDERER_PAUSED.value) {\n                    this.rootStore.subjects.KEY_UP.next(null);\n                    return;\n                }\n\n                if (\n                    this.rootStore.subjects.KEY_DOWN.value === null ||\n                    keyUpEv.key !== this.rootStore.subjects.KEY_DOWN.value.key\n                ) {\n                    return;\n                }\n\n                if (!Core.DISABLE_KEYBOARD_EVENTS.value && !this.preventKeyboardWhenClick) {\n                    this.rootStore.subjects.KEY_DOWN.next(null);\n                    this.rootStore.subjects.KEY_UP.next(e);\n                }\n                e.preventDefault();\n            });\n        fromEvent(document, 'keydown')\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe((e: KeyboardEvent) => {\n                // This check is for enable input for disconect button\n                // in dev tools\n                const isInputField = document.activeElement && document.activeElement.tagName === 'INPUT';\n                if (!isInputField && ['ArrowDown', 'ArrowUp', 'PageDown', 'PageUp'].indexOf(e.key) === -1) {\n                    e.preventDefault();\n                }\n                if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) {\n                    return;\n                }\n                // if F11 is used to go to FUllscreen - switch to API fullscreen\n                // in order to can handle exit fullscreen !!!\n                if (e.code === 'F11') {\n                    e.preventDefault();\n                    if (Core.environment.isFullScreenSupported()) {\n                        Core.environment.fullScreenControl().toggle();\n                        window.focus();\n                    }\n                    return;\n                }\n\n                if (this.rootStore.subjects.KEY_DOWN.value !== null) {\n                    return;\n                }\n\n                if (Core.ON_RENDERER_PAUSED.value) {\n                    this.rootStore.subjects.KEY_DOWN.next(null);\n                    return;\n                }\n\n                if (!Core.DISABLE_KEYBOARD_EVENTS.value && !this.preventKeyboardWhenClick) {\n                    this.rootStore.subjects.KEY_DOWN.next(e);\n                }\n            });\n\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/slot/src/egt/slots/components/root/RootController.ts:165:9\",(document),\"pointerdown\"]), fromEvent(document, 'pointerdown'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe((_e) => {\n                if (!this.rootStore.subjects.KEY_DOWN.value) {\n                    this.preventKeyboardWhenClick = true;\n                }\n            });\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"L\",\"click:packages/slot/src/egt/slots/components/root/RootController.ts:172:9\",(document),\"pointerup\"]), fromEvent(document, 'pointerup'))\n            .pipe(takeUntil(this.DESTROY))\n            .subscribe((_e) => {\n                this.preventKeyboardWhenClick = false;\n            });\n\n        this.rootStore.subjects.RESET_KEY_EVENTS.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.resetKeyBoardEvents.bind(this),\n        );\n\n        this.rootStore.domainStore.SPIN_MODE.pipe(takeUntil(this.DESTROY)).subscribe(\n            this.checkForSpecialStopCondition.bind(this),\n        );\n    }\n\n    private checkForSpecialStopCondition(): void {\n        const isStopConditionReached: boolean =\n            this.rootStore.domainStore.SPIN_MODE.value === Features.MANUAL_SPIN &&\n            this.rootStore.domainStore.SPIN_MODE.prev === Features.AUTO_PLAY;\n\n        this.rootStore.subjects.SPECIAL_STOP_CONDITION_REACHED.next(isStopConditionReached);\n    }\n}\n","import Core, { AnalyticsDispatcher, BaseStore, LoggerGroups, Money, logSubjectsValues } from '@egt/core';\nimport { Texture } from 'pixi.js';\nimport { Subject } from 'rxjs';\nimport { filter, takeUntil, tap } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { Logger } from 'unicorn.console-logger';\nimport { ISlotConfiguration } from '../../slot-configuration/ISlotConfiguration';\nimport DomainStore from '../data/DomainStore';\nimport ServerState from '../data/ServerState';\nimport InitialSettings from '../data/InitialSettings';\nimport Subjects from '../data/Subjects';\nimport { ITexturesMapObject } from '../symbols/INonProportionalSymbol';\nimport UIStore from '../ui/UIStore';\nimport CustomResultStore from './CustomResultStore';\n\n@injectable()\nexport default class RootStore extends BaseStore {\n    public uiStore: UIStore;\n    public domainStore: DomainStore;\n    public customResultStore: CustomResultStore;\n    public topTexturesMap: Map<number, Texture> = new Map();\n    public texturesMap: Map<number, Texture> = new Map();\n    public blurredTexturesMap: Map<number, Texture> = new Map();\n    public readonly DESTROY: Subject<void> = new Subject<void>();\n    public complexTexturesMap: Map<number, ITexturesMapObject> = new Map();\n\n    public get settings(): InitialSettings {\n        return this._settings;\n    }\n\n    constructor(\n        @inject('InitialSettings') protected _settings: InitialSettings,\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('SlotSubjects') public readonly subjects: Subjects,\n    ) {\n        super();\n        this.enableLogging();\n\n        this.uiStore = new UIStore(_settings);\n        this.domainStore = new DomainStore(this, this.slotConfiguration);\n        this.customResultStore = new CustomResultStore(this, slotConfiguration);\n\n        this.subjects.SPIN_SPEED.pipe(\n            takeUntil(this.DESTROY),\n            tap((value) => {\n                AnalyticsDispatcher.spinSpeed = value;\n            }),\n        ).subscribe();\n\n        this.subjects.FEATURE_STARTED.pipe(takeUntil(this.DESTROY)).subscribe((feat) => {\n            if (!this.subjects.ACTIVE_FEATURE.value.includes(feat)) {\n                this.subjects.ACTIVE_FEATURE.next([...this.subjects.ACTIVE_FEATURE.value, feat]);\n            }\n        });\n        this.subjects.FEATURE_COMPLETE.pipe(takeUntil(this.DESTROY)).subscribe((feat) => {\n            const currentFeats = this.subjects.ACTIVE_FEATURE.value;\n            const idx = currentFeats.lastIndexOf(feat);\n            if (idx !== -1) {\n                currentFeats.splice(idx, 1);\n                this.subjects.ACTIVE_FEATURE.next(currentFeats);\n            }\n        });\n    }\n\n    protected enableLogging() {\n        if (Core.configuration.devTools) {\n            // TODO [NX] we have to do this due to a suspicious logic inside PaytableHTMLView.ts this.rootStore.subjects.FEATURE_MODIFY_PAYTABLE.observers.length === 0\n            logSubjectsValues(this.subjects, [this.subjects.FEATURE_MODIFY_PAYTABLE]);\n            this.subjects.BEFORE_SPIN.pipe(\n                takeUntil(this.DESTROY),\n                filter(() => Logger.allowLogs),\n                tap(() => {\n                    const currentGroup = Logger.getLastGroupName();\n\n                    switch (currentGroup) {\n                        case LoggerGroups.FREE_SPINS:\n                            Logger.openGroup(LoggerGroups.FREE_SPINS);\n                            Logger.openGroup(LoggerGroups.ROUND, true);\n                            break;\n                        default:\n                            Logger.closeGroup(currentGroup);\n                            Logger.openGroup(LoggerGroups.ROUND, true);\n                            break;\n                    }\n                }),\n            ).subscribe();\n        }\n\n        super.enableLogging();\n    }\n\n    public getBetAmount(): number {\n        return this.uiStore.SELECTED_BET.value * this.factor * Core.SELECTED_DENOMINATION.value;\n    }\n\n    public getBetAmountNormalFactor(): number {\n        return (\n            this.uiStore.SELECTED_BET.value *\n            this.settings.getFactorByUniqueGameMode('NORMAL_MODE') *\n            Core.SELECTED_DENOMINATION.value\n        );\n    }\n\n    public getModalData(numberOfAutoSpins) {\n        const betMoney = new Money(this.getBetAmount());\n        const betAmount = Core.MONEY_MODE_IN_CREDITS.value ? betMoney.stringCredits : betMoney.stringMoneyWithCurrency;\n\n        const totalBetMoney = new Money(betMoney.moneyInUnits * numberOfAutoSpins);\n        const totalBetAmount = Core.MONEY_MODE_IN_CREDITS.value\n            ? totalBetMoney.stringCredits\n            : totalBetMoney.stringMoneyWithCurrency;\n\n        return { betAmount, totalBetAmount };\n    }\n\n    public get factor(): number {\n        if (this.settings.factor) {\n            return this.settings.factor;\n        } else {\n            return this.uiStore.LINES.value;\n        }\n    }\n    public displayedMinBetUnits(exact: number): number {\n        const { bets, denominations } = this.uiStore;\n        let nearest = 0;\n\n        for (const denomination of denominations) {\n            for (const bet of bets) {\n                const value = bet * denomination * this.factor;\n                if (value <= exact && value > nearest) {\n                    nearest = value;\n                }\n            }\n        }\n\n        return nearest || exact;\n    }\n\n    public get winFactor(): number {\n        return (\n            this.domainStore.betResponse?.totalWinAmount /\n            Core.SELECTED_DENOMINATION.value /\n            (this.uiStore.SELECTED_BET.value * this.factor)\n        );\n    }\n\n    /*\n     * The two isCampaign* getters below are the campaign seam every consumer calls: each one ORs\n     * the private per-campaign checks, because a future campaign may not identify its round the way\n     * prize-pop does. When campaign #2 lands, give it its own private getter and OR it in here.\n     * If it turns out every campaign does match on round type alone, collapse these back to a single\n     * match against a shared set of campaign round types.\n     */\n    public get isCampaignOutro(): boolean {\n        return this.isPrizePopOutro;\n    }\n\n    public get isUnfinishedCampaign(): boolean {\n        return this.isUnfinishedPrizePop;\n    }\n\n    /** The server waits for a campaign collect: the campaign presents the win and applies the state after it. */\n    public get isCampaignServerState(): boolean {\n        return this.domainStore.SERVER_STATE.value === ServerState.PRIZE_POPS;\n    }\n\n    /** The last server response is a campaign collect: it carries a restore that no restore chain replays. */\n    public get isCampaignCollectResponse(): boolean {\n        return this.domainStore.serverBetResponse?.event === 'collectPrizePop';\n    }\n\n    private get isPrizePopOutro(): boolean {\n        const prizePopRound = this.domainStore.serverBetResponse?.game?.state?.rounds?.find(\n            ({ type }) => type === 'PRIZE_POP',\n        );\n\n        return prizePopRound && prizePopRound.remain === 0;\n    }\n\n    private get isUnfinishedPrizePop(): boolean {\n        // same source as isPrizePopOutro: a multi-round collectPrizePop only updates serverBetResponse.game.state\n        const prizePopRound = this.domainStore?.serverBetResponse?.game?.state?.rounds?.find(\n            ({ type }) => type === 'PRIZE_POP',\n        );\n\n        return prizePopRound && prizePopRound.remain > 0;\n    }\n\n    public get increaseMultipliersWinFactor(): number {\n        return (\n            this.domainStore.betResponse?.stateWinAmount /\n            Core.SELECTED_DENOMINATION.value /\n            (this.uiStore.SELECTED_BET.value * this.settings.getFactorByUniqueGameMode('NORMAL_MODE'))\n        );\n    }\n\n    public get isBuyBonusThresholdMode(): boolean {\n        return (this.slotConfiguration.buyBonusThresholdGameModes ?? []).includes(this.settings.gameMode);\n    }\n\n    public get coinFeatureCoefActive(): number[] {\n        return this.isBuyBonusThresholdMode\n            ? (this.slotConfiguration.coinFeatureCoefBuyBonus ?? this.slotConfiguration.coinFeatureCoef)\n            : this.slotConfiguration.coinFeatureCoef;\n    }\n\n    public get isGreatWin(): boolean {\n        const winFactorWhenBB = this.subjects.EXTENDED_MULTIPLE_BUY_BONUS_ACTIVATED.value\n            ? this.domainStore.betResponse?.totalWinAmount /\n              Core.SELECTED_DENOMINATION.value /\n              (this.uiStore.SELECTED_BET.value * this.settings.getFactorByUniqueGameMode('NORMAL_MODE'))\n            : this.winFactor;\n        return winFactorWhenBB >= this.coinFeatureCoefActive[0] ? true : false;\n    }\n\n    public getReelsScaleFactor(symbolResolution: number = 1, portraitFirst: boolean = true): number {\n        let scaleFactor: number = 1 / symbolResolution;\n        if (\n            (Core.ORIENTATION.value.isLandscape && portraitFirst) ||\n            (Core.ORIENTATION.value.isPortrait && !portraitFirst)\n        ) {\n            scaleFactor = this.subjects.REELS_SCALE_FACTOR.value;\n        }\n        return scaleFactor;\n    }\n    public get expandWinFactor(): number {\n        let totalWin = this.domainStore.betResponse?.totalWinAmount;\n        if (this.domainStore.currentSpinResults === 0 && this.domainStore.betResponse?.result?.spins?.length > 1) {\n            totalWin = this.domainStore.betResponse.result.totalWinAmount;\n        }\n        return totalWin / Core.SELECTED_DENOMINATION.value / (this.uiStore.SELECTED_BET.value * this.factor);\n    }\n\n    public get isGreatWinOnExpand(): boolean {\n        return this.expandWinFactor >= this.coinFeatureCoefActive[0] ? true : false;\n    }\n    public get cascadeWinFactor(): number {\n        let factor: number;\n        if (this.settings.factors) {\n            factor = this.settings.getFactorByUniqueGameMode('NORMAL_MODE');\n        } else {\n            factor = this.uiStore.LINES.value;\n        }\n        const denomination: number = Core.SELECTED_DENOMINATION.value;\n        const totalWin: number = this.domainStore.betResponse\n            ? this.domainStore.betResponse.result.totalWinAmount >= 0\n                ? this.domainStore.betResponse.result.totalWinAmount\n                : this.domainStore.betResponse.totalWinAmount\n            : 0;\n        return totalWin / denomination / (this.uiStore.SELECTED_BET.value * factor);\n    }\n    public get isCascadeGreatWin(): boolean {\n        return this.slotConfiguration.cascadeGame && this.cascadeWinFactor >= this.coinFeatureCoefActive[0]\n            ? true\n            : false;\n    }\n    public get totalWinFactor(): number {\n        let factor: number;\n\n        if (this.settings.linesOptions.length > 1) {\n            factor = this.uiStore.LINES.value;\n        } else {\n            factor = this.settings.getFactorByUniqueGameMode('NORMAL_MODE');\n        }\n        const denomination: number = Core.SELECTED_DENOMINATION.value;\n        const totalWin: number =\n            this.domainStore.betResponse.result.totalWinAmount >= 0\n                ? this.domainStore.betResponse.result.totalWinAmount\n                : this.domainStore.betResponse.totalWinAmount;\n        return totalWin / denomination / (this.uiStore.SELECTED_BET.value * factor);\n    }\n\n    public get isTotalGreatWin(): boolean {\n        return this.totalWinFactor >= this.coinFeatureCoefActive[0] ? true : false;\n    }\n\n    public destroy(): void {\n        this.DESTROY.next();\n        this.DESTROY.complete();\n\n        // @ts-ignore\n        this.DESTROY = null;\n\n        this.texturesMap.forEach((textur, _key) => {\n            textur?.destroy();\n            // @ts-ignore\n            textur = null;\n        });\n\n        if (this.slotConfiguration) {\n            // @ts-ignore\n            this.slotConfiguration = null;\n        }\n\n        this.topTexturesMap.forEach((textur) => {\n            textur?.destroy();\n            // @ts-ignore\n            textur = null;\n        });\n\n        this.complexTexturesMap.forEach((texture) => {\n            texture.texture?.destroy();\n            texture.blurredTexture?.destroy();\n            texture.topTexture?.destroy();\n            texture.landscapeTexture?.destroy();\n            texture.landcsapeBluredTexture?.destroy();\n            texture.landscapeTopTexture?.destroy();\n            // @ts-ignore\n            texture = null;\n        });\n\n        this.blurredTexturesMap.forEach((textur) => {\n            textur?.destroy();\n            // @ts-ignore\n            textur = null;\n        });\n        this.topTexturesMap.clear();\n        this.texturesMap.clear();\n        this.blurredTexturesMap.clear();\n\n        this.uiStore.destroy();\n        this.domainStore.destroy();\n        this.customResultStore.destroy();\n\n        this.subjects.destroy();\n        // @ts-ignore\n        this.uiStore = null;\n        // @ts-ignore\n        this.domainStore = null;\n        // @ts-ignore\n        this.customResultStore = null;\n        // @ts-ignore\n        this.topTexturesMap = null;\n        // @ts-ignore\n        this.texturesMap = null;\n        // @ts-ignore\n        this.blurredTexturesMap = null;\n        // @ts-ignore\n        this.subjects = null;\n    }\n}\n","import { ViewContainer } from '@egt/ui-lib';\nimport { takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport RootStore from './RootStore';\n\n@injectable()\nexport default class RootView extends ViewContainer {\n    constructor(@inject('RootStore') protected rootStore: RootStore) {\n        super();\n        // this.setFontStyles();\n        this.sortableChildren = true;\n        this.rootStore.subjects.CHANGE_Z_ORDER.pipe(takeUntil(this.DESTROY)).subscribe((values) => {\n            values.forEach((val) => {\n                const found = this.children.find((child) => val.name === child.name);\n                if (found) {\n                    found.zIndex = val.order;\n                }\n            });\n        });\n\n        this.rootStore.subjects.SHOW_HIDE_VIEW.pipe(takeUntil(this.DESTROY)).subscribe((val) => {\n            const found = this.children.find((child) => val.name === child.name);\n            if (found) {\n                found.visible = val.display;\n            }\n        });\n    }\n    public destroy(): void {\n        // @ts-ignore\n        this.rootStore = null;\n        super.destroy({ children: true, texture: true, baseTexture: true });\n    }\n}\n","import Core, { IVideoPlayer } from '@egt/core';\nimport { ReelDefault } from '@egt/reels';\nimport { ViewContainer } from '@egt/ui-lib';\nimport { Sprite } from 'pixi.js';\nimport { race } from 'rxjs';\nimport { first, takeUntil } from 'rxjs/operators';\nimport { inject, injectable } from 'tsyringe';\nimport { ISlotConfiguration } from '../../slot-configuration/ISlotConfiguration';\nimport RootStore from '../root/RootStore';\n\n@injectable()\nexport default class StopVideoView extends ViewContainer {\n    constructor(\n        @inject('ISlotConfiguration') protected slotConfiguration: ISlotConfiguration,\n        @inject('RootStore') protected rootStore: RootStore,\n    ) {\n        super();\n        this.rootStore.subjects.REEL_STOPPED.pipe(takeUntil(this.DESTROY)).subscribe(this.startVideos.bind(this));\n    }\n\n    private startVideos(reel: ReelDefault): void {\n        const result: number[] = reel.getResult();\n        const symbols: number[] = result.slice(1, result.length - 1);\n\n        symbols.forEach((symbol, index) => {\n            if (symbol > 100) {\n                const symbolIndex: number | undefined = this.getImage(symbol);\n                if (symbolIndex) {\n                    symbol = symbolIndex;\n                }\n            }\n            const videoConfig: any = this.slotConfiguration.symbolsConfig[symbol].stopVideo;\n            const asset: any = videoConfig ? Core.assets.getAsset(videoConfig.id) : null;\n            if (asset && asset.spritesheet) {\n                this.startVideo(asset, videoConfig, index, reel.getIndex());\n            }\n        });\n    }\n\n    private getImage(symbolIndex: number): number | undefined {\n        for (let i: number = 0; i < this.slotConfiguration.symbolsConfig.length; i++) {\n            if (this.slotConfiguration.symbolsConfig[i].index === symbolIndex) {\n                return i;\n            }\n        }\n    }\n\n    private startVideo(asset: any, videoConfig: any, col: number, row: number): void {\n        const symbolTextures = asset.spritesheet.textures;\n        const videoPlayer: IVideoPlayer = Core.createVideoPlayer();\n        const symbolSprite: Sprite = new Sprite();\n        symbolSprite.x =\n            (this.rootStore.subjects.REELS_POSITION.value.reelWidth +\n                this.rootStore.subjects.REELS_POSITION.value.reelSpacing) *\n                row +\n            this.rootStore.subjects.REELS_POSITION.value.reelWidth / 2;\n        symbolSprite.y =\n            this.rootStore.subjects.REELS_POSITION.value.symbolHeight * col +\n            this.rootStore.subjects.REELS_POSITION.value.symbolHeight / 2;\n        symbolSprite.anchor.set(0.5);\n        this.addChild(symbolSprite);\n\n        videoPlayer.frames = Object.keys(symbolTextures).map((personNamedIndex) => {\n            return symbolTextures[personNamedIndex];\n        });\n        videoPlayer.config = videoConfig;\n\n        race(videoPlayer.VIDEO_COMPLETE, this.rootStore.subjects.REELS_STOPPED)\n            .pipe(first())\n            .subscribe(() => {\n                videoPlayer.stop();\n                videoPlayer.removeAllInstances();\n                this.removeChild(symbolSprite);\n                Core.destroyVideoPlayer(videoPlayer);\n            });\n\n        videoPlayer.addInstance(symbolSprite);\n        videoPlayer.play();\n    }\n}\n","import { Texture } from 'pixi.js';\nimport { INonProportionalSymbol } from './INonProportionalSymbol';\nimport SymbolBase from './SymbolBase';\n\nexport default class NonProportionalSymbol extends SymbolBase implements INonProportionalSymbol {\n    constructor(\n        protected _texture: Texture,\n        protected _topTexture: Texture,\n        protected _blurredTexture: Texture,\n        private _landscapeTexture: Texture,\n        private _landscapeTopTexture: Texture,\n        private _landscapeBlurredTexture: Texture,\n        protected _index: number,\n        protected _name: string,\n        protected _video: any,\n        protected _expandVideo?: any,\n        protected _expandSound?: any,\n        protected _isScatter?: boolean,\n        protected _isStackedScatter?: boolean,\n        protected _isVerticalStackedSymbol?: boolean,\n        protected _isWild?: boolean,\n        protected _stopWildSound?: any,\n        protected _scatterConfig?: any,\n        protected _stopVideo?: any,\n    ) {\n        super(\n            _texture,\n            _topTexture,\n            _blurredTexture,\n            _index,\n            _name,\n            _video,\n            _expandVideo,\n            _expandSound,\n            _isScatter,\n            _isStackedScatter,\n            _isVerticalStackedSymbol,\n            _isWild,\n            _stopWildSound,\n            _scatterConfig,\n            _stopVideo,\n        );\n    }\n\n    landscapeTexture(): Texture {\n        return this._landscapeTexture;\n    }\n\n    landscapeTopTexture(): Texture {\n        return this._landscapeTopTexture;\n    }\n\n    landcsapeBluredTexture(): Texture {\n        return this._landscapeBlurredTexture;\n    }\n}\n","import { Texture } from 'pixi.js';\nimport { ISymbol } from './ISymbol';\n\nexport default class SymbolBase implements ISymbol {\n    constructor(\n        protected _texture: Texture,\n        protected _topTexture: Texture,\n        protected _blurredTexture: Texture,\n        protected _index: number,\n        protected _name: string,\n        protected _video: any,\n        protected _expandVideo?: any,\n        protected _expandSound?: any,\n        protected _isScatter?: boolean,\n        protected _isStackedScatter?: boolean,\n        protected _isVerticalStackedSymbol?: boolean,\n        protected _isWild?: boolean,\n        protected _stopWildSound?: any,\n        protected _scatterConfig?: any,\n        protected _stopVideo?: any,\n    ) {\n        // Implement\n    }\n\n    public texture(): Texture {\n        return this._texture;\n    }\n\n    public setTexture(texture: Texture): void {\n        this._texture = texture;\n    }\n\n    public topTexture(): Texture {\n        return this._topTexture;\n    }\n\n    public blurredTexture(): Texture {\n        return this._blurredTexture;\n    }\n    public index(): number {\n        return this._index;\n    }\n\n    public name(): string {\n        return this._name;\n    }\n\n    public video(): any {\n        return this._video;\n    }\n\n    public stopVideo(): any {\n        return this._stopVideo;\n    }\n\n    public expandVideo(): any {\n        return this._expandVideo;\n    }\n\n    public expandSound(): any {\n        return this._expandSound;\n    }\n\n    public isScatter(): any {\n        return this._isScatter;\n    }\n\n    public isStackedScatter(): any {\n        return this._isStackedScatter;\n    }\n\n    public isVerticalStackedSymbol(): any {\n        return this._isVerticalStackedSymbol;\n    }\n\n    public isWild(): any {\n        return this._isWild;\n    }\n\n    public stopWildSound(): any {\n        return this._stopWildSound;\n    }\n\n    public scatterConfig(): any {\n        return this._scatterConfig;\n    }\n}\n","const enum BangupActionConsts {\n    /** Called on load game to set last win*/\n    RESTORE = 'restore',\n    /** Called when no animation needed (restore) Direct set of amount */\n    SET = 'set',\n    /** Called when win. Bang up from 0 to amount */\n    WIN = 'win',\n    /** Called when accumulated wins (we need to add this separate win). Bang up from current to accumulated amount */\n    ADD = 'add',\n    /** Called when accumulated win received (FS,etc.). Bang up from current to the new amount */\n    BANGUP = 'bangup',\n    /** Called when collect. Down WIN amount to 0 */\n    COLLECT = 'collect',\n}\nexport default BangupActionConsts;\n","import Core, { Timers } from '@egt/core';\nimport { ViewContainer } from '@egt/ui-lib';\nimport { takeUntil } from 'rxjs/operators';\nimport { ISlotConfiguration } from '../../slot-configuration/ISlotConfiguration';\nimport RootStore from '../root/RootStore';\n\nexport default class SpinSpeedIndicator extends ViewContainer {\n    public timer: any;\n    protected spineAnimation: any;\n    private spinTime = 0;\n\n    constructor(\n        protected rootStore: RootStore,\n        protected config: ISlotConfiguration,\n    ) {\n        super();\n\n        this.rootStore.subjects.SPIN_STARTED.pipe(takeUntil(this.DESTROY)).subscribe(this.startLoader.bind(this));\n        this.rootStore.subjects.REELS_STOPPED.pipe(takeUntil(this.DESTROY)).subscribe(this.stopLoader.bind(this));\n\n        // const animAsset = Core.assets.getAsset('progressSpinTime');\n        // this.spineAnimation = new PIXI.spine.Spine(animAsset.spineData);\n        this.spineAnimation = Core.spineAnimations.createSpineAnimations('progressSpinTime');\n        this.spineAnimation.x = 66;\n        this.spineAnimation.y = 32;\n        this.addChild(this.spineAnimation);\n\n        this.spinTime = this.rootStore.subjects.REELS_MINIMUM_SPIN_TIME.value;\n\n        this.spineAnimation.state.timeScale = 0;\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"spine:packages/slot/src/egt/slots/components/ui/SpinSpeedIndicator.ts:31:9\",\"loadingAnimation\"]), this.spineAnimation.state.setAnimation(0, 'loadingAnimation', false));\n        this.spineAnimation.visible = true;\n\n        this.rootStore.subjects.MIN_TIME_ROLL.pipe(takeUntil(this.DESTROY)).subscribe(this.startStopLoader.bind(this));\n    }\n\n    public destroy(): void {\n        // @ts-ignore\n        if (this.spineAnimation) {\n            this.spineAnimation.destroy();\n            this.spineAnimation = null;\n        }\n        super.destroy();\n    }\n\n    private startStopLoader(start: boolean = false): void {\n        if (start) {\n            this.startLoader();\n        } else {\n            this.stopLoader();\n        }\n    }\n\n    private startLoader(): void {\n        Timers.setTimeout(() => {\n            const spineAnimationTime = 1100;\n            this.spineAnimation.state.timeScale = spineAnimationTime / this.spinTime;\n            (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"spine:packages/slot/src/egt/slots/components/ui/SpinSpeedIndicator.ts:58:13\",\"loadingAnimation\"]), this.spineAnimation.state.setAnimation(0, 'loadingAnimation', false));\n\n            this.spineAnimation.visible = true;\n        }, 0);\n    }\n\n    private stopLoader(): void {\n        this.spineAnimation.state.timeScale = 0;\n        (((window as any).__SLQ=(window as any).__SLQ||[]).push([\"t\",\"spine:packages/slot/src/egt/slots/components/ui/SpinSpeedIndicator.ts:66:9\",\"loadingAnimation\"]), this.spineAnimation.state.setAnimation(0, 'loadingAnimation', false));\n        this.spineAnimation.visible = true;\n    }\n}\n","const enum UIState {\n    UNSET = 'unset',\n    DISABLED = 'disabled',\n    SLIDING_BETS = 'slidingBets',\n    WIN = 'win',\n    IDLE = 'idle',\n    BONUS_IDLE = 'bonusIdle',\n    COLLECT_BEFORE_IDLE = 'collectBeforeIdle',\n    BONUS_SUMMARY = 'bonusSummary',\n    WAITING_FOR_RESPONSE = 'waitingForResponse',\n    WAITING_FOR_RESPONSE_IN_AUTOPLAY = 'waitingForResponseAutoplay',\n    WAITING_FOR_RESPONSE_IN_FREESPIN = 'waitingForResponseFreespin',\n    WAITING_FOR_RESPONSE_IN_RESPIN = 'waitingForResponseInRespin',\n    WAITING_FOR_RESPONSE_IN_GIFTSPINS = 'waitingForResponseInGiftspins',\n    WAITING_FOR_COLLECT = 'waitingForCollect',\n    WAITING_FOR_COLLECT_IN_AUTOPLAY = 'waitingForCollectInAutoplay',\n    WAITING_FOR_COLLECT_IN_FREE_SPINS = 'waitingForCollectInFreeSPins',\n    GAMBLE = 'gamble',\n    WAITING_FOR_STATE_CHANGE = 'waitingForStateChange',\n    GAMBLE_WIN = 'gambleWin',\n    FREESPIN = 'freespin',\n    BELL_LINK = 'bell_link',\n    CASH_HEAT = 'cash_heat',\n    GODS_AND_KINGS_LINK = 'gods_and_kings_link',\n    BONUS_CHANCE = 'bonusChance',\n    PICK_ME_BONUS = 'pick',\n    EXIT_FREESPIN = 'exitFreeSpin',\n    LAST_GAMBLE_WIN = 'lastGambleWin',\n    RESPIN = 'respin',\n    FREERESPIN = 'freeRespin',\n    MYSTERY = 'mystery',\n    HIGH_CASH_FEATURE = 'highCashFeature',\n    MAIN_RESPIN = 'mainRespin',\n    PRIZE_POP = 'prizePop',\n}\nexport default UIState;\n","import { BackgroundMusic } from '@egt/background-sound';\nimport Core, { BaseStore, LoggerGroups } from '@egt/core';\nimport { SettingsTab } from '@egt/settings-popup';\nimport { UIViewModes } from '@egt/ui-view';\nimport { BehaviorSubject, Subject } from 'rxjs';\nimport { filter, skip } from 'rxjs/operators';\nimport { Logger } from 'unicorn.console-logger';\nimport ChainSubject from '../data/ChainSubject';\nimport HistorySubject from '../data/HistorySubject';\nimport InitialSettings from '../data/InitialSettings';\nimport PausableSubject from '../data/PausableSubject';\nimport CentralWinActions from '../enums/CentralWinActions';\nimport SlotComponents from '../enums/SlotComponents';\nimport Features from '../feature/Features';\nimport Line from '../lines/Line';\nimport LineMode from '../lines/LineMode';\nimport BangupActionConsts from './BangupActionConsts';\nimport UIState from './UIState';\n\nexport default class UIStore extends BaseStore {\n    public currency: string = '';\n    public denominations: number[] = [];\n    public units: number = 100;\n    public bets: number[] = [];\n    public autoPlayFromSettings: boolean = false;\n\n    //this event should be dispatched only when new bet request is created this is for notification for new bet to server\n    public readonly NEW_BET_REQUEST_CREATED = new Subject();\n    // Generic\n    public readonly STATE: PausableSubject<string> = new PausableSubject(UIState.IDLE);\n    public readonly RESTORE_STATE = new Subject();\n    public readonly BALANCE: BehaviorSubject<number> = new BehaviorSubject(0);\n    public readonly SELECTED_BET: HistorySubject<number> = new HistorySubject(0);\n    public readonly CURRENT_BET_LEVEL: BehaviorSubject<any> = new BehaviorSubject({ betLevel: 0, denomLevel: 0 });\n    public readonly VISIBLE_BETS: HistorySubject<number[]> = new HistorySubject([]);\n    public readonly SHOW_FAKE_ACTIVE_BET: Subject<{ index: number; visible: boolean }> = new Subject();\n    public readonly ANIMATE_BET_BTNS: Subject<'slideLeft' | 'slideRight' | 'none'> = new Subject();\n    public readonly WIN: HistorySubject<{\n        amount: number;\n        action: BangupActionConsts;\n        feature: Features | string;\n        duration?: number;\n        centralWinAction?: CentralWinActions;\n    }> = new HistorySubject({\n        amount: 0,\n        action: BangupActionConsts.SET,\n        feature: Features.NONE,\n        duration: undefined,\n        centralWinAction: CentralWinActions.NONE,\n    });\n    // public readonly SELECTED_DENOMINATION: BehaviorSubject<number> = new BehaviorSubject(1);\n    public readonly AUTOPLAY_BET_COUNTER: BehaviorSubject<number> = new BehaviorSubject(0);\n    public readonly SELECTED_SETTINGS_TAB: BehaviorSubject<SettingsTab> = new BehaviorSubject(SettingsTab.GENERAL);\n    public readonly SHOW_HIDE_BET_BUTTONS: BehaviorSubject<boolean> = new BehaviorSubject(true);\n    public readonly SHOW_HIDE_EXACT_BET_BUTTON: Subject<{\n        index: number;\n        visible: boolean;\n        shouldAlterPosition: boolean;\n        alteredPosition?: { [K in 'desktop' | 'landscape' | 'portrait']?: { x?: number; y?: number } };\n    }> = new Subject();\n    public readonly SHOW_HIDE_GIFT_SPINS_VIEW: BehaviorSubject<boolean> = new BehaviorSubject(false);\n\n    // Reels\n    public readonly FAKE_REELS: BehaviorSubject<number[][]> = new BehaviorSubject([]);\n    public readonly REAL_REELS: BehaviorSubject<number[][]> = new BehaviorSubject([]);\n    public readonly HORIZONTAL_REEL: BehaviorSubject<number[]> = new BehaviorSubject([]);\n    // public readonly RESET_REELS = new Subject();\n    public drawNow: boolean;\n\n    // Gamble\n    public gamblesLeft: number = 5;\n    public readonly HISTORY: BehaviorSubject<number[]> = new BehaviorSubject([]);\n\n    // Freespin\n    // public readonly SHOW_FREE_SPIN: BehaviorSubject<boolean> = new BehaviorSubject(false);\n\n    // Autoplay\n    public quickSpinEnabled: boolean = false;\n    public disableSpecialSpinSpeedForCurrentState: boolean = false;\n    public fastSpinMode: boolean = false;\n    public turboModeEnabled: boolean = false;\n    // public turboModeDeactivated: boolean = false;\n    public turboModeLastWin: number = 0;\n    public winLimitValue: number = 0;\n    public balanceStartValue: number = 0;\n    public balanceDecreaseValue: number = 0;\n    private _balanceIncreaseValue: number = 0;\n    public maxTotalLossLimit: number = 0;\n    public currentTotalLoss: number = 0;\n    public allRestrictionsApplied: boolean = false;\n    public lastResponseFromBlitzPlay: boolean = false;\n\n    public set balanceIncreaseValue(value: number) {\n        this._balanceIncreaseValue = value;\n    }\n\n    public get balanceIncreaseValue() {\n        return this._balanceIncreaseValue;\n    }\n    // Lines\n    public readonly LINES: BehaviorSubject<number> = new BehaviorSubject(-1); // MARK\n    public readonly LINES_TO_SHOW: BehaviorSubject<any[]> = new BehaviorSubject([]); // MARK\n    public readonly FORCE_START_LINES = new Subject();\n    public readonly CLEAR_LINES = new Subject(); // MARK\n    // use this event when you want to hide the lines from stage but show message bar\n    public readonly HIDE_LINES_FROM_STAGE: BehaviorSubject<boolean> = new BehaviorSubject(false);\n    // public readonly HIDE_LINES = new Subject(); // MARK\n\n    // fast line cycle is stopped for now to enable it set the value to true\n    public readonly FAST_CYCLE: BehaviorSubject<boolean> = new BehaviorSubject(false);\n\n    // Active line properties:\n    public readonly ACTIVE_LINE: BehaviorSubject<number | Line> = new BehaviorSubject(-1);\n    public readonly ACTIVE_LINE_IS_DARKENED: BehaviorSubject<boolean> = new BehaviorSubject(false);\n\n    // when switching line we show them for 2 seconds\n    public readonly SHOW_ALL_LINES: BehaviorSubject<boolean> = new BehaviorSubject(false);\n\n    public readonly SHOW_SETTINGS: BehaviorSubject<boolean> = new BehaviorSubject(false);\n\n    // collect\n    public readonly COLLECT_CLICKED = new ChainSubject();\n    public readonly COLLECT_CHANGED = new Subject();\n\n    // public readonly SPIN_BTN_CLICKED = new ChainSubject();\n\n    // Demo Result\n    public selectedDemoResult: string = '';\n\n    // Bangup\n    public readonly CLEAR_BANG_UP = new Subject();\n    public readonly BANGUP_RUNNING: BehaviorSubject<boolean> = new BehaviorSubject(false);\n\n    // subscriber is used as proxy to control to play or not background music\n    public readonly BACKGROUND_SOUND_PLAY: BehaviorSubject<{\n        sound: BackgroundMusic;\n        ms: number;\n        msNoPlay?: number;\n        seek?: number;\n    }> = new BehaviorSubject({ sound: undefined, ms: 0, msNoPlay: undefined });\n\n    // subscriber is used as proxy to control the fade in/out of the background music so it can be played in sync with creditAnimationSound\n    public readonly SYNC_BACKGROUND_AND_CREDIT_SOUNDS: BehaviorSubject<boolean> = new BehaviorSubject(false);\n\n    public winSoundPlaying: string = '';\n    public creditLineSoundPlaying: string = '';\n\n    private _loading: boolean = false;\n\n    constructor(settings: InitialSettings) {\n        super();\n        this.enableLogging();\n\n        this.BALANCE.next(settings.balance);\n\n        this.setBet(settings);\n\n        this.STATE.next(settings.state);\n\n        if (Core.configuration.devTools) {\n            this.STATE.pipe(\n                skip(1),\n                filter((state) => {\n                    return state === UIState.FREESPIN;\n                }),\n            ).subscribe(() => {\n                if (!Logger.getAllGroupsList().includes(LoggerGroups.FREE_SPINS)) {\n                    Logger.closeAllGroups();\n                    Logger.openGroup(LoggerGroups.FREE_SPINS);\n                }\n            });\n        }\n\n        this.WIN.next({ amount: settings.winAmount, action: BangupActionConsts.RESTORE, feature: Features.NONE });\n\n        this.bets = settings.bets;\n        this.currency = settings.currency;\n        this.units = settings.units;\n        this.denominations = settings.denominations;\n        /* if (settings.freespin) {\n            this.enterFreeSpin = settings.freespin.count === settings.freespin.remaining;\n        } */\n        if (settings.entries) {\n            this.LINES_TO_SHOW.next(settings.entries.sort((a, b) => a.line - b.line).slice());\n            this.LINES_TO_SHOW.value.forEach((line) => {\n                line.symbols = [];\n                for (let i = 0; i < line.cells.length - 1; i += 2) {\n                    if (line.mode !== LineMode.WAYS) {\n                        line.symbols.push(settings.reels[line.cells[i]][line.cells[i + 1] + 1]);\n                    }\n                }\n            });\n        }\n        this.LINES.next(settings.lines);\n        this.drawNow = true;\n    }\n\n    public get denominationInMoney(): number {\n        return Core.SELECTED_DENOMINATION.value / 100;\n    }\n\n    public get loading(): boolean {\n        return this._loading;\n    }\n\n    public set loading(value: boolean) {\n        if (this._loading !== value) {\n            this._loading = value;\n        }\n    }\n\n    public destroy(): void {\n        this.RESTORE_STATE.complete();\n    }\n\n    private setBet(settings: InitialSettings) {\n        if (Core.configuration.demo) {\n            this.setMaxBetValues(settings);\n        } else {\n            this.setResponseBetValues(settings);\n        }\n    }\n\n    private setMaxBetValues(settings: InitialSettings) {\n        const turtleUIBetOffset: number = Core.hasComponent(SlotComponents.UI_VIEW, UIViewModes.TURTLE) ? 2 : 0;\n        Core.SELECTED_DENOMINATION.next(settings.denominations[settings.denominations.length - 1]);\n        this.SELECTED_BET.next(settings.bets[settings.bets.length - 1 - turtleUIBetOffset]);\n    }\n\n    private setResponseBetValues(settings: InitialSettings) {\n        Core.SELECTED_DENOMINATION.next(settings.denomination);\n        this.SELECTED_BET.next(settings.bet);\n    }\n}\n","import {\n    AutoplayPopupComponentConfigurationDefault,\n    IAutoplayButtonInterfaceDefault,\n    IAutoplayPopupInterfaceDefault,\n} from '@egt/autoplay-popup';\nimport { AssetPriority, AssetsCollection, DynamicPositionObject, ModifyAssets, ModifyValue } from '@egt/core';\nimport { TextStyle } from 'pixi.js';\n\nexport default function SingleProgressiveAutoplayPopupComponentConfigurationFactoryDefault(\n    ClassType: typeof AutoplayPopupComponentConfigurationDefault,\n): typeof AutoplayPopupComponentConfigurationDefault {\n    class SingleProgressiveAutoplayPopupComponentConfiguration extends ClassType {\n        @ModifyAssets([\n            {\n                id: 'svgBet',\n                url: '../assets/components/slot/autoplay-popup/default/ui-svg/standardButton.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 120, height: 96 },\n                    desktop: { width: 94, height: 75 },\n                },\n            },\n            {\n                id: 'svgBetPressed',\n                url: '../assets/components/slot/autoplay-popup/default/ui-svg/standardButtonPressed.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 120, height: 96 },\n                    desktop: { width: 94, height: 75 },\n                },\n            },\n            {\n                id: 'svgBetHover',\n                url: '../assets/components/slot/autoplay-popup/default/ui-svg/standardButtonHover.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 120, height: 96 },\n                    desktop: { width: 94, height: 75 },\n                },\n            },\n            {\n                id: 'svgActiveBet',\n                url: '../assets/components/slot/autoplay-popup/default/ui-svg/greenButton.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 120, height: 96 },\n                    desktop: { width: 94, height: 75 },\n                },\n            },\n            {\n                id: 'svgActiveBetPressed',\n                url: '../assets/components/slot/autoplay-popup/default/ui-svg/greenButtonPressed.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 120, height: 96 },\n                    desktop: { width: 94, height: 75 },\n                },\n            },\n            {\n                id: 'svgActiveBetHover',\n                url: '../assets/components/slot/autoplay-popup/default/ui-svg/greenButtonHover.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 120, height: 96 },\n                    desktop: { width: 94, height: 75 },\n                },\n            },\n        ])\n        public assets: AssetsCollection;\n\n        @ModifyValue<IAutoplayPopupInterfaceDefault>({\n            defaults: {\n                titleStyle: new TextStyle({\n                    fontFamily: 'Arial',\n                    fill: 0xcfcfcf,\n                    fontWeight: 'bold',\n                    fontSize: 21,\n                    letterSpacing: 0,\n                }),\n            },\n        })\n        public popupProps: DynamicPositionObject<IAutoplayPopupInterfaceDefault> & IAutoplayPopupInterfaceDefault;\n\n        @ModifyValue<IAutoplayButtonInterfaceDefault>({\n            defaults: {\n                textStyle: new TextStyle({\n                    fontFamily: 'Arial',\n                    fill: '#FFFFFF',\n                    fontWeight: 'bold',\n                    fontSize: 35,\n                }),\n                infinityTexture: 'svgInfinity',\n            },\n        })\n        public autoplayButtonProps: DynamicPositionObject<IAutoplayButtonInterfaceDefault> &\n            IAutoplayButtonInterfaceDefault;\n    }\n    return SingleProgressiveAutoplayPopupComponentConfiguration;\n}\n","import { AssetPriority, AssetsCollection, DynamicPositionObject, ModifyAssets, ModifyValue } from '@egt/core';\nimport {\n    AutoplayPopupComponentConfigurationExtended,\n    IAutoplayBtnTextExtended,\n    IAutoplayPopUpTextExtended,\n    IAutoplayPopUpTitleTextExtended,\n    IBalanceAndBetTextExtended,\n} from '@egt/autoplay-popup';\nimport { TextStyle } from 'pixi.js';\n\nexport default function SingleProgressiveAutoplayPopupComponentConfigurationFactoryExtended(\n    ClassType: typeof AutoplayPopupComponentConfigurationExtended,\n): typeof AutoplayPopupComponentConfigurationExtended {\n    class SingleProgressiveAutoplayPopupComponentConfigurationExtended extends ClassType {\n        @ModifyAssets([\n            // {\n            //     id: 'autoplayResources',\n            //     url: '../assets/autoplayResources.json',\n            //     priority: AssetPriority.HIGHEST,\n            //     type: 'texture',\n            // },\n            // {\n            //     id: 'svgAutoplaySelected',\n            //     url: '../assets/uiSvg/autoplaySelected.svg',\n            //     priority: AssetPriority.HIGHEST,\n            //     type: 'svg',\n            //     config: {\n            //         mobile: { width: 132, height: 132 },\n            //         desktop: { width: 99, height: 99 },\n            //     },\n            // },\n            // {\n            //     id: 'svgSliderDotActive',\n            //     url: '../assets/uiSvg/sliderDotActive.svg',\n            //     priority: AssetPriority.HIGHEST,\n            //     type: 'svg',\n            //     config: {\n            //         mobile: { width: 74, height: 74 },\n            //         desktop: { width: 74, height: 74 },\n            //     },\n            // },\n            // {\n            //     id: 'svgSliderDotInactive',\n            //     url: '../assets/uiSvg/sliderDotInactive.svg',\n            //     priority: AssetPriority.HIGHEST,\n            //     type: 'svg',\n            //     config: {\n            //         mobile: { width: 74, height: 74 },\n            //         desktop: { width: 74, height: 74 },\n            //     },\n            // },\n            // {\n            //     id: 'svgSliderDotPressed',\n            //     url: '../assets/uiSvg/sliderDotPressed.svg',\n            //     priority: AssetPriority.HIGHEST,\n            //     type: 'svg',\n            //     config: {\n            //         mobile: { width: 74, height: 74 },\n            //         desktop: { width: 74, height: 74 },\n            //     },\n            // },\n            // {\n            //     id: 'svgSliderDotHover',\n            //     url: '../assets/uiSvg/sliderDotHover.svg',\n            //     priority: AssetPriority.HIGHEST,\n            //     type: 'svg',\n            //     config: {\n            //         mobile: { width: 74, height: 74 },\n            //         desktop: { width: 74, height: 74 },\n            //     },\n            // },\n            // {\n            //     id: 'svgAutoplayPopUpHover',\n            //     url: '../assets/uiSvg/autoplayPopUpHover.svg',\n            //     priority: AssetPriority.HIGHEST,\n            //     type: 'svg',\n            //     config: {\n            //         mobile: { width: 104, height: 74 },\n            //         desktop: { width: 104, height: 74 },\n            //     },\n            // },\n            // {\n            //     id: 'svgAutoplayPopUpNormal',\n            //     url: '../assets/uiSvg/autoplayPopUpNormal.svg',\n            //     priority: AssetPriority.HIGHEST,\n            //     type: 'svg',\n            //     config: {\n            //         mobile: { width: 104, height: 74 },\n            //         desktop: { width: 104, height: 74 },\n            //     },\n            // },\n            // {\n            //     id: 'svgAutoplayPopUpSelected',\n            //     url: '../assets/uiSvg/autoplayPopUpSelected.svg',\n            //     priority: AssetPriority.HIGHEST,\n            //     type: 'svg',\n            //     config: {\n            //         mobile: { width: 104, height: 74 },\n            //         desktop: { width: 104, height: 74 },\n            //     },\n            // },\n            // {\n            //     id: 'svgAutoplayStartDisabled',\n            //     url: '../assets/uiSvg/autoplayStartDisabled.svg',\n            //     priority: AssetPriority.HIGHEST,\n            //     type: 'svg',\n            //     config: {\n            //         mobile: { width: 222, height: 78 },\n            //         desktop: { width: 222, height: 78 },\n            //     },\n            // },\n            // {\n            //     id: 'svgAutoplayStartHover',\n            //     url: '../assets/uiSvg/autoplayStartHover.svg',\n            //     priority: AssetPriority.HIGHEST,\n            //     type: 'svg',\n            //     config: {\n            //         mobile: { width: 222, height: 78 },\n            //         desktop: { width: 222, height: 78 },\n            //     },\n            // },\n            // {\n            //     id: 'svgAutoplayStartNormal',\n            //     url: '../assets/uiSvg/autoplayStartNormal.svg',\n            //     priority: AssetPriority.HIGHEST,\n            //     type: 'svg',\n            //     config: {\n            //         mobile: { width: 222, height: 78 },\n            //         desktop: { width: 222, height: 78 },\n            //     },\n            // },\n            {\n                id: 'infinityIcon',\n                url: '../assets/uiSvg/oldInfinityIcon.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 51, height: 24 },\n                    desktop: { width: 51, height: 24 },\n                },\n            },\n            {\n                id: 'infinityIconSelected',\n                url: '../assets/uiSvg/oldInfinityIconSelected.svg',\n                priority: AssetPriority.HIGHEST,\n                type: 'svg',\n                config: {\n                    mobile: { width: 51, height: 24 },\n                    desktop: { width: 51, height: 24 },\n                },\n            },\n        ])\n        public assets: AssetsCollection;\n\n        @ModifyValue<IAutoplayPopUpTitleTextExtended>({\n            defaults: {\n                textStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold, Arial',\n                    fontSize: 36,\n                    fill: '#FFFFFF',\n                    align: 'center',\n                }),\n            },\n        })\n        public popUpTitle: DynamicPositionObject<IAutoplayPopUpTitleTextExtended> & IAutoplayPopUpTitleTextExtended;\n\n        @ModifyValue<IAutoplayPopUpTextExtended>({\n            defaults: {\n                textStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold, Arial',\n                    fontSize: 28,\n                    fill: '#FFFFFF',\n                    align: 'center',\n                }),\n            },\n        })\n        public stopOnTitle: DynamicPositionObject<IAutoplayPopUpTextExtended> & IAutoplayPopUpTextExtended;\n\n        @ModifyValue<IAutoplayPopUpTextExtended>({\n            defaults: {\n                textStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold, Arial',\n                    fontSize: 28,\n                    fill: '#FFFFFF',\n                    align: 'center',\n                }),\n            },\n        })\n        public autoplayTitle: DynamicPositionObject<IAutoplayPopUpTextExtended> & IAutoplayPopUpTextExtended;\n\n        @ModifyValue<IAutoplayPopUpTextExtended>({\n            defaults: {\n                y: -26,\n                textStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Regular, Arial',\n                    fontSize: 30,\n                    fill: '#FFFFFF',\n                    align: 'left',\n                }),\n            },\n        })\n        public slidersTitleText: DynamicPositionObject<IAutoplayPopUpTextExtended> & IAutoplayPopUpTextExtended;\n\n        @ModifyValue<IAutoplayPopUpTextExtended>({\n            defaults: {\n                textStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold, Arial',\n                    fontSize: 26,\n                    fill: '#FF0000',\n                    align: 'right',\n                }),\n            },\n        })\n        public slidersValueMandatoryText: DynamicPositionObject<IAutoplayPopUpTextExtended> &\n            IAutoplayPopUpTextExtended;\n\n        @ModifyValue<IAutoplayPopUpTextExtended>({\n            defaults: {\n                y: -26,\n                textStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold, Arial',\n                    fontSize: 34,\n                    fill: '#FFD200',\n                    align: 'right',\n                }),\n            },\n        })\n        public slidersValueText: DynamicPositionObject<IAutoplayPopUpTextExtended> & IAutoplayPopUpTextExtended;\n\n        @ModifyValue<IAutoplayPopUpTextExtended>({\n            defaults: {\n                y: -30,\n                textStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold, Arial',\n                    fontSize: 17,\n                    fill: '#FFD200',\n                    align: 'right',\n                }),\n            },\n        })\n        public slidersCurrencyText: DynamicPositionObject<IAutoplayPopUpTextExtended> & IAutoplayPopUpTextExtended;\n\n        @ModifyValue<IAutoplayPopUpTextExtended>({\n            defaults: {\n                y: -27,\n                textStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Regular, Arial',\n                    fontSize: 26,\n                    fill: '#909090',\n                    align: 'right',\n                }),\n            },\n        })\n        public slidersValueNoLimit: DynamicPositionObject<IAutoplayPopUpTextExtended> & IAutoplayPopUpTextExtended;\n\n        @ModifyValue<IAutoplayPopUpTextExtended>({\n            defaults: {\n                textStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold, Arial',\n                    fontSize: 36,\n                    fill: '#FFFFFF',\n                    align: 'center',\n                }),\n            },\n        })\n        public startAutoplayNormalText: DynamicPositionObject<IAutoplayPopUpTextExtended> & IAutoplayPopUpTextExtended;\n\n        @ModifyValue<IAutoplayPopUpTextExtended>({\n            defaults: {\n                textStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold, Arial',\n                    fontSize: 36,\n                    fill: '#818c86',\n                    align: 'center',\n                }),\n            },\n        })\n        public startAutoplayDisabledText: DynamicPositionObject<IAutoplayPopUpTextExtended> &\n            IAutoplayPopUpTextExtended;\n\n        @ModifyValue<IAutoplayBtnTextExtended>({\n            defaults: {\n                textStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold, Arial',\n                    fontSize: 42,\n                    fill: '#C6C5C5',\n                    align: 'center',\n                }),\n                selectedTextStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold, Arial',\n                    fontSize: 42,\n                    fill: '#FFFFFF',\n                    align: 'center',\n                }),\n            },\n        })\n        public buttonValueText: DynamicPositionObject<IAutoplayBtnTextExtended> & IAutoplayBtnTextExtended;\n\n        @ModifyValue<IBalanceAndBetTextExtended>({\n            defaults: {\n                textStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFD200',\n                    fontSize: 24,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                valueStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 36,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                currencyStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 22,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n            },\n        })\n        public balanceText: DynamicPositionObject<IBalanceAndBetTextExtended> & IBalanceAndBetTextExtended;\n\n        @ModifyValue<IBalanceAndBetTextExtended>({\n            defaults: {\n                textStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFD200',\n                    fontSize: 24,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                valueStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 36,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                currencyStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold, Arial',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 22,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n            },\n        })\n        public betText: DynamicPositionObject<IBalanceAndBetTextExtended> & IBalanceAndBetTextExtended;\n    }\n\n    return SingleProgressiveAutoplayPopupComponentConfigurationExtended;\n}\n","import { AddPriority, DynamicPositionObject, ModifyValue } from '@egt/core';\nimport {\n    AutoplayPopupComponentConfigurationNumeric,\n    IAutoPlaySelectedBtnPositionsNumeric,\n    IMainContainerPositionNumeric,\n    IAutoPlayArrowPositionsNumeric,\n} from '@egt/autoplay-popup';\nimport { SlotComponents } from '@egt/slot';\nimport { FooterBackgroundModes } from '@egt/footer-background';\nimport { IKeyboardContainerPositionNumeric, IKeyboardShadowBackgroundConfigNumeric } from '@egt/ui-lib';\n\nexport default function SingleProgressiveAutoplayPopupComponentConfigurationFactoryNumeric(\n    ClassType: typeof AutoplayPopupComponentConfigurationNumeric,\n): typeof AutoplayPopupComponentConfigurationNumeric {\n    class SingleProgressiveAutoplayPopupComponentConfigurationNumeric\n        extends ClassType\n        implements SingleProgressiveAutoplayPopupComponentConfigurationNumeric\n    {\n        @ModifyValue<IMainContainerPositionNumeric>({\n            defaults: {\n                x: 0,\n                y: 0,\n                leftHandX: -276,\n            },\n        })\n        public mainContainerPosition: DynamicPositionObject<IMainContainerPositionNumeric> &\n            IMainContainerPositionNumeric;\n\n        @ModifyValue<IAutoPlayArrowPositionsNumeric>({\n            defaults: {\n                x: 1186,\n                y: 127,\n                angle: 270,\n                leftHandX: 174,\n                leftHandY: 76,\n                leftHandAngle: 90,\n            },\n            portrait: {\n                x: 162,\n                y: 935,\n                angle: 0,\n            },\n            desktop: {\n                y: 228,\n            },\n        })\n        public arrowPosition: DynamicPositionObject<IAutoPlayArrowPositionsNumeric> & IAutoPlayArrowPositionsNumeric;\n\n        @AddPriority<IAutoPlaySelectedBtnPositionsNumeric>([\n            {\n                priorityType: { feature: SlotComponents.FOOTER_BACKGROUND, mode: FooterBackgroundModes.BLURRED },\n                priority: 1,\n                value: {\n                    portrait: { y: 1164 },\n                },\n            },\n        ])\n        @ModifyValue<IAutoPlaySelectedBtnPositionsNumeric>({\n            defaults: {\n                x: 1285,\n                y: 101,\n                leftHandX: 75,\n                scale: 1,\n            },\n            portrait: {\n                x: 187,\n                y: 1061,\n            },\n            desktop: {\n                x: 1272.5,\n                y: 198.5,\n            },\n        })\n        selectedButton: DynamicPositionObject<IAutoPlaySelectedBtnPositionsNumeric> &\n            IAutoPlaySelectedBtnPositionsNumeric;\n\n        @ModifyValue<IKeyboardContainerPositionNumeric>({\n            defaults: {\n                x: 445,\n                y: 404,\n                leftHandX: 169,\n            },\n            portrait: {\n                x: 0,\n                y: 876,\n            },\n        })\n        public numericKeyboardContainerPosition: DynamicPositionObject<IKeyboardContainerPositionNumeric> &\n            IKeyboardContainerPositionNumeric;\n\n        @ModifyValue<IKeyboardShadowBackgroundConfigNumeric>({\n            defaults: {\n                x: 0,\n                y: 761,\n            },\n            portrait: {\n                x: 0,\n                y: -245,\n            },\n        })\n        public numericKeyboardShadowBackground: DynamicPositionObject<IKeyboardShadowBackgroundConfigNumeric> &\n            IKeyboardShadowBackgroundConfigNumeric;\n    }\n    return SingleProgressiveAutoplayPopupComponentConfigurationNumeric;\n}\n","import { BetButtonsComponentConfigurationDefault, IBetButton, IJackpotLabel } from '@egt/bet-buttons';\nimport { DefaultValue, DynamicPositionObject } from '@egt/core';\nimport { AutoAlign, IBetButtonsConfig, TextAlign } from '@egt/ui-lib';\nimport { TextStyle } from 'pixi.js';\n\nexport default function SingleProgressiveBetButtonsComponentConfigurationFactoryDefault(\n    ClassType: typeof BetButtonsComponentConfigurationDefault,\n): typeof BetButtonsComponentConfigurationDefault {\n    class SingleProgressiveBetButtonsComponentConfiguration extends ClassType {\n        @DefaultValue<IJackpotLabel>({\n            defaults: {\n                x: 8,\n                y: 65,\n                width: 105,\n                height: 28,\n                alpha: 0,\n                texture: 'jackpotBet.png',\n                spriteSheet: 'uiSGJackpot',\n            },\n            desktop: { x: 8, y: 50, width: 81, height: 20 },\n        })\n        public jackpotStampConfig: DynamicPositionObject<IJackpotLabel> & IJackpotLabel;\n\n        @DefaultValue<IBetButtonsConfig>({\n            defaults: {\n                currency: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 17,\n                        fontWeight: 'bold',\n                        fill: '#C6C5C5',\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 17,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 3,\n                    bounds: { width: 106, height: 30 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                amount: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 36,\n                        fill: '#C6C5C5', // '#FFFFFF'\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 36,\n                        fill: '#FFFFFF',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 31,\n                    bounds: { width: 106, height: 34 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                label: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 21,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                        padding: 5,\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 21,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                        padding: 5,\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 63,\n                    bounds: { width: 106, height: 30 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                stamp: {\n                    hasStamp: false,\n                    x: 0,\n                    y: 0,\n                    width: 0,\n                    height: 0,\n                    alpha: 0,\n                    texture: { source: '', name: '' },\n                },\n                textures: ['svgSpjBet', 'svgSpjBetOn', 'svgSpjBet', 'svgSpjBet'],\n                selectedTextures: ['svgSpjActiveBet', 'svgSpjActiveBetOn', 'svgSpjActiveBet', 'svgSpjActiveBet'],\n                fakeMaskTexture: 'maxBet',\n                width: 120,\n                height: 96,\n            },\n            desktop: {\n                currency: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 15,\n                        fontWeight: 'bold',\n                        fill: '#C6C5C5', // '#FFD200'\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 15,\n                        fill: '#FFD200',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 4,\n                    bounds: { width: 84, height: 20 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                amount: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 27,\n                        fill: '#C6C5C5', // '#FFFFFF'\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 27,\n                        fill: '#FFFFFF',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 27,\n                    bounds: { width: 84, height: 20 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                label: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 16,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                        padding: 5,\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 16,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                        padding: 5,\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 52,\n                    bounds: { width: 78, height: 17 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                textures: ['svgSpjBet', 'svgSpjBetOn', 'svgSpjBet', 'svgSpjBet'],\n                selectedTextures: ['svgSpjActiveBet', 'svgSpjActiveBetOn', 'svgSpjActiveBet', 'svgSpjActiveBet'],\n                width: 94,\n                height: 75,\n            },\n        })\n        public betButtonsConfigsSpj: DynamicPositionObject<IBetButtonsConfig> & IBetButtonsConfig;\n\n        @DefaultValue<IBetButtonsConfig>({\n            defaults: {\n                currency: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 17,\n                        fontWeight: 'bold',\n                        fill: '#C6C5C5',\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 17,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 3,\n                    bounds: { width: 106, height: 30 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                amount: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 36,\n                        fill: '#C6C5C5', // '#FFFFFF'\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 36,\n                        fill: '#FFFFFF',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 31,\n                    bounds: { width: 106, height: 34 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                label: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 21,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                        padding: 5,\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 21,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                        padding: 5,\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 63,\n                    bounds: { width: 106, height: 30 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                stamp: {\n                    hasStamp: false,\n                    x: 0,\n                    y: 0,\n                    width: 0,\n                    height: 0,\n                    alpha: 0,\n                    texture: { source: '', name: '' },\n                },\n                textures: ['svgBet', 'svgBetPressed', 'svgBet', 'svgBet'],\n                selectedTextures: ['svgActiveBet', 'svgActiveBetPressed', 'svgActiveBet', 'svgActiveBet'],\n                fakeMaskTexture: 'maxBet',\n                width: 120,\n                height: 96,\n            },\n            desktop: {\n                currency: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 15,\n                        fontWeight: 'bold',\n                        fill: '#C6C5C5', // '#FFD200'\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 15,\n                        fill: '#FFD200',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 4,\n                    bounds: { width: 84, height: 20 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                amount: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 27,\n                        fill: '#C6C5C5', // '#FFFFFF'\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 27,\n                        fill: '#FFFFFF',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 27,\n                    bounds: { width: 84, height: 20 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                label: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 16,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                        padding: 5,\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 16,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                        padding: 5,\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 52,\n                    bounds: { width: 78, height: 17 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                textures: ['svgBet', 'svgBetPressed', 'svgBetHover', 'svgBet'],\n                selectedTextures: ['svgActiveBet', 'svgActiveBetPressed', 'svgActiveBetHover', 'svgActiveBet'],\n                width: 94,\n                height: 75,\n            },\n        })\n        public betButtonsConfigs: DynamicPositionObject<IBetButtonsConfig> & IBetButtonsConfig;\n\n        public betButtons: Array<DynamicPositionObject<IBetButton>> = [\n            new DynamicPositionObject<IBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs, x: 0, y: 0 },\n                landscape: { x: 227, y: 4 },\n                portrait: { x: 62, y: 149 },\n                desktop: { x: 282, y: 6 },\n            }),\n            new DynamicPositionObject<IBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs, x: 0, y: 0 },\n                landscape: { x: 348, y: 4 },\n                portrait: { x: 193, y: 149 },\n                desktop: { x: 382, y: 6 },\n            }),\n            new DynamicPositionObject<IBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs, x: 0, y: 0 },\n                landscape: { x: 469, y: 4 },\n                portrait: { x: 324, y: 149 },\n                desktop: { x: 482, y: 6 },\n            }),\n            new DynamicPositionObject<IBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs, x: 0, y: 0 },\n                landscape: { x: 590, y: 4 },\n                portrait: { x: 455, y: 149 },\n                desktop: { x: 582, y: 6 },\n            }),\n            new DynamicPositionObject<IBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigsSpj, x: 0, y: 0 },\n                landscape: { x: 711, y: 4 },\n                portrait: { x: 586, y: 149 },\n                desktop: { x: 682, y: 6 },\n            }),\n        ];\n    }\n    return SingleProgressiveBetButtonsComponentConfiguration;\n}\n","import { BetButtonsComponentConfigurationDefault, IBetButton, IJackpotLabel } from '@egt/bet-buttons';\nimport { DefaultValue, DynamicPositionObject } from '@egt/core';\nimport { AutoAlign, IBetButtonsConfig, TextAlign } from '@egt/ui-lib';\nimport { TextStyle } from 'pixi.js';\n\nexport default function SingleProgressiveBetButtonsComponentConfigurationFactoryOneDenom(\n    ClassType: typeof BetButtonsComponentConfigurationDefault,\n): typeof BetButtonsComponentConfigurationDefault {\n    class SingleProgressiveBetButtonsComponentConfiguration extends ClassType {\n        @DefaultValue<IJackpotLabel>({\n            defaults: {\n                x: 8,\n                y: 65,\n                width: 105,\n                height: 28,\n                alpha: 0,\n                texture: 'jackpotBet.png',\n                spriteSheet: 'uiSGJackpot',\n            },\n            desktop: { x: 8, y: 50, width: 81, height: 20 },\n        })\n        public jackpotStampConfig: DynamicPositionObject<IJackpotLabel> & IJackpotLabel;\n\n        @DefaultValue<IBetButtonsConfig>({\n            defaults: {\n                currency: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 17,\n                        fontWeight: 'bold',\n                        fill: '#C6C5C5',\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 17,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 3,\n                    bounds: { width: 106, height: 30 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                amount: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 36,\n                        fill: '#C6C5C5', // '#FFFFFF'\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 36,\n                        fill: '#FFFFFF',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 31,\n                    bounds: { width: 106, height: 34 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                label: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 21,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                        padding: 5,\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 21,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                        padding: 5,\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 63,\n                    bounds: { width: 106, height: 30 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                stamp: {\n                    hasStamp: false,\n                    x: 0,\n                    y: 0,\n                    width: 0,\n                    height: 0,\n                    alpha: 0,\n                    texture: { source: '', name: '' },\n                },\n                textures: ['svgSpjBet', 'svgSpjBetOn', 'svgSpjBet', 'svgSpjBet'],\n                selectedTextures: ['svgSpjActiveBet', 'svgSpjActiveBetOn', 'svgSpjActiveBet', 'svgSpjActiveBet'],\n                fakeMaskTexture: 'maxBet',\n                width: 120,\n                height: 96,\n            },\n            desktop: {\n                currency: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 15,\n                        fontWeight: 'bold',\n                        fill: '#C6C5C5', // '#FFD200'\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 15,\n                        fill: '#FFD200',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 4,\n                    bounds: { width: 84, height: 20 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                amount: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 27,\n                        fill: '#C6C5C5', // '#FFFFFF'\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 27,\n                        fill: '#FFFFFF',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 27,\n                    bounds: { width: 84, height: 20 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                label: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 16,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                        padding: 5,\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 16,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                        padding: 5,\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 52,\n                    bounds: { width: 78, height: 17 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                textures: ['svgSpjBet', 'svgSpjBetOn', 'svgSpjBet', 'svgSpjBet'],\n                selectedTextures: ['svgSpjActiveBet', 'svgSpjActiveBetOn', 'svgSpjActiveBet', 'svgSpjActiveBet'],\n                width: 94,\n                height: 75,\n            },\n        })\n        public betButtonsConfigsSpj: DynamicPositionObject<IBetButtonsConfig> & IBetButtonsConfig;\n\n        @DefaultValue<IBetButtonsConfig>({\n            defaults: {\n                currency: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 17,\n                        fontWeight: 'bold',\n                        fill: '#C6C5C5',\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 17,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 3,\n                    bounds: { width: 106, height: 30 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                amount: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 36,\n                        fill: '#C6C5C5', // '#FFFFFF'\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 36,\n                        fill: '#FFFFFF',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 31,\n                    bounds: { width: 106, height: 34 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                label: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 21,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                        padding: 5,\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 21,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                        padding: 5,\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 63,\n                    bounds: { width: 106, height: 30 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                stamp: {\n                    hasStamp: false,\n                    x: 0,\n                    y: 0,\n                    width: 0,\n                    height: 0,\n                    alpha: 0,\n                    texture: { source: '', name: '' },\n                },\n                textures: ['svgBet', 'svgBetPressed', 'svgBet', 'svgBet'],\n                selectedTextures: ['svgActiveBet', 'svgActiveBetPressed', 'svgActiveBet', 'svgActiveBet'],\n                fakeMaskTexture: 'maxBet',\n                width: 120,\n                height: 96,\n            },\n            desktop: {\n                currency: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 15,\n                        fontWeight: 'bold',\n                        fill: '#C6C5C5', // '#FFD200'\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 15,\n                        fill: '#FFD200',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 4,\n                    bounds: { width: 84, height: 20 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                amount: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 27,\n                        fill: '#C6C5C5', // '#FFFFFF'\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 27,\n                        fill: '#FFFFFF',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 27,\n                    bounds: { width: 84, height: 20 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                label: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 16,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                        padding: 5,\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 16,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                        padding: 5,\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 52,\n                    bounds: { width: 78, height: 17 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                textures: ['svgBet', 'svgBetPressed', 'svgBetHover', 'svgBet'],\n                selectedTextures: ['svgActiveBet', 'svgActiveBetPressed', 'svgActiveBetHover', 'svgActiveBet'],\n                width: 94,\n                height: 75,\n            },\n        })\n        public betButtonsConfigs: DynamicPositionObject<IBetButtonsConfig> & IBetButtonsConfig;\n\n        public betButtons: Array<DynamicPositionObject<IBetButton>> = [\n            new DynamicPositionObject<IBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs, x: 0, y: 0 },\n                landscape: { x: 227, y: 4 },\n                portrait: { x: 62, y: 149 },\n                desktop: { x: 282, y: 6 },\n            }),\n            new DynamicPositionObject<IBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs, x: 0, y: 0 },\n                landscape: { x: 348, y: 4 },\n                portrait: { x: 193, y: 149 },\n                desktop: { x: 382, y: 6 },\n            }),\n            new DynamicPositionObject<IBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs, x: 0, y: 0 },\n                landscape: { x: 469, y: 4 },\n                portrait: { x: 324, y: 149 },\n                desktop: { x: 482, y: 6 },\n            }),\n            new DynamicPositionObject<IBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs, x: 0, y: 0 },\n                landscape: { x: 590, y: 4 },\n                portrait: { x: 455, y: 149 },\n                desktop: { x: 582, y: 6 },\n            }),\n            new DynamicPositionObject<IBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigsSpj, x: 0, y: 0 },\n                landscape: { x: 711, y: 4 },\n                portrait: { x: 586, y: 149 },\n                desktop: { x: 682, y: 6 },\n            }),\n        ];\n    }\n    return SingleProgressiveBetButtonsComponentConfiguration;\n}\n","import {\n    BetCalculatorComponentConfigurationDefault,\n    IDenominationPopUpBtnsText,\n    IJackpotLabel,\n} from '@egt/bet-calculator';\nimport Core, {\n    AssetPriority,\n    AssetsCollection,\n    DefaultValue,\n    DynamicPositionObject,\n    ModifyAssets,\n    ModifyValue,\n} from '@egt/core';\nimport { TextStyle } from 'pixi.js';\n\nexport default function SingleProgressiveBetCalculatorComponentConfigurationFactoryDefault(\n    ClassType: typeof BetCalculatorComponentConfigurationDefault,\n): typeof BetCalculatorComponentConfigurationDefault {\n    class SingleProgressiveBetCalculatorComponentConfiguration extends ClassType {\n        @ModifyAssets([\n            {\n                id: 'calculatorResources',\n                url: '../assets/' + Core.configuration.gameKey + '/betCalculator/calculatorResources.json',\n                priority: AssetPriority.HIGHEST,\n                type: 'texture',\n            },\n        ])\n        public assets: AssetsCollection;\n\n        @ModifyValue<IDenominationPopUpBtnsText>({\n            defaults: {\n                normalTextStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold',\n                    fontSize: 42,\n                    lineHeight: 42,\n                    fill: '#C6C5C5',\n                    align: 'center',\n                }),\n                hilightedTextStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold',\n                    fontSize: 42,\n                    lineHeight: 42,\n                    fill: '#FFFFFF',\n                    align: 'center',\n                }),\n                currencyNormalTextStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold',\n                    fontSize: 20,\n                    lineHeight: 20,\n                    fill: '#FFD200',\n                    align: 'center',\n                    letterSpacing: 0.4,\n                }),\n                currencyHilightedTextStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold',\n                    fontSize: 20,\n                    lineHeight: 20,\n                    fill: '#FFD200',\n                    align: 'center',\n                    letterSpacing: 0.4,\n                }),\n            },\n        })\n        public popUpButtonsText: DynamicPositionObject<IDenominationPopUpBtnsText> & IDenominationPopUpBtnsText;\n\n        @DefaultValue<IJackpotLabel>({\n            defaults: {\n                offset: 5,\n            },\n        })\n        public jackpotStampConfig: DynamicPositionObject<IJackpotLabel> & IJackpotLabel;\n    }\n    return SingleProgressiveBetCalculatorComponentConfiguration;\n}\n","import { ClockComponentConfigurationDefault, IClockTextStyle } from '@egt/clock';\nimport { DynamicPositionObject, OverrideDefaultProperties } from '@egt/core';\nimport { TextStyle } from 'pixi.js';\n\nexport default function SingleProgressiveClockComponentConfigurationFactoryDefault(\n    ClassType: typeof ClockComponentConfigurationDefault,\n): typeof ClockComponentConfigurationDefault {\n    class SingleProgressiveClockComponentConfiguration extends ClassType {\n        @OverrideDefaultProperties<IClockTextStyle>({\n            clockTextStyle: new TextStyle({\n                fontFamily: 'Arial, sans-serif',\n                fontWeight: 'bold',\n                fontSize: 15,\n                fill: '#888888',\n            }),\n        })\n        public clockTextStyles: DynamicPositionObject<IClockTextStyle> & IClockTextStyle;\n    }\n    return SingleProgressiveClockComponentConfiguration;\n}\n","import { DynamicPositionObject, ModifyValue } from '@egt/core';\nimport {\n    DenominationPopupComponentConfigurationExtended,\n    IBalanceAndBetTextExtended,\n    IDenominationPopUpTitleTextExtended,\n} from '@egt/denomination-popup';\nimport { TextStyle } from 'pixi.js';\n\nexport default function SingleProgressiveDenominationPopupComponentConfigurationFactoryExtended(\n    ClassType: typeof DenominationPopupComponentConfigurationExtended,\n): typeof DenominationPopupComponentConfigurationExtended {\n    class SingleProgressiveDenominationPopupComponentConfigurationExtended\n        extends ClassType\n        implements SingleProgressiveDenominationPopupComponentConfigurationExtended\n    {\n        @ModifyValue<IDenominationPopUpTitleTextExtended>({\n            defaults: {\n                yOffset: 30,\n                textStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold',\n                    fontSize: 36,\n                    lineHeight: 42,\n                    fill: '#FFFFFF',\n                    align: 'center',\n                }),\n            },\n        })\n        public popUpTitle: DynamicPositionObject<IDenominationPopUpTitleTextExtended> &\n            IDenominationPopUpTitleTextExtended;\n\n        @ModifyValue<IBalanceAndBetTextExtended>({\n            defaults: {\n                textStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold',\n                    align: 'left',\n                    fill: '#FFD200',\n                    fontSize: 24,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                valueStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 36,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                currencyStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 22,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n            },\n        })\n        public balanceText: DynamicPositionObject<IBalanceAndBetTextExtended> & IBalanceAndBetTextExtended;\n\n        @ModifyValue<IBalanceAndBetTextExtended>({\n            defaults: {\n                textStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold',\n                    align: 'left',\n                    fill: '#FFD200',\n                    fontSize: 24,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                valueStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 36,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n                currencyStyle: new TextStyle({\n                    fontFamily: 'RobotoCondensed-Bold',\n                    align: 'left',\n                    fill: '#FFFFFF',\n                    fontSize: 22,\n                    lineJoin: 'round',\n                    miterLimit: 0,\n                    textBaseline: 'middle',\n                    padding: 4,\n                }),\n            },\n        })\n        public betText: DynamicPositionObject<IBalanceAndBetTextExtended> & IBalanceAndBetTextExtended;\n    }\n\n    return SingleProgressiveDenominationPopupComponentConfigurationExtended;\n}\n","import { DynamicPositionObject, ModifyValue } from '@egt/core';\nimport { ITextStyles, MessageBarComponentConfiguration } from '@egt/message-bar';\nimport { TextStyle } from 'pixi.js';\nexport default function SingleProgressiveMessageBarComponentConfigurationFactory(\n    ClassType: typeof MessageBarComponentConfiguration,\n): typeof MessageBarComponentConfiguration {\n    class SingleProgressiveMessageBarComponentConfiguration extends ClassType {\n        @ModifyValue<ITextStyles>({\n            defaults: {\n                messageTextStyle: new TextStyle({\n                    fontFamily: 'Arial, sans-serif',\n                    fontSize: 24,\n                    lineHeight: 26,\n                    fontWeight: 'bold',\n                    fill: '#FFFFFF',\n                }),\n                lineTextStyle: new TextStyle({\n                    fontFamily: 'Arial, sans-serif',\n                    fontSize: 21,\n                    lineHeight: 25,\n                    fontWeight: 'bold',\n                    fill: '#FFFFFF',\n                    wordWrap: true,\n                    wordWrapWidth: 260,\n                    align: 'center',\n                }),\n                currencyTextStyle: new TextStyle({\n                    fontFamily: 'Arial, sans-serif',\n                    fontSize: 14,\n                    fontWeight: 'bold',\n                    fill: '#FFFFFF',\n                }),\n            },\n            landscape: {\n                lineTextStyle: new TextStyle({\n                    fontFamily: 'Arial, sans-serif',\n                    fontSize: 21,\n                    lineHeight: 25,\n                    fontWeight: 'bold',\n                    fill: '#FFFFFF',\n                    wordWrap: false,\n                    align: 'center',\n                }),\n            },\n            portrait: {\n                messageTextStyle: new TextStyle({\n                    fontFamily: 'Arial, sans-serif',\n                    fontSize: 28,\n                    lineHeight: 30,\n                    fontWeight: 'bold',\n                    fill: '#FFFFFF',\n                    wordWrap: true,\n                    wordWrapWidth: 260,\n                    align: 'center',\n                }),\n            },\n        })\n        public textStyles: DynamicPositionObject<ITextStyles> & ITextStyles;\n\n        public portraitMessageOnOneLine: boolean = false;\n    }\n    return SingleProgressiveMessageBarComponentConfiguration;\n}\n","import { DefaultValue, DynamicPositionObject, ModifyValue } from '@egt/core';\nimport {\n    IAutoplayViewInterface,\n    IBetViewInterface,\n    IGeneralSettingsInterface,\n    IMenuBetButton,\n    IOneDenomBetViewInterface,\n    ISettingsTabNameInterface,\n    SettingsPopupComponentConfiguration,\n} from '@egt/settings-popup';\nimport { AutoAlign, IBetButtonsConfig, TextAlign } from '@egt/ui-lib';\nimport { IPointData, TextStyle } from 'pixi.js';\nimport {\n    IAutoplayNumericInputsViewProps,\n    ISettingsMenuCover,\n} from 'slot-components/settings-popup/src/egt/interfaces/SettingsInterfaces';\n\nexport default function SingleProgressiveSettingsPopupComponentConfigurationFactory(\n    ClassType: typeof SettingsPopupComponentConfiguration,\n): typeof SettingsPopupComponentConfiguration {\n    class SingleProgressiveSettingsPopupComponentConfiguration extends ClassType {\n        @ModifyValue<ISettingsTabNameInterface>({\n            defaults: {\n                textStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'Arial',\n                    fontWeight: 'bold',\n                    fontSize: 32,\n                    padding: 5,\n                }),\n                minFontSize: 12,\n                useTextConfig: true,\n            },\n            desktop: {\n                textStyle: new TextStyle({\n                    fill: '#CFCFCF',\n                    fontFamily: 'Arial',\n                    fontSize: 21,\n                    fontWeight: 'bold',\n                    padding: 5,\n                }),\n            },\n        })\n        public tabNameProps: DynamicPositionObject<ISettingsTabNameInterface> & ISettingsTabNameInterface;\n\n        @ModifyValue<IAutoplayViewInterface>({\n            defaults: {\n                sliderContainerWidth: 600,\n                sliderContainerHeight: 60,\n                sliderWidth: 540,\n                sliderHeight: 6,\n                sliderTopOffset: 20,\n                textTopOffset: 80,\n                slidersValuesColor: 0x7cc810,\n                slidersNotSelectedColor: 0x585858,\n                slidersSelectedColor: 0x6ba717,\n                useTexturesForDots: false,\n                useCanvasForSliders: false,\n                canvasSlidersNumberOfStops: 0,\n                canvasNotSelectedSliderStops: [],\n                canvasSelectedSliderStops: [],\n                canvasNotSelectedSlidersColors: [],\n                canvasSelectedSlidersColors: [],\n                inactiveDotTexture: '',\n                activeDotTexture: '',\n                inactiveHandleTexture: ['svgRedAuto', 'svgGreyAuto'],\n                activeHandleTexture: 'svgGreenAuto',\n                valuesWidthDevider: 5.5,\n                headersWidthDevider: 2,\n                ///// TEXT STYLES /////\n                zeroValueStyle: new TextStyle({\n                    fill: '#595959',\n                    fontFamily: 'Arial',\n                    fontSize: 20,\n                    padding: 5,\n                    fontWeight: 'bold',\n                }),\n                mandatorySignStyle: new TextStyle({\n                    fill: '#FF0000',\n                    fontFamily: 'Arial',\n                    fontSize: 48,\n                    fontWeight: 'bold',\n                }),\n                spinsStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'Arial',\n                    fontSize: 32,\n                    padding: 5,\n                    fontWeight: 'bold',\n                }),\n                spinsValueStyle: new TextStyle({\n                    fill: 0x7cc810,\n                    fontFamily: 'Arial',\n                    fontSize: 34,\n                    fontWeight: 'bold',\n                }),\n                decreaseStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'Arial',\n                    fontSize: 32,\n                    padding: 5,\n                }),\n                decreaseValueStyle: new TextStyle({\n                    fill: 0x7cc810,\n                    fontFamily: 'Arial',\n                    fontSize: 28,\n                    padding: 5,\n                }),\n                increaseStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'Arial',\n                    fontSize: 32,\n                    padding: 5,\n                }),\n                increaseValueStyle: new TextStyle({\n                    fill: 0x7cc810,\n                    fontFamily: 'Arial',\n                    fontSize: 28,\n                }),\n                singleWinStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'Arial',\n                    fontSize: 32,\n                    padding: 5,\n                }),\n                singleWinValueStyle: new TextStyle({\n                    fill: 0x7cc810,\n                    fontFamily: 'Arial',\n                    fontSize: 28,\n                }),\n                startButtonTextStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'Arial',\n                    fontSize: 40,\n                    padding: 5,\n                    fontWeight: 'bold',\n                }),\n                balanceTextStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'Arial',\n                    fontSize: 22,\n                    padding: 3,\n                    fontWeight: 'bold',\n                }),\n                betTextStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'Arial',\n                    fontSize: 22,\n                    padding: 3,\n                    fontWeight: 'bold',\n                }),\n                betValueStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'Arial',\n                    fontSize: 22,\n                    fontWeight: 'bold',\n                }),\n                balanceValueStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'Arial',\n                    fontSize: 22,\n                    fontWeight: 'bold',\n                }),\n                stopOnStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'Arial',\n                    fontSize: 32,\n                    padding: 5,\n                    fontWeight: 'bold',\n                }),\n\n                ///// TEXT CONFIGS /////\n                mandatorySignConfig: {\n                    boundsWidth: 40,\n                    shouldFitInBounds: true,\n                    align: TextAlign.CENTER,\n                },\n                spinsConfig: {\n                    boundsWidth: 0,\n                    boundsHeight: 32,\n                    minFontSize: 16,\n                    shouldFitInBounds: true,\n                },\n                spinsValueConfig: {\n                    boundsWidth: 0,\n                    boundsHeight: 34,\n                    minFontSize: 17,\n                    shouldFitInBounds: true,\n                    align: TextAlign.RIGHT,\n                },\n                decreaseConfig: {\n                    boundsWidth: 0,\n                    boundsHeight: 32,\n                    minFontSize: 16,\n                    shouldFitInBounds: true,\n                },\n                increaseConfig: {\n                    boundsWidth: 0,\n                    boundsHeight: 32,\n                    minFontSize: 16,\n                    shouldFitInBounds: true,\n                },\n                singleWinConfig: {\n                    boundsWidth: 0,\n                    boundsHeight: 32,\n                    minFontSize: 16,\n                    shouldFitInBounds: true,\n                },\n                noLimitConfig: {\n                    boundsWidth: 0,\n                    boundsHeight: 28,\n                    minFontSize: 14,\n                    moneyFontSize: 30,\n                    align: TextAlign.RIGHT,\n                },\n                startButtonTextConfig: {\n                    boundsWidth: 20,\n                    boundsHeight: 40,\n                    minFontSize: 30,\n                    shouldFitInBounds: true,\n                    align: TextAlign.CENTER,\n                },\n                limitsValuesConfig: {\n                    boundsWidth: 0,\n                    boundsHeight: 28,\n                    minFontSize: 14,\n                    shouldFitInBounds: true,\n                    align: TextAlign.RIGHT,\n                    shouldHideWhenMoneyValueIsZero: true,\n                    useMoneyMode: true,\n                    moneyFontSize: 28,\n                    centsFontSize: 28,\n                    currencyFontSize: 14,\n                },\n                balanceValueConfig: {\n                    boundsWidth: 0,\n                },\n                betValueConfig: {\n                    boundsWidth: 0,\n                },\n\n                stopOnTextX: 90,\n                stopOnTextY: 80,\n                balanceDecreaseTextX: 100,\n                balanceDecreaseTextY: 140,\n                balanceDecreaseValueX: 520,\n                balanceDecreaseValueY: 140,\n                sliderContainersX: 0,\n                // lossSliderContainerX: 0,\n                balanceIncreaseTextX: 100,\n                balanceIncreaseValueX: 520,\n                // winsSliderContainerX: 0,\n                singleWinLimitTextX: 100,\n                singleWinLimitValueX: 520,\n                // singleWinSliderContainerX: 0,\n                numberOfSpinsTextX: 90,\n                numberOfSpinsTextY: 130,\n                numberOfSpinsValueDevider: 5,\n                numberOfSpinsValueX: 500,\n                numberOfSpinsValueY: 130,\n                infinityValueTextureX: 160,\n                infinityValueTextureY: 4,\n                // spinsSliderContainerX: 0,\n                spinsSliderContainerY: 30,\n                startAutoplayButtonX: 0,\n                startAutoplayButtonY: 48,\n                startButtonTextX: 10,\n                // startButtonTextY: 8,\n                startButtonTextActiveAlpha: 1,\n                startButtonTextInactiveAlpha: 0.6,\n                balanceTextX: 0,\n                balanceTextY: 0,\n                balanceValueX: 0,\n                balanceValueY: 0,\n                balanceContainerX: 50,\n                balanceContainerY: 1060,\n                betTextX: 0,\n                betTextY: 0,\n                betValueX: 0,\n                betValueY: 0,\n                betContainerX: 715,\n                betContainerY: 0,\n                balanceDecreaseZeroValueX: 0,\n                balanceDecreaseZeroValueY: 0,\n                balanceIncreaseZeroValueX: 0,\n                balanceIncreaseZeroValueY: 0,\n                singleWinZeroValueX: 0,\n                singleWinZeroValueY: 0,\n                decreaseMandatorySignX: 0,\n                decreaseMandatorySignY: -5,\n                increaseMandatorySignX: 0,\n                increaseMandatorySignY: -5,\n                winMandatorySignX: 0,\n                winMandatorySignY: -5,\n                startAutoplayButtonTextures: [\n                    'svgStartButton',\n                    'svgStartButton',\n                    'svgStartButton',\n                    'svgStartButtonInactive',\n                ],\n                infinityValueTexture: 'svgInfinity',\n                valueButtonsTextStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'Arial',\n                    fontSize: 20,\n                    fontWeight: 'bold',\n                }),\n                // windowTitleTextStyleDesktop: new TextStyle({\n                //     fill: '#CFCFCF',\n                //     fontFamily: 'Arial',\n                //     fontSize: 21,\n                //     fontWeight: 'bold',\n                //     padding: 5,\n                // }),\n            },\n            landscape: {\n                valuesWidthDevider: 8.5,\n                headersWidthDevider: 3.5,\n                noLimitConfig: {\n                    boundsWidth: 0,\n                    boundsHeight: 28,\n                    minFontSize: 14,\n                    moneyFontSize: 28,\n                    align: TextAlign.RIGHT,\n                },\n                stopOnTextX: 65,\n                stopOnTextY: -20,\n                balanceDecreaseTextX: 65,\n                balanceDecreaseTextY: 30,\n                balanceDecreaseValueX: 480,\n                balanceDecreaseValueY: 30,\n                sliderContainersX: 55,\n                // lossSliderContainerX: 55,\n                balanceIncreaseTextX: 65,\n                balanceIncreaseValueX: 480,\n                // winsSliderContainerX: 55,\n                singleWinLimitTextX: 65,\n                singleWinLimitValueX: 480,\n                // singleWinSliderContainerX: 55,\n                numberOfSpinsTextX: 45,\n                numberOfSpinsTextY: 30,\n                numberOfSpinsValueDevider: 10,\n                numberOfSpinsValueX: 215,\n                numberOfSpinsValueY: 30,\n                infinityValueTextureX: 130,\n                // spinsSliderContainerX: 55,\n                startAutoplayButtonX: 865,\n                startAutoplayButtonY: 106,\n                balanceContainerX: 45,\n                balanceContainerY: 0,\n                betContainerX: 1280,\n            },\n            desktop: {\n                zeroValueStyle: new TextStyle({\n                    fill: '#767676',\n                    fontFamily: 'Arial',\n                    fontSize: 16,\n                }),\n                mandatorySignStyle: new TextStyle({\n                    fill: '#FF0000',\n                    fontFamily: 'Arial',\n                    fontSize: 20,\n                    fontWeight: 'bold',\n                }),\n                spinsStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'Arial',\n                    fontSize: 11,\n                    fontWeight: 'bold',\n                    padding: 5,\n                }),\n                decreaseStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'Arial',\n                    fontSize: 11,\n                    fontWeight: 'bold',\n                    padding: 5,\n                }),\n                decreaseValueStyle: new TextStyle({\n                    fill: '#595959',\n                    fontFamily: 'Arial',\n                    fontSize: 16,\n                }),\n                increaseStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'Arial',\n                    fontSize: 11,\n                    fontWeight: 'bold',\n                    padding: 5,\n                }),\n                increaseValueStyle: new TextStyle({\n                    fill: '#595959',\n                    fontFamily: 'Arial',\n                    fontSize: 16,\n                }),\n                singleWinStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'Arial',\n                    fontSize: 11,\n                    fontWeight: 'bold',\n                    padding: 5,\n                }),\n                singleWinValueStyle: new TextStyle({\n                    fill: '#595959',\n                    fontFamily: 'Arial',\n                    fontSize: 16,\n                }),\n                startButtonTextStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'Arial',\n                    fontSize: 24,\n                    fontWeight: 'bold',\n                    padding: 5,\n                }),\n            },\n        })\n        public autoplayViewProps: DynamicPositionObject<IAutoplayViewInterface> & IAutoplayViewInterface;\n\n        @DefaultValue<IBetButtonsConfig>({\n            defaults: {\n                currency: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 17,\n                        fontWeight: 'bold',\n                        fill: '#C6C5C5',\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 17,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 3,\n                    bounds: { width: 106, height: 30 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                amount: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 36,\n                        fill: '#C6C5C5', // '#FFFFFF'\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 36,\n                        fill: '#FFFFFF',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 31,\n                    bounds: { width: 106, height: 34 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                label: {\n                    visible: false,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 21,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                        padding: 5,\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 21,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                        padding: 5,\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 63,\n                    bounds: { width: 106, height: 30 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                stamp: {\n                    hasStamp: true,\n                    x: 8,\n                    y: 64,\n                    width: 105,\n                    height: 28,\n                    alpha: 1,\n                    texture: { source: 'uiSGJackpot', name: 'jackpotBet.png' },\n                },\n                textures: ['svgSpjBet', 'svgSpjBetOn', 'svgSpjBet', 'svgSpjBet'],\n                selectedTextures: ['svgSpjActiveBet', 'svgSpjActiveBetOn', 'svgSpjActiveBet', 'svgSpjActiveBet'],\n                width: 120,\n                height: 96,\n                fakeMaskTexture: 'maxBet',\n            },\n            desktop: {\n                currency: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 15,\n                        fontWeight: 'bold',\n                        fill: '#C6C5C5', // '#FFD200'\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 15,\n                        fill: '#FFD200',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 4,\n                    bounds: { width: 84, height: 20 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                amount: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 27,\n                        fill: '#C6C5C5', // '#FFFFFF'\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 27,\n                        fill: '#FFFFFF',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 27,\n                    bounds: { width: 84, height: 20 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                label: {\n                    visible: false,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 16,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                        padding: 5,\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 16,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                        padding: 5,\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 52,\n                    bounds: { width: 78, height: 17 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                stamp: {\n                    hasStamp: true,\n                    x: 8,\n                    y: 51,\n                    width: 80,\n                    height: 21,\n                    alpha: 1,\n                    texture: { source: 'uiSGJackpot', name: 'jackpotBet.png' },\n                },\n                textures: ['svgSpjBet', 'svgSpjBetOn', 'svgSpjBet', 'svgSpjBet'],\n                selectedTextures: ['svgSpjActiveBet', 'svgSpjActiveBetOn', 'svgSpjActiveBet', 'svgSpjActiveBet'],\n                width: 94,\n                height: 75,\n            },\n        })\n        public betButtonsConfigsSpj: DynamicPositionObject<IBetButtonsConfig> & IBetButtonsConfig;\n\n        @ModifyValue<IBetButtonsConfig>({\n            defaults: {\n                currency: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 17,\n                        fontWeight: 'bold',\n                        fill: '#C6C5C5',\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 17,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 3,\n                    bounds: { width: 106, height: 30 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                amount: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 36,\n                        fill: '#C6C5C5', // '#FFFFFF'\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 36,\n                        fill: '#FFFFFF',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 31,\n                    bounds: { width: 106, height: 34 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                label: {\n                    visible: false,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 21,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                        padding: 5,\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 21,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                        padding: 5,\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 63,\n                    bounds: { width: 106, height: 30 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                stamp: {\n                    hasStamp: false,\n                    x: 0,\n                    y: 0,\n                    width: 0,\n                    height: 0,\n                    alpha: 0,\n                    texture: { source: '', name: '' },\n                },\n                textures: ['svgBet', 'svgBetPressed', 'svgBet', 'svgBet'],\n                selectedTextures: ['svgActiveBet', 'svgActiveBetPressed', 'svgActiveBet', 'svgActiveBet'],\n                width: 120,\n                height: 96,\n            },\n            desktop: {\n                currency: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 15,\n                        fontWeight: 'bold',\n                        fill: '#C6C5C5', // '#FFD200'\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 15,\n                        fill: '#FFD200',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 4,\n                    bounds: { width: 84, height: 20 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                amount: {\n                    visible: true,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 27,\n                        fill: '#C6C5C5', // '#FFFFFF'\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontWeight: 'bold',\n                        fontSize: 27,\n                        fill: '#FFFFFF',\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 27,\n                    bounds: { width: 84, height: 20 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                label: {\n                    visible: false,\n                    defaultStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 16,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                        padding: 5,\n                    }),\n                    selectedStyle: new TextStyle({\n                        fontFamily: 'Arial',\n                        fontSize: 16,\n                        fontWeight: 'bold',\n                        fill: '#FFD200',\n                        padding: 5,\n                    }),\n                    x: AutoAlign.CENTER,\n                    y: 52,\n                    bounds: { width: 78, height: 17 },\n                    textAlign: TextAlign.CENTER,\n                    debug: false,\n                    shouldFitInBounds: true,\n                },\n                stamp: {\n                    hasStamp: false,\n                    x: 0,\n                    y: 0,\n                    width: 0,\n                    height: 0,\n                    alpha: 0,\n                    texture: { source: '', name: '' },\n                },\n                textures: ['svgBet', 'svgBetPressed', 'svgBet', 'svgBet'],\n                selectedTextures: ['svgActiveBet', 'svgActiveBetPressed', 'svgActiveBet', 'svgActiveBet'],\n                width: 94,\n                height: 75,\n            },\n        })\n        public betButtonsConfigs: DynamicPositionObject<IBetButtonsConfig> & IBetButtonsConfig;\n\n        public betButtons: Array<DynamicPositionObject<IMenuBetButton>> = [\n            new DynamicPositionObject<IMenuBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs },\n            }),\n            new DynamicPositionObject<IMenuBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs },\n            }),\n            new DynamicPositionObject<IMenuBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs },\n            }),\n            new DynamicPositionObject<IMenuBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigs },\n            }),\n            new DynamicPositionObject<IMenuBetButton>({\n                // @ts-ignore\n                defaults: { betConfig: this.betButtonsConfigsSpj },\n            }),\n        ];\n\n        @ModifyValue<IBetViewInterface>({\n            defaults: {\n                winlinesTextY: 110,\n                betsTextY: 364,\n                denominationsTextY: 617,\n                linesButtonsY: 162,\n                betButtonsY: 416,\n                denominationButtonsY: 670,\n                widthBounds: 0,\n                heightBounds: 0,\n                viewTopOffset: 0,\n                buttonsOffsetX: [8, 8, 8, 8, 8, 8],\n                buttonsOffsetY: 20,\n                balanceContainerX: 50,\n                balanceContainerY: 1060,\n                betContainerX: 715,\n                betContainerY: 1060,\n                firstButtonPositionsX: [325, 260, 196, 133, 70, 4],\n                denomButtonScale: [1, 1, 1, 1, 1, 1],\n                titleTextStyle: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 28,\n                    lineHeight: 32,\n                    fontWeight: 'bold',\n                    fill: 0xffffff,\n                    padding: 5,\n                }),\n                balanceTextStyle: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 22,\n                    fontWeight: 'bold',\n                    fill: 0xffffff,\n                    padding: 3,\n                }),\n                betTextStyle: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 22,\n                    fontWeight: 'bold',\n                    fill: 0xffffff,\n                    padding: 3,\n                }),\n                betValueStyle: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 22,\n                    fontWeight: 'bold',\n                    fill: 0xffffff,\n                }),\n                balanceValueStyle: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 22,\n                    fontWeight: 'bold',\n                    fill: 0xffffff,\n                }),\n                hasLinesSection: true,\n                denominationButtonTextures: ['svgBet', 'svgBetPressed', 'svgBet', 'svgBet'],\n                denominationButtonSelectedTextures: [\n                    'svgBetBlue',\n                    'svgBetBluePressed',\n                    'svgBetBlueHover',\n                    'svgBetBlue',\n                ],\n                allButtonsBounds: {\n                    width: 120,\n                    height: 86,\n                },\n                winlinesButtonTextures: ['svgBet', 'svgBetPressed', 'svgBet', 'svgBet'],\n                winlinesButtonSelectedTextures: [\n                    'svgActiveBetPressed',\n                    'svgActiveBetPressed',\n                    'svgActiveBetPressed',\n                    'svgActiveBetPressed',\n                ],\n                winlinesButtonTextOffsetX: 14,\n                winlinesButtonTextOffsetY: 15,\n                winlineTextStyle: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 25,\n                    fontWeight: 'bold',\n                    fill: '#FFFFFF',\n                }),\n                selectedLinesValueTextStyle: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 35,\n                    fontWeight: 'bold',\n                    fill: '#FFFFFF',\n                }),\n                defaultLinesValueTextStyle: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 35,\n                    fontWeight: 'bold',\n                    fill: '#C6C5C5',\n                }),\n            },\n            landscape: {\n                // x: 365,\n                // y: 0,\n                winlinesTextY: 0,\n                betsTextY: 168,\n                denominationsTextY: 335,\n                balanceContainerX: 50,\n                balanceContainerY: 500,\n                betContainerX: 1310,\n                betContainerY: 500,\n                firstButtonPositionsX: [620, 557, 493, 429, 365, 300],\n                linesButtonsY: 52,\n                betButtonsY: 220,\n                denominationButtonsY: 388,\n            },\n            desktop: {\n                // x: 97,\n                // y: 55,\n                // winlinesTextY: 55,\n                widthBounds: 770,\n                heightBounds: 454,\n                viewTopOffset: 117,\n                buttonsOffsetX: [27, 27, 27, 27, 27, 27],\n                buttonsOffsetY: 6,\n                balanceContainerX: 60,\n                balanceContainerY: 0,\n                betContainerX: 710,\n                betContainerY: 0,\n                titleTextStyle: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 19,\n                    lineHeight: 21,\n                    fontWeight: 'bold',\n                    fill: 0xffffff,\n                    padding: 5,\n                }),\n                balanceTextStyle: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 18,\n                    fill: 0xffffff,\n                    padding: 3,\n                }),\n                betTextStyle: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 18,\n                    fill: 0xffffff,\n                    padding: 3,\n                }),\n                betValueStyle: new TextStyle({\n                    fontFamily: 'Arial',\n                    fill: 0xffffff,\n                    fontSize: 18,\n                }),\n                balanceValueStyle: new TextStyle({\n                    fontFamily: 'Arial',\n                    fill: 0xffffff,\n                    fontSize: 18,\n                }),\n                denominationButtonTextures: ['svgBet', 'svgBetPressed', 'svgBetHover', 'svgBet'],\n                denominationButtonSelectedTextures: [\n                    'svgBetBlue',\n                    'svgBetBluePressed',\n                    'svgBetBlueHover',\n                    'svgBetBlue',\n                ],\n                allButtonsBounds: {\n                    width: 94,\n                    height: 75,\n                },\n                winlineTextStyle: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 18,\n                    fontWeight: 'bold',\n                    fill: '#FFFFFF',\n                }),\n                selectedLinesValueTextStyle: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 24,\n                    fontWeight: 'bold',\n                    fill: '#FFFFFF',\n                }),\n                defaultLinesValueTextStyle: new TextStyle({\n                    fontFamily: 'Arial',\n                    fontSize: 24,\n                    fontWeight: 'bold',\n                    fill: '#C6C5C5',\n                }),\n            },\n        })\n        public betViewProps: DynamicPositionObject<IBetViewInterface> & IBetViewInterface;\n\n        @ModifyValue<IGeneralSettingsInterface>({\n            defaults: {\n                textStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'Arial',\n                    fontSize: 31,\n                    lineHeight: 38,\n                    fontWeight: 'bold',\n                    // wordWrap: true,\n                }),\n                italicTextStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'Arial',\n                    fontSize: 24,\n                    lineHeight: 28,\n                    wordWrap: true,\n                }),\n            },\n            desktop: {\n                textStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'Arial',\n                    fontSize: 21,\n                    lineHeight: 26,\n                    fontWeight: 'bold',\n                    // wordWrap: true,\n                }),\n                italicTextStyle: new TextStyle({\n                    fill: '#FFFFFF',\n                    fontFamily: 'Arial',\n                    fontSize: 16,\n                    lineHeight: 22,\n                    wordWrap: true,\n                }),\n            },\n        })\n        public generalSettingsProps: DynamicPositionObject<IGeneralSettingsInterface> & IGeneralSettingsInterface;\n\n        @ModifyValue<IAutoplayNumericInputsViewProps>({\n            defaults: {\n                stopOnText: new DynamicPositionObject<IPointData>({\n                    defaults: { x: 41, y: -22 },\n                    portrait: { x: 42, y: 85 },\n                }),\n                settingsMenuCover: new DynamicPositionObject<ISettingsMenuCover>({\n                    defaults: {\n                        width: 765,\n                        height: 118,\n                        color: 0x000000,\n                        x: 0,\n                        y: 551,\n                    },\n                }),\n            },\n        })\n        public autoplayNumericInputsViewProps: DynamicPositionObject<IAutoplayNumericInputsViewProps> &\n            IAutoplayNumericInputsViewProps;\n\n        @ModifyValue<IOneDenomBetViewInterface>({\n            defaults: {\n                winlinesTextY: 189,\n            },\n            portrait: {\n                winlinesTextY: 122,\n            },\n        })\n        public oneDenomBetViewProps: DynamicPositionObject<IOneDenomBetViewInterface> & IOneDenomBetViewInterface;\n    }\n    return SingleProgressiveSettingsPopupComponentConfiguration;\n}\n","import { DynamicPositionObject, ModifyValue } from '@egt/core';\nimport { GameTitleComponentConfiguration, IGameTitlePosition } from '@egt/game-title';\nimport { TextStyle } from 'pixi.js';\n\nexport default function SingleProgressiveTitleComponentConfigurationFactory(\n    ClassType: typeof GameTitleComponentConfiguration,\n): typeof GameTitleComponentConfiguration {\n    class SingleProgressiveTitleComponentConfiguration extends ClassType {\n        @ModifyValue<IGameTitlePosition>({\n            defaults: {\n                x: 0,\n                y: 0,\n                anchorX: 0,\n                anchorY: 0,\n                textStyle: new TextStyle({\n                    fontFamily: 'Arial, sans-serif',\n                    fontWeight: 'bold',\n                    fontSize: 15,\n                    fill: '#888888',\n                    align: 'center',\n                    breakWords: true,\n                    wordWrap: true,\n                    wordWrapWidth: 120,\n                }),\n            },\n            portrait: {\n                x: 14,\n                y: 1328,\n                textStyle: new TextStyle({\n                    fontFamily: 'Arial, sans-serif',\n                    fontSize: 15,\n                    fontWeight: 'bold',\n                    fill: '#888888',\n                    align: 'center',\n                    breakWords: true,\n                    wordWrap: true,\n                    wordWrapWidth: 765,\n                }),\n            },\n            landscape: {\n                x: 70,\n                y: 746,\n                anchorX: 0.5,\n                anchorY: 0.5,\n                textStyle: new TextStyle({\n                    fontFamily: 'Arial, sans-serif',\n                    fontSize: 15,\n                    fontWeight: 'bold',\n                    fill: '#888888',\n                    align: 'center',\n                    breakWords: true,\n                    wordWrap: true,\n                    wordWrapWidth: 140,\n                }),\n            },\n            desktop: {\n                x: 112,\n                y: 738,\n                textStyle: new TextStyle({\n                    fontFamily: 'Arial, sans-serif',\n                    fontWeight: 'bold',\n                    fontSize: 15,\n                    fill: '#888888',\n                    align: 'center',\n                    breakWords: true,\n                    wordWrap: false,\n                    wordWrapWidth: 120,\n                }),\n            },\n        })\n        public gameTitlePosition: DynamicPositionObject<IGameTitlePosition> & IGameTitlePosition;\n    }\n    return SingleProgressiveTitleComponentConfiguration;\n}\n","import { DynamicPositionObject, ModifyValue } from '@egt/core';\nimport { IMoneyFieldDefault, UIMainPanelComponentConfigurationDefault } from '@egt/ui-main-panel';\n\nexport default function SingleProgressiveUIMainPanelComponentConfigurationFactoryDefault(\n    ClassType: typeof UIMainPanelComponentConfigurationDefault,\n): typeof UIMainPanelComponentConfigurationDefault {\n    class SingleProgressiveUIMainPanelComponentConfiguration extends ClassType {\n        @ModifyValue<IMoneyFieldDefault>({\n            desktop: {\n                y: 648,\n            },\n            landscape: {\n                y: 678,\n            },\n            portrait: {\n                y: 720,\n            },\n        })\n        public balanceContainerProperties: DynamicPositionObject<IMoneyFieldDefault> & IMoneyFieldDefault;\n\n        @ModifyValue<IMoneyFieldDefault>({\n            desktop: {\n                y: 648,\n            },\n            landscape: {\n                y: 678,\n            },\n            portrait: {\n                y: 720,\n            },\n        })\n        public winContainerProperties: DynamicPositionObject<IMoneyFieldDefault> & IMoneyFieldDefault;\n    }\n    return SingleProgressiveUIMainPanelComponentConfiguration;\n}\n","import { DynamicPositionObject, ModifyValue } from '@egt/core';\nimport { GambleFeatureConfigurationDefault, IPointWithScale } from '@egt/gamble';\nimport { IPointData } from 'pixi.js';\n\nexport default function SingleProgressiveGambleFeatureConfigurationFactoryDefault(\n    ClassType: typeof GambleFeatureConfigurationDefault,\n): typeof GambleFeatureConfigurationDefault {\n    class SingleProgressiveGambleFeatureConfigurationDefault extends ClassType {\n        @ModifyValue<IPointWithScale>({\n            desktop: { x: 678 },\n            landscape: { x: 678 },\n        })\n        public animatedCards: DynamicPositionObject<IPointWithScale> & IPointWithScale;\n\n        @ModifyValue<IPointData>({\n            desktop: { x: 683 },\n            landscape: { x: 683 },\n            portrait: { x: 385 },\n        })\n        public gambleAttemptsLeft: DynamicPositionObject<IPointData> & IPointData;\n    }\n    return SingleProgressiveGambleFeatureConfigurationDefault;\n}\n","import Core, {\n    Align,\n    AssetPriority,\n    GameTypes,\n    IAsset,\n    IBaseConfiguration,\n    ISoundAsset,\n    IStageOptions,\n    Language,\n    PositionObject,\n    Scale,\n} from '@egt/core';\nimport { injectable } from 'tsyringe';\nimport Features from '../components/feature/Features';\nimport { IBrandingConfiguration } from '../components/interfaces/IBrandingConfiguration';\nimport { IDenomButtonStyle } from '../components/interfaces/IDenomButtonStyle';\nimport { ISymbol } from '../components/symbols/ISymbol';\nimport { ISlotConfiguration } from './ISlotConfiguration';\n\n@injectable()\nexport default class SlotConfiguration implements ISlotConfiguration, IBaseConfiguration {\n    protected _maxWinFactor: string = '5000x';\n    protected _maxWinFactorDoubleChanceActive: string = '4000x';\n\n    protected _rngPresets: Array<{ name: string; values: string }> = [];\n\n    get rngPresets(): Array<{ name: string; values: string }> {\n        return this._rngPresets;\n    }\n\n    get maxWinFactor(): string {\n        return this._maxWinFactor;\n    }\n    get maxWinFactorDoubleChanceActive(): string {\n        return this._maxWinFactorDoubleChanceActive;\n    }\n    protected _gameHasLinesButNoLinesTile: boolean = false;\n    get gameHasLinesButNoLinesTile(): boolean {\n        return this._gameHasLinesButNoLinesTile;\n    }\n    public customSendGuards: boolean = true;\n    protected readonly gameKey: string = Core.configuration.gameKey;\n    protected _hasSquaresOnlyOnScatters: boolean = false;\n    protected _symbolsVideosConfig: any[];\n    protected _noTintedSymbols: any[] = [];\n    protected _hasFreeSpins: boolean = false;\n    protected _numberOfGameSymbols: number = 11;\n    protected _numberOfLines: number = 30;\n\n    // protected _doubleChanceFactorIndex: number = 1;\n    protected _buyBonusGameMode: string = 'BUY_BONUS';\n    protected _superBuyBonusGameMode: string = 'SUPER_BUY_BONUS';\n    protected _megaBuyBonusGameMode: string = 'MEGA_BUY_BONUS';\n\n    protected _jackpotValueLoadOffset: number = 50;\n\n    protected _cloneGameKey: string;\n\n    // Use this config when a VIP version extends a branding game, so it can reuse\n    // the branding assets and logic instead of duplicating them in VIP.\n    protected _brandingGameKey: string;\n\n    protected _stageOptions: IStageOptions = {\n        width: 1360,\n        height: 765,\n        scale: Scale.KEEP_ASPECT_RATIO,\n        align: Align.MIDDLE,\n        resolution: window.devicePixelRatio,\n        backgroundAlpha: 0,\n        backgroundColor: 0x000000,\n        changeOrientation: true,\n        antialias: false,\n    };\n\n    protected _desktopScale: number = 1;\n    protected _hasOldBuyBonusRTPs: boolean = false;\n    protected _symbols: ISymbol[] = [];\n    protected _timeSymbolTravelDuration: number = 66.667; // ms\n    protected _wildIndex: number = 8;\n    protected _wildForJackpot: number = 5;\n    protected _reelsMinimumSpinTime: number = 0;\n    protected _symbolsConfig: any[] = [];\n    protected _reelsBoostSymbolsConfig: any[] = [];\n    protected _videoConfigs: any[] = [];\n    protected _commonFPS: number = 30; // Default FPS for all animations\n    protected _symbolTextureExtension: string = '.png'; // Default file extension for symbol textures\n    protected _lines: Array<{ cells: number[]; axisY: number }> = [];\n    protected _assets: Array<IAsset | ISoundAsset> = [];\n    protected _fonts: IAsset[] = [\n        {\n            id: 'FuturaPT-ExtraBold',\n            url: '../assets/Fonts/FuturaPT-ExtraBold/FuturaPT-ExtraBold.ttf',\n            priority: AssetPriority.HIGHEST,\n            type: 'font',\n        },\n        {\n            id: 'FuturaPT',\n            url: '../assets/Fonts/FuturaPT/FuturaPT.ttf',\n            priority: AssetPriority.HIGHEST,\n            type: 'font',\n        },\n        {\n            id: 'FuturaPTCond-Bold',\n            url: '../assets/Fonts/FuturaPTCond-Bold/FuturaPTCond-Bold.ttf',\n            priority: AssetPriority.HIGHEST,\n            type: 'font',\n        },\n        {\n            id: 'FuturaPT-Bold',\n            url: '../assets/Fonts/FuturaPT-Bold/FuturaPT-Bold.ttf',\n            priority: AssetPriority.HIGHEST,\n            type: 'font',\n        },\n        {\n            id: 'FuturaPT-Book',\n            url: '../assets/Fonts/FuturaPT-Book/FuturaPT-Book.ttf',\n            priority: AssetPriority.HIGHEST,\n            type: 'font',\n        },\n        {\n            id: 'FuturaPT-Medium',\n            url: '../assets/Fonts/FuturaPT-Medium/FuturaPT-Medium.ttf',\n            priority: AssetPriority.HIGHEST,\n            type: 'font',\n        },\n    ];\n    protected _tileSize: number = 64;\n    protected _supportedLanguages: Language[] = [Language.EN];\n    protected _componentsConfiguration: any = [];\n    protected _gameTitle: string;\n    protected _gameTitleShort?: string;\n    protected _vipGameTitle?: string;\n    protected _vipGameTitleShort?: string;\n    protected _gameLogoLandscapeConfig: any = { visible: false, positionX: 0, positionY: 0, scale: 1 };\n    protected _mainPanelSideGraphicsConfig: any = {\n        width: 149.5,\n        leftGraphicPosition: -1,\n        rightGraphicPosition: 149.5,\n    };\n    protected _gameLogoPortraitConfig: any = { visible: true, positionX: 0, positionY: 200, scale: 1 };\n    protected _gameLogoPosition: PositionObject = new PositionObject({\n        landscape: { visible: true, x: 0, y: 0, scale: 1 },\n        portrait: { visible: true, x: -1, y: 200, scale: 1 },\n    });\n    protected _winThresholds: number[] = [0, 10, 50, 500, 1500, 3000, 10000];\n    protected _winBangupDurations: number[] = [2, 4, 6, 8, 12, 16, 18]; // in seconds\n    protected _autoplayBangupDuration: number = 4;\n    protected _freeSpinBangupDuration: number = 4;\n    protected _bellLinkBangupDuration: number = 8;\n    protected _collectBangupDuration: number = 1; // in seconds\n    protected _scattersConfig: any[];\n    protected _gameFeatures: any[] = [];\n    protected _coinFeatureCoef: number[] = [20];\n    protected _coinFeatureCoefBuyBonus: number[];\n    protected _buyBonusThresholdGameModes: string[];\n    protected _bellLinkCoinFeatureCoef: number = 50;\n    protected _backgroundAnimationShouldPauseOnGamePause: boolean = false;\n\n    protected _helpAssetsFolder: string = '';\n    protected _setCloneGameKeyForHelpAssets: boolean = true;\n    // protected _normalFactorIndex: number = 0;\n\n    protected _waitBetweenMessages: number = 2; // in seconds - prev 3.8\n    protected _cascadeGame: boolean = false;\n    protected _retriggerPopup: { overlay: { color: number; opacity: number } } = {\n        overlay: { color: 0x000000, opacity: 0.6 },\n    };\n    protected _autoplayWinTime: number = 3000;\n    protected _autoplayWinQuickTime: number = 2000;\n    protected _autoplayWinTurboTime: number = 1500;\n    protected _autoplayWinCoinFeatureTime: number = 5000;\n    protected _autoplayWinBigWinTime: number = 500;\n    protected _autoplayDelayOnNonWiningSpin: number = 133;\n    protected _backgroundSoundsGroup: string[] = [\n        'backgroundMusic',\n        'backgroundNoPlay',\n        'freeSpinsBackgroundSound',\n        'superFreeSpinsBackgroundSound',\n        'backgroundMusicLoop',\n    ];\n    // protected _haveBackgroundMusicButton: boolean = true;\n\n    // based of the configuration for number of reels visible symbols per reel and guard symbols\n    // initial reels used only part from next array you can see logic in sloGame wen configuration is loaded\n    protected _initialReels: number[][] | null = null;\n    protected _payTableCoef: any = {\n        '0': { coef: [2, 8, 15], multiplier: 1 },\n        '1': { coef: [2, 8, 15], multiplier: 1 },\n        '2': { coef: [4, 10, 20], multiplier: 1 },\n        '3': { coef: [4, 10, 20], multiplier: 1 },\n        '4': { coef: [6, 15, 25], multiplier: 1 },\n        '5': { coef: [8, 15, 30], multiplier: 1 },\n        '6': { coef: [8, 15, 40], multiplier: 1 },\n        '7': { coef: [4, 10, 20, 45], multiplier: 1 },\n        '8': { coef: [5, 10, 20, 50], multiplier: 1 },\n        '9': { coef: [10, 50, 250, 1000], multiplier: 1 },\n        '10': { coef: [2, 2, 2], multiplier: 1 },\n    };\n    protected _freespinSpine: boolean = false;\n    protected _freespinSpineDesktop: boolean = false;\n    protected _freespinElements: boolean = false;\n    protected _respinElements: boolean = true;\n\n    /**\n     * Used to store the calculated symbols config.\n     * The idea is to avoid recalculating the symbols config every time it is accessed.\n     * The explicit adding of config for symbol texture and win sound is now obsolete.\n     * The code uses the symbol name to assemble the config.\n     */\n    protected _calculatedSymbolsConfig: any[] = null!;\n\n    // protected _uiAssets: IAsset;\n    // protected _uiAssets: IAsset = {\n    //     id: 'miscellaneous',\n    //     url: '../assets/commons/images/miscellaneous/miscellaneous.json',\n    //     priority: AssetPriority.HIGHEST,\n    //     hasDesktopVersion: true,\n    //     type: 'texture',\n    // };\n\n    protected _overrideSvgs: IAsset[] = [];\n\n    private _uiSvgs: IAsset[] = [\n        // {\n        //     id: 'svgSpin',\n        //     url: '../assets/commons/images/ui/svg/spinButton.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 219, height: 219 },\n        //         desktop: { width: 150, height: 150 },\n        //     },\n        // },\n        // {\n        //     id: 'svgSpinDisabled',\n        //     url: '../assets/commons/images/ui/svg/spinButtonDisabled.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 219, height: 219 },\n        //         desktop: { width: 150, height: 150 },\n        //     },\n        // },\n        // {\n        //     id: 'svgSpinSkipAnimation',\n        //     url: '../assets/commons/images/ui/svg/spinSkipAnimationButton.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 219, height: 219 },\n        //         desktop: { width: 150, height: 150 },\n        //     },\n        // },\n        // {\n        //     id: 'svgAutoPlay',\n        //     url: '../assets/commons/images/ui/svg/autoplayButton.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 132, height: 132 },\n        //         desktop: { width: 99, height: 99 },\n        //     },\n        // },\n\n        // {\n        //     id: 'svgAutoPlayInactive',\n        //     url: '../assets/commons/images/ui/svg/autoplayButtonDisabled.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 132, height: 132 },\n        //         desktop: { width: 99, height: 99 },\n        //     },\n        // },\n        // {\n        //     id: 'svgAutoPlayStop',\n        //     url: '../assets/commons/images/ui/svg/autoplayStopButton.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 219, height: 219 },\n        //         desktop: { width: 150, height: 150 },\n        //     },\n        // },\n        // {\n        //     id: 'svgChooseBet',\n        //     url: '../assets/commons/images/ui/svg/chooseBetButton.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     hasDesktopVersion: true,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 132, height: 132 },\n        //         desktop: { width: 99, height: 99 },\n        //     },\n        // },\n        // {\n        //     id: 'svgChooseBetInactive',\n        //     url: '../assets/commons/images/ui/svg/chooseBetButtonDisabled.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     hasDesktopVersion: true,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 132, height: 132 },\n        //         desktop: { width: 99, height: 99 },\n        //     },\n        // },\n        {\n            id: 'maxBet',\n            url: '../assets/commons/images/ui/svg/maxBet.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 120, height: 96 },\n                desktop: { width: 94, height: 75 },\n            },\n        },\n        // {\n        //     id: 'svgBet',\n        //     url: '../assets/commons/images/ui/svg/standardButton.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 120, height: 96 },\n        //         desktop: { width: 94, height: 75 },\n        //     },\n        // },\n        // {\n        //     id: 'svgBetPressed',\n        //     url: '../assets/commons/images/ui/svg/standardButtonPressed.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 120, height: 96 },\n        //         desktop: { width: 94, height: 75 },\n        //     },\n        // },\n        // {\n        //     id: 'svgActiveBet',\n        //     url: '../assets/commons/images/ui/svg/greenButton.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 120, height: 96 },\n        //         desktop: { width: 94, height: 75 },\n        //     },\n        // },\n        // {\n        //     id: 'svgActiveBetPressed',\n        //     url: '../assets/commons/images/ui/svg/greenButtonPressed.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 120, height: 96 },\n        //         desktop: { width: 94, height: 75 },\n        //     },\n        // },\n        {\n            id: 'svgBetBlue',\n            url: '../assets/commons/images/ui/svg/blueButton.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 120, height: 96 },\n                desktop: { width: 94, height: 75 },\n            },\n        },\n        {\n            id: 'svgBetBluePressed',\n            url: '../assets/commons/images/ui/svg/blueButtonPressed.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 120, height: 96 },\n                desktop: { width: 94, height: 75 },\n            },\n        },\n        // {\n        //     id: 'svgBetHover',\n        //     url: '../assets/commons/images/ui/svg/standardButtonHover.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 120, height: 96 },\n        //         desktop: { width: 94, height: 75 },\n        //     },\n        // },\n        // {\n        //     id: 'svgActiveBetHover',\n        //     url: '../assets/commons/images/ui/svg/greenButtonHover.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 120, height: 96 },\n        //         desktop: { width: 94, height: 75 },\n        //     },\n        // },\n        {\n            id: 'svgBetBlueHover',\n            url: '../assets/commons/images/ui/svg/blueButtonHover.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 120, height: 96 },\n                desktop: { width: 94, height: 75 },\n            },\n        },\n        // {\n        //     id: 'svgCollect',\n        //     url: '../assets/commons/images/ui/svg/collectButton.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 219, height: 219 },\n        //         desktop: { width: 150, height: 150 },\n        //     },\n        // },\n        // {\n        //     id: 'svgCollectDisabled',\n        //     url: '../assets/commons/images/ui/svg/collectButtonDisabled.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 219, height: 219 },\n        //         desktop: { width: 150, height: 150 },\n        //     },\n        // },\n        // {\n        //     id: 'svgCollectSmall',\n        //     url: '../assets/commons/images/ui/svg/collectSmallButton.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 132, height: 132 },\n        //         desktop: { width: 99, height: 99 },\n        //     },\n        // },\n        // {\n        //     id: 'svgCollectSmallDisabled',\n        //     url: '../assets/commons/images/ui/svg/collectSmallButtonDisabled.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 132, height: 132 },\n        //         desktop: { width: 99, height: 99 },\n        //     },\n        // },\n        // {\n        //     id: 'svgDisabledSpeed',\n        //     url: '../assets/commons/images/ui/svg/speedButtonDisabled.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 132, height: 64 },\n        //         desktop: { width: 99, height: 48 },\n        //     },\n        // },\n        // {\n        //     id: 'svgNormalSpeed',\n        //     url: '../assets/commons/images/ui/svg/normalSpeedButton.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 132, height: 64 },\n        //         desktop: { width: 99, height: 48 },\n        //     },\n        // },\n        // {\n        //     id: 'svgQuickSpeed',\n        //     url: '../assets/commons/images/ui/svg/quickSpeedButton.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 132, height: 64 },\n        //         desktop: { width: 99, height: 48 },\n        //     },\n        // },\n        // {\n        //     id: 'svgTurboSpeed',\n        //     url: '../assets/commons/images/ui/svg/turboSpeedButton.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 132, height: 64 },\n        //         desktop: { width: 99, height: 48 },\n        //     },\n        // },\n        // {\n        //     id: 'svgAutoPlayInfinity',\n        //     url: '../assets/commons/images/ui/svg/autoInfinityIcon.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 40, height: 21 },\n        //         desktop: { width: 40, height: 21 },\n        //     },\n        // },\n        {\n            id: 'svgToggleActive',\n            url: '../assets/commons/images/ui/svg/toggleButton.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 126, height: 65 },\n                desktop: { width: 67, height: 36 },\n            },\n        },\n        {\n            id: 'svgToggleInactive',\n            url: '../assets/commons/images/ui/svg/toggleButtonDisabled.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 126, height: 65 },\n                desktop: { width: 67, height: 36 },\n            },\n        },\n        {\n            id: 'svgGreyAuto',\n            url: '../assets/commons/images/ui/svg/greySliderButton.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 54, height: 57 },\n                desktop: { width: 34, height: 35 },\n            },\n        },\n        {\n            id: 'svgGreenAuto',\n            url: '../assets/commons/images/ui/svg/greenSliderButton.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 54, height: 57 },\n                desktop: { width: 34, height: 35 },\n            },\n        },\n        {\n            id: 'svgRedAuto',\n            url: '../assets/commons/images/ui/svg/redSliderButton.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 54, height: 57 },\n                desktop: { width: 34, height: 35 },\n            },\n        },\n        {\n            id: 'svgTabOn',\n            url: '../assets/commons/images/ui/svg/tabButton.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 101, height: 96 },\n                desktop: { width: 101, height: 96 },\n            },\n        },\n        {\n            id: 'svgTabOff',\n            url: '../assets/commons/images/ui/svg/tabButtonDisabled.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 101, height: 96 },\n                desktop: { width: 101, height: 96 },\n            },\n        },\n        {\n            id: 'svgBetSettingsOn',\n            url: '../assets/commons/images/ui/svg/betSettingsIcon.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 101, height: 96 },\n                desktop: { width: 101, height: 96 },\n            },\n        },\n        {\n            id: 'svgBetSettingsOff',\n            url: '../assets/commons/images/ui/svg/betSettingsIconDisabled.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 101, height: 96 },\n                desktop: { width: 101, height: 96 },\n            },\n        },\n        {\n            id: 'svgGeneralSettingsOn',\n            url: '../assets/commons/images/ui/svg/generalSettingsIcon.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 101, height: 96 },\n                desktop: { width: 101, height: 96 },\n            },\n        },\n        {\n            id: 'svgGeneralSettingsOff',\n            url: '../assets/commons/images/ui/svg/generalSettingsIconDisabled.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 101, height: 96 },\n                desktop: { width: 101, height: 96 },\n            },\n        },\n        {\n            id: 'svgAutoPlaySettingsOn',\n            url: '../assets/commons/images/ui/svg/autoplaySettingsIcon.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 101, height: 96 },\n                desktop: { width: 101, height: 96 },\n            },\n        },\n        {\n            id: 'svgAutoPlaySettingsOff',\n            url: '../assets/commons/images/ui/svg/autoplaySettingsIconDisabled.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 101, height: 96 },\n                desktop: { width: 101, height: 96 },\n            },\n        },\n        {\n            id: 'svgStartButton',\n            url: '../assets/commons/images/ui/svg/startButton.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 294, height: 104 },\n                desktop: { width: 152, height: 64 },\n            },\n        },\n        {\n            id: 'svgStartButtonInactive',\n            url: '../assets/commons/images/ui/svg/startButtonDisabled.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 294, height: 104 },\n                desktop: { width: 152, height: 64 },\n            },\n        },\n        {\n            id: 'svgStartButtonHover',\n            url: '../assets/commons/images/ui/svg/startButtonHover.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 294, height: 104 },\n                desktop: { width: 152, height: 64 },\n            },\n        },\n        {\n            id: 'svgSpinsButtonOn',\n            url: '../assets/commons/images/ui/svg/spinsButton.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 70, height: 48 },\n                desktop: { width: 70, height: 48 },\n            },\n        },\n        {\n            id: 'svgSpinsButtonOff',\n            url: '../assets/commons/images/ui/svg/spinsButtonDisabled.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 70, height: 48 },\n                desktop: { width: 70, height: 48 },\n            },\n        },\n        {\n            id: 'svgSpinsButtonGreen',\n            url: '../assets/commons/images/ui/svg/spinsButtonGreen.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 70, height: 48 },\n                desktop: { width: 70, height: 48 },\n            },\n        },\n        {\n            id: 'svgInfinity',\n            url: '../assets/commons/images/ui/svg/infinityIcon.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 48, height: 27 },\n                desktop: { width: 48, height: 27 },\n            },\n        },\n        {\n            id: 'svgInfinityBoldedDefault',\n            url: '../assets/commons/images/ui/svg/infinityIconDefaultBold.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 46, height: 45 },\n                desktop: { width: 46, height: 45 },\n            },\n        },\n        {\n            id: 'svgInfinityBoldedSelected',\n            url: '../assets/commons/images/ui/svg/infinityIconSelectedBold.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 46, height: 45 },\n                desktop: { width: 46, height: 45 },\n            },\n        },\n        {\n            id: 'svgLineLong',\n            url: '../assets/commons/images/ui/svg/lineLong.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 662, height: 7 },\n                desktop: { width: 714, height: 3 },\n            },\n        },\n\n        // icons\n\n        {\n            id: 'svgHistory',\n            url: '../assets/commons/images/ui/svg/icons/historyIcon.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 54, height: 54 },\n                desktop: { width: 25, height: 25 },\n            },\n        },\n        {\n            id: 'svgInfoOn',\n            url: '../assets/commons/images/ui/svg/infoIcon.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 101, height: 96 },\n                desktop: { width: 101, height: 96 },\n            },\n        },\n        {\n            id: 'svgInfoOff',\n            url: '../assets/commons/images/ui/svg/infoIconDisabled.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 101, height: 96 },\n                desktop: { width: 101, height: 96 },\n            },\n        },\n        {\n            id: 'svgHelpOn',\n            url: '../assets/commons/images/ui/svg/helpIcon.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 101, height: 96 },\n                desktop: { width: 101, height: 96 },\n            },\n        },\n        {\n            id: 'svgHelpOff',\n            url: '../assets/commons/images/ui/svg/helpIconDisabled.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 101, height: 96 },\n                desktop: { width: 101, height: 96 },\n            },\n        },\n        // {\n        //     id: 'svgInfo',\n        //     url: '../assets/commons/images/ui/svg/icons/info.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     hasDesktopVersion: true,\n        //     config: {\n        //         mobile: { width: 76, height: 76 },\n        //         desktop: { width: 32, height: 32 },\n        //     },\n        // },\n        // {\n        //     id: 'svgHome',\n        //     url: '../assets/commons/images/ui/svg/icons/home.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     hasDesktopVersion: true,\n        //     config: {\n        //         mobile: { width: 76, height: 76 },\n        //         desktop: { width: 32, height: 32 },\n        //     },\n        // },\n        // {\n        //     id: 'svgSettings',\n        //     url: '../assets/commons/images/ui/svg/icons/settings.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     hasDesktopVersion: true,\n        //     config: {\n        //         mobile: { width: 76, height: 76 },\n        //         desktop: { width: 32, height: 32 },\n        //     },\n        // },\n        // {\n        //     id: 'svgSettingsClose',\n        //     url: '../assets/commons/images/ui/svg/icons/settingsClose.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     // hasDesktopVersion: true,\n        //     config: {\n        //         mobile: { width: 76, height: 76 },\n        //         desktop: { width: 76, height: 76 },\n        //     },\n        // },\n        // {\n        //     id: 'svgEgtLobbyButton',\n        //     url: '../assets/commons/images/ui/svg/icons/egtLobbyButton.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     // hasDesktopVersion: true,\n        //     config: {\n        //         mobile: { width: 76, height: 76 },\n        //         desktop: { width: 76, height: 76 },\n        //     },\n        // },\n        {\n            id: 'svgExitLobbyButton',\n            url: '../assets/commons/images/ui/svg/icons/exitLobbyButton.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            // hasDesktopVersion: true,\n            config: {\n                mobile: { width: 76, height: 76 },\n                desktop: { width: 76, height: 76 },\n            },\n        },\n        // {\n        //     id: 'svgLobbyPopupClose',\n        //     url: '../assets/commons/images/ui/svg/icons/lobbyPopupClose.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     // hasDesktopVersion: true,\n        //     config: {\n        //         mobile: { width: 76, height: 76 },\n        //         desktop: { width: 76, height: 76 },\n        //     },\n        // },\n        // {\n        //     id: 'svgSound',\n        //     url: '../assets/commons/images/ui/svg/icons/speak.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     hasDesktopVersion: true,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 70, height: 70 },\n        //         desktop: { width: 32, height: 32 },\n        //     },\n        // },\n        // {\n        //     id: 'svgSoundOff',\n        //     url: '../assets/commons/images/ui/svg/icons/speakOff.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     hasDesktopVersion: true,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 70, height: 70 },\n        //         desktop: { width: 32, height: 32 },\n        //     },\n        // },\n        // {\n        //     id: 'musicBackgroundOn',\n        //     url: '../assets/commons/images/ui/svg/icons/musicBackgroundOn.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     hasDesktopVersion: true,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 70, height: 70 },\n        //         desktop: { width: 32, height: 32 },\n        //     },\n        // },\n        // {\n        //     id: 'musicBackgroundOnDisabled',\n        //     url: '../assets/commons/images/ui/svg/icons/musicBackgroundOnDisabled.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     hasDesktopVersion: true,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 70, height: 70 },\n        //         desktop: { width: 32, height: 32 },\n        //     },\n        // },\n        // {\n        //     id: 'musicBackgroundOff',\n        //     url: '../assets/commons/images/ui/svg/icons/musicBackgroundOff.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     hasDesktopVersion: true,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 70, height: 70 },\n        //         desktop: { width: 32, height: 32 },\n        //     },\n        // },\n        // {\n        //     id: 'musicBackgroundOffDisabled',\n        //     url: '../assets/commons/images/ui/svg/icons/musicBackgroundOffDisabled.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     hasDesktopVersion: true,\n        //     type: 'svg',\n        //     config: {\n        //         mobile: { width: 70, height: 70 },\n        //         desktop: { width: 32, height: 32 },\n        //     },\n        // },\n        // {\n        //     id: 'svgFullscreen',\n        //     url: '../assets/commons/images/ui/svg/icons/fullscreen.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     config: {\n        //         desktop: { width: 32, height: 32 },\n        //     },\n        // },\n        // {\n        //     id: 'svgFullscreenExit',\n        //     url: '../assets/commons/images/ui/svg/icons/exitFullscreen.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     config: {\n        //         desktop: { width: 32, height: 32 },\n        //     },\n        // },\n        // {\n        //     id: 'svgHelp',\n        //     url: '../assets/commons/images/ui/svg/icons/help.svg',\n        //     priority: AssetPriority.HIGHEST,\n        //     type: 'svg',\n        //     hasDesktopVersion: true,\n        //     config: {\n        //         desktop: { width: 32, height: 32 },\n        //     },\n        // },\n        // General settings icons + setting background\n        {\n            id: 'popupFill',\n            url: '../assets/commons/images/miscellaneous/popupFill.json',\n            priority: AssetPriority.HIGHEST,\n            type: 'texture',\n        },\n        {\n            id: 'soundEffectsOn',\n            url: '../assets/commons/images/ui/svg/icons/soundEffectsOn.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 54, height: 54 },\n                desktop: { width: 36, height: 36 },\n            },\n        },\n        {\n            id: 'soundEffectsOff',\n            url: '../assets/commons/images/ui/svg/icons/soundEffectsOff.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 54, height: 54 },\n                desktop: { width: 36, height: 36 },\n            },\n        },\n        {\n            id: 'leftHandModeOn',\n            url: '../assets/commons/images/ui/svg/icons/leftHandModeOn.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 54, height: 54 },\n                desktop: { width: 36, height: 36 },\n            },\n        },\n        {\n            id: 'leftHandModeOff',\n            url: '../assets/commons/images/ui/svg/icons/leftHandModeOff.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 54, height: 54 },\n                desktop: { width: 36, height: 36 },\n            },\n        },\n        {\n            id: 'quickSpinOn',\n            url: '../assets/commons/images/ui/svg/icons/quickSpinOn.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 54, height: 54 },\n                desktop: { width: 36, height: 36 },\n            },\n        },\n        {\n            id: 'quickSpinOff',\n            url: '../assets/commons/images/ui/svg/icons/quickSpinOff.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 54, height: 54 },\n                desktop: { width: 36, height: 36 },\n            },\n        },\n        {\n            id: 'turboSpinOn',\n            url: '../assets/commons/images/ui/svg/icons/turboSpinOn.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 54, height: 54 },\n                desktop: { width: 36, height: 36 },\n            },\n        },\n        {\n            id: 'turboSpinOff',\n            url: '../assets/commons/images/ui/svg/icons/turboSpinOff.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 54, height: 54 },\n                desktop: { width: 36, height: 36 },\n            },\n        },\n        {\n            id: 'musicOn',\n            url: '../assets/commons/images/ui/svg/icons/musicOn.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 54, height: 54 },\n                desktop: { width: 36, height: 36 },\n            },\n        },\n        {\n            id: 'musicOff',\n            url: '../assets/commons/images/ui/svg/icons/musicOff.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 54, height: 54 },\n                desktop: { width: 36, height: 36 },\n            },\n        },\n        {\n            id: 'batterySaverModeOn',\n            url: '../assets/commons/images/ui/svg/icons/batterySaverModeOn.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 54, height: 54 },\n                desktop: { width: 36, height: 36 },\n            },\n        },\n        {\n            id: 'batterySaverModeOff',\n            url: '../assets/commons/images/ui/svg/icons/batterySaverModeOff.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 54, height: 54 },\n                desktop: { width: 36, height: 36 },\n            },\n        },\n        {\n            id: 'historyOn',\n            url: '../assets/commons/images/ui/svg/icons/HistoryOn.svg',\n            priority: AssetPriority.HIGHEST,\n            type: 'svg',\n            config: {\n                mobile: { width: 54, height: 54 },\n                desktop: { width: 36, height: 36 },\n            },\n        },\n    ];\n    protected soundAssets = {\n        id: 'mainSounds',\n        url: '../assets/commons/sounds/mainSounds.mp3',\n        priority: AssetPriority.HIGHEST,\n        type: 'sound',\n        sprite: {\n            autoplaySelectSound: [0, 370.3628117913832],\n            changeBetSound: [2000, 370.3628117913831],\n            changeDenominationSound: [4000, 547.5283446712016],\n            chosenDenominationSound: [6000, 500],\n            collectSound: [8000, 1485.5782312925178],\n            creditSound: [11000, 384.6031746031748],\n            currencySound: [13000, 1384.603174603175],\n            fullLine1: [16000, 4274.0589569161],\n            fullLine2: [22000, 4701.927437641722],\n            fullLine3: [28000, 4826.9387755102],\n            fullLine4: [34000, 5538.480725623586],\n            gsCountDown: [41000, 3520.7256235827626],\n            hideDenominationsSound: [46000, 461.5419501133786],\n            homeSound: [48000, 802.9024943310645],\n            jpWonByAnotherPlayer: [50000, 2451.9274376417216],\n            lineChange1: [54000, 759.6371882086146],\n            lineChange2: [56000, 596.1678004535145],\n            lineChange3: [58000, 533.6734693877575],\n            lineChange4: [60000, 673.0839002267572],\n            lineChange5: [62000, 754.829931972786],\n            menuSound: [64000, 100.97505668933593],\n            moneyAnimationEndSound: [66000, 1384.6031746031713],\n            paytableSound: [69000, 370.22675736960764],\n            quickReelsStop: [71000, 216.34920634920718],\n            showDenominationsSound: [73000, 370.2040816326502],\n            slideButton: [75000, 937.5056689342358],\n            sliderClick: [77000, 34.5804988662195],\n            spinSound: [79000, 274.0362811791357],\n            startAutoplaySound: [81000, 259.6145124716571],\n            stopAutoplaySound: [83000, 533.6507936507928],\n            stopReelAllSound: [85000, 173.06122448979977],\n            stopReelSound: [87000, 365.3968253968287],\n            turboQuickOff: [89000, 375.01133786848584],\n            turboQuickOn: [91000, 451.9274376417286],\n            turboQuickOn2: [93000, 375.01133786848584],\n            turboReelsStop: [95000, 173.06122448979977],\n            unmuteSound: [97000, 163.44671201814265],\n        },\n    };\n\n    protected _freeSpinAssets: Array<IAsset | ISoundAsset> = [];\n\n    protected _tournamentsDefault: any = {\n        button: {\n            landscape: {\n                default: {\n                    hidden: false,\n                    scale: 1,\n                    leftHand: { x: 1284, y: 522 },\n                    rightHand: { x: 76, y: 522 },\n                },\n            },\n            portrait: {\n                default: {\n                    hidden: false,\n                    scale: 1,\n                    leftHand: { x: 60, y: 1170 },\n                    rightHand: { x: 60, y: 1170 },\n                },\n            },\n            desktop: {\n                default: {\n                    hidden: false,\n                    scale: 1,\n                    rightHand: { x: 88, y: 522 },\n                },\n            },\n            features: {\n                [Features.FREE_SPINS]: {\n                    portrait: { hidden: true },\n                    landscape: { hidden: true },\n                },\n                [Features.BASE_FREE_SPINS]: {\n                    portrait: { hidden: true },\n                    landscape: { hidden: true },\n                },\n                [Features.GAMBLE]: {\n                    portrait: { hidden: true },\n                    landscape: { hidden: true },\n                    desktop: { hidden: true },\n                },\n                [Features.BL_JACKPOT]: {\n                    portrait: { hidden: true },\n                    landscape: { hidden: true },\n                    desktop: { hidden: true },\n                },\n            },\n        },\n    };\n\n    protected _tournaments: any = {};\n\n    // Overrided TextStyle for the bet buttons. By default is null. Set in game where different colors or fonts needed\n    protected _denomButtonStyles: IDenomButtonStyle;\n    protected _denomButtonStylesDesktop: IDenomButtonStyle;\n    protected _brandingConfig: Map<string, IBrandingConfiguration>;\n    protected _gameType: GameTypes = GameTypes.STANDARD_SLOT;\n    public get gameType(): GameTypes {\n        return this._gameType;\n    }\n\n    public get brandingConfig(): Map<string, IBrandingConfiguration> {\n        return this._brandingConfig;\n    }\n    public set brandingConfig(value: Map<string, IBrandingConfiguration>) {\n        this._brandingConfig = value;\n    }\n\n    public get hasSquaresOnlyOnScatters(): boolean {\n        return this._hasSquaresOnlyOnScatters;\n    }\n    public set hasSquaresOnlyOnScatters(value: boolean) {\n        this._hasSquaresOnlyOnScatters = value;\n    }\n\n    public get gameLanguage(): Language {\n        if (this.supportedLanguages.indexOf(Core.configuration.language as Language) === -1) {\n            return Language.EN;\n        } else {\n            return Core.configuration.language as Language;\n        }\n    }\n\n    public get hasFreeSpins(): boolean {\n        return this._hasFreeSpins;\n    }\n    public get hasOldBuyBonusRTPs(): boolean {\n        return this._hasOldBuyBonusRTPs;\n    }\n\n    public get numberOfGameSymbols(): number {\n        return this._numberOfGameSymbols;\n    }\n\n    public get numberOfLines(): number {\n        return this._numberOfLines;\n    }\n\n    get cascadeGame(): boolean {\n        return this._cascadeGame;\n    }\n\n    public get desktopScale(): number {\n        return this._desktopScale;\n    }\n\n    public set desktopScale(value: number) {\n        this._desktopScale = value;\n    }\n\n    public get symbols(): ISymbol[] {\n        return this._symbols;\n    }\n\n    public set symbols(value: ISymbol[]) {\n        this._symbols = value;\n    }\n\n    public get timeSymbolTravelDuration(): number {\n        return this._timeSymbolTravelDuration;\n    }\n\n    public get wildIndex(): number {\n        return this._wildIndex;\n    }\n\n    public get wildForJackpot(): number {\n        return this._wildForJackpot;\n    }\n\n    public get symbolsConfig(): any[] {\n        /* if (!this._calculatedSymbolsConfig) {\n            this._calculatedSymbolsConfig = this._symbolsConfig.map((symbol) => ({\n                ...symbol,\n                winSound: symbol.winSound !== undefined ? symbol.winSound : symbol.name,\n                texture: symbol.texture !== undefined ? symbol.texture : symbol.name + this._symbolTextureExtension,\n            }));\n        }\n\n        return this._calculatedSymbolsConfig; */\n        return this._symbolsConfig;\n    }\n\n    public set symbolsConfig(value: any[]) {\n        this._symbolsConfig = value;\n    }\n\n    public get reelsBoostSymbolsConfig(): any[] {\n        return this._reelsBoostSymbolsConfig;\n    }\n\n    public get lines(): Array<{ cells: number[]; axisY: number }> {\n        return this._lines;\n    }\n\n    public set lines(value: Array<{ cells: number[]; axisY: number }>) {\n        this._lines = value;\n    }\n\n    public set reelsMinimumSpinTime(val: number) {\n        this._reelsMinimumSpinTime = val;\n    }\n\n    public get assets(): Array<IAsset | ISoundAsset> {\n        return this._assets;\n    }\n\n    public get commonAssets(): Array<IAsset | ISoundAsset> {\n        // if (this._uiAssets) {\n        //     return [this._uiAssets, this.soundAssets].concat(this._uiSvgs);\n        // }\n        return [this.soundAssets, ...this._uiSvgs];\n    }\n\n    public get fontAssets(): IAsset[] {\n        return this._fonts;\n    }\n\n    // public set uiAssets(value: IAsset) {\n    //     this._uiAssets = value;\n    // }\n\n    public get uiSvgs(): IAsset[] {\n        return this._uiSvgs;\n    }\n\n    public set uiSvgs(value: IAsset[]) {\n        this._uiSvgs = value;\n    }\n\n    public get freeSpinAssets(): Array<IAsset | ISoundAsset> {\n        return this._freeSpinAssets;\n    }\n\n    public get payTableCoef(): any {\n        return this._payTableCoef;\n    }\n\n    public get videoConfigs(): any[] {\n        return this._videoConfigs;\n    }\n\n    get commonFPS(): number {\n        return this._commonFPS;\n    }\n\n    public get symbolTextureExtension(): string {\n        return this._symbolTextureExtension;\n    }\n\n    public set symbolTextureExtension(value: string) {\n        this._symbolTextureExtension = value;\n    }\n\n    public get tileSize(): number {\n        return this._tileSize;\n    }\n\n    public get supportedLanguages(): Language[] {\n        return this._supportedLanguages;\n    }\n\n    public get componentsConfiguration(): any {\n        return this._componentsConfiguration;\n    }\n\n    public set componentsConfiguration(val: any) {\n        this._componentsConfiguration = val;\n    }\n\n    public get gameTitle(): string {\n        return this._gameTitle;\n    }\n\n    public set gameTitle(title: string) {\n        this._gameTitle = title;\n    }\n\n    public get gameTitleShort(): string {\n        return this._gameTitleShort ?? this._gameTitle;\n    }\n\n    public set gameTitleShort(titleShort: string) {\n        this._gameTitleShort = titleShort;\n    }\n\n    public get vipGameTitle(): string | undefined {\n        return this._vipGameTitle;\n    }\n\n    public set vipGameTitle(title: string) {\n        this._vipGameTitle = title;\n    }\n\n    public get vipGameTitleShort(): string | undefined {\n        return this._vipGameTitleShort;\n    }\n\n    public set vipGameTitleShort(titleShort: string) {\n        this._vipGameTitleShort = titleShort;\n    }\n\n    public set gameLogoPosition(position: PositionObject) {\n        this._gameLogoPosition = new PositionObject(position.positionData, this._gameLogoPosition);\n    }\n\n    public get gameLogoPosition(): PositionObject {\n        return this._gameLogoPosition as PositionObject;\n    }\n\n    public get mainPanelSideGraphicsConfig(): any {\n        return this._mainPanelSideGraphicsConfig;\n    }\n\n    public set mainPanelSideGraphicsConfig(settings: any) {\n        this._mainPanelSideGraphicsConfig.width = settings.width;\n        this._mainPanelSideGraphicsConfig.leftGraphicPosition = settings.leftGraphicPosition;\n        this._mainPanelSideGraphicsConfig.rightGraphicPosition = settings.rightGraphicPosition;\n    }\n\n    public get stageOptions(): IStageOptions {\n        return this._stageOptions;\n    }\n\n    // public get doubleChanceFactorIndex(): number {\n    //     return this._doubleChanceFactorIndex;\n    // }\n\n    public get buyBonusGameMode(): string {\n        return this._buyBonusGameMode;\n    }\n\n    public get superBuyBonusGameMode(): string {\n        return this._superBuyBonusGameMode;\n    }\n    public get megaBuyBonusGameMode(): string {\n        return this._megaBuyBonusGameMode;\n    }\n\n    public get jackpotValueLoadOffset(): number {\n        return this._jackpotValueLoadOffset;\n    }\n\n    public get winThresholds(): number[] {\n        return this._winThresholds;\n    }\n\n    public get winBangupDurations(): number[] {\n        return this._winBangupDurations;\n    }\n\n    public get autoplayBangupDuration(): number {\n        return this._autoplayBangupDuration;\n    }\n\n    public get freeSpinBangupDuration(): number {\n        return this._freeSpinBangupDuration;\n    }\n\n    public get bellLinkBangupDuration(): number {\n        return this._bellLinkBangupDuration;\n    }\n\n    public get collectBangupDuration(): number {\n        return this._collectBangupDuration;\n    }\n\n    public get gameFeatures(): any[] {\n        return this._gameFeatures;\n    }\n\n    public set gameFeatures(features: any[]) {\n        this._gameFeatures = features;\n    }\n\n    public get overrideSvgs(): IAsset[] {\n        return this._overrideSvgs;\n    }\n\n    public get helpAssetsFolder(): string {\n        return this._helpAssetsFolder;\n    }\n\n    public get setCloneGameKeyForHelpAssets(): boolean {\n        return this._setCloneGameKeyForHelpAssets;\n    }\n\n    // public get normalFactorIndex(): number {\n    //     return this._normalFactorIndex;\n    // }\n\n    get symbolsVideosConfig(): any[] {\n        return this._symbolsVideosConfig;\n    }\n\n    set symbolsVideosConfig(value: any[]) {\n        this._symbolsVideosConfig = value;\n    }\n\n    set cloneGameKey(val: string) {\n        this._cloneGameKey = val;\n    }\n\n    set brandingGameKey(val: string) {\n        this._brandingGameKey = val;\n    }\n\n    get noTintedSymbols(): any[] {\n        return this._noTintedSymbols;\n    }\n\n    set noTintedSymbols(value: any[]) {\n        this._noTintedSymbols = value;\n    }\n\n    get retriggerPopup(): { overlay: { color: number; opacity: number } } {\n        return this._retriggerPopup;\n    }\n\n    get scattersConfig(): any[] {\n        return this._scattersConfig;\n    }\n    public get scattersIds(): number[] {\n        return this._symbolsConfig.reduce((acc, symbol) => {\n            if (symbol.isScatter) {\n                acc.push(symbol.index);\n            }\n            return acc;\n        }, []);\n    }\n\n    set scattersConfig(value: any[]) {\n        this._scattersConfig = value;\n    }\n    get autoplayDelayOnNonWiningSpin(): number {\n        return this._autoplayDelayOnNonWiningSpin;\n    }\n    set autoplayDelayOnNonWiningSpin(value: number) {\n        this._autoplayDelayOnNonWiningSpin = value;\n    }\n    get freespinSpine(): boolean {\n        return this._freespinSpine;\n    }\n\n    set freespinSpine(value: boolean) {\n        this._freespinSpine = value;\n    }\n    get freespinSpineDesktop(): boolean {\n        return this._freespinSpineDesktop;\n    }\n\n    set freespinSpineDesktop(value: boolean) {\n        this._freespinSpineDesktop = value;\n    }\n\n    get backgroundSoundsGroup(): string[] {\n        return this._backgroundSoundsGroup;\n    }\n\n    set backgroundSoundsGroup(value: string[]) {\n        this._backgroundSoundsGroup = value;\n    }\n\n    get freespinElements(): boolean {\n        return this._freespinElements;\n    }\n\n    set freespinElements(value: boolean) {\n        this._freespinElements = value;\n    }\n\n    get respinElements(): boolean {\n        return this._respinElements;\n    }\n\n    set respinElements(value: boolean) {\n        this._respinElements = value;\n    }\n\n    get coinFeatureCoef(): number[] {\n        return this._coinFeatureCoef;\n    }\n\n    get coinFeatureCoefBuyBonus(): number[] {\n        return this._coinFeatureCoefBuyBonus ?? this._coinFeatureCoef;\n    }\n\n    get buyBonusThresholdGameModes(): string[] {\n        return this._buyBonusThresholdGameModes;\n    }\n\n    get bellLinkCoinFeatureCoef(): number {\n        return this._bellLinkCoinFeatureCoef;\n    }\n\n    get initialReels(): number[][] | null {\n        return this._initialReels;\n    }\n\n    get waitBetweenMessages(): number {\n        return this._waitBetweenMessages;\n    }\n\n    get autoplayWinTime(): number {\n        return this._autoplayWinTime;\n    }\n\n    get autoplayWinQuickTime(): number {\n        return this._autoplayWinQuickTime;\n    }\n\n    get autoplayWinTurboTime(): number {\n        return this._autoplayWinTurboTime;\n    }\n\n    get autoplayWinCoinFeatureTime(): number {\n        return this._autoplayWinCoinFeatureTime;\n    }\n\n    get autoplayWinBigWinTime(): number {\n        return this._autoplayWinBigWinTime;\n    }\n\n    get tournaments(): any {\n        // THIS DOESNOT WORKING. IT IS WORKING WITH ITERATE CHILDS\n        // Object.assign(this._tournamentsDefault, this._tournaments)\n        Object.keys(this._tournamentsDefault).forEach((key) => {\n            if (this._tournaments.hasOwnProperty(key)) {\n                this._tournamentsDefault[key] = Object.assign(this._tournamentsDefault[key], this._tournaments[key]);\n            }\n        });\n        return this._tournamentsDefault;\n    }\n\n    set tournaments(data) {\n        this._tournaments = data;\n    }\n\n    // tslint:disable-next-line: adjacent-overload-signatures\n    get cloneGameKey(): string {\n        return this._cloneGameKey;\n    }\n\n    get brandingGameKey(): string {\n        return this._brandingGameKey;\n    }\n\n    get denomButtonStyles(): IDenomButtonStyle {\n        if (Core.isDesktopMode) {\n            return this._denomButtonStylesDesktop;\n        } else {\n            return this._denomButtonStyles;\n        }\n    }\n\n    public get backgroundAnimationShouldPauseOnGamePause(): boolean {\n        return this._backgroundAnimationShouldPauseOnGamePause;\n    }\n}\n","import { AutoplayPopupModes } from '@egt/autoplay-popup';\nimport { BetButtonsModes } from '@egt/bet-buttons';\nimport { BetCalculatorModes } from '@egt/bet-calculator';\nimport { ClockModes } from '@egt/clock';\nimport { BackgroundModes } from '@egt/components/slot/background';\nimport Core, { FeatureFlags, ISlotTemplateConstructorProps } from '@egt/core';\nimport { DenominationPopupModes } from '@egt/denomination-popup';\nimport { FooterBackgroundModes } from '@egt/footer-background';\nimport { GambleModes } from '@egt/gamble';\nimport { HomeButtonModes } from '@egt/home-button';\nimport { LinesModes } from '@egt/lines';\nimport { UIMainPanelModes } from '@egt/ui-main-panel';\nimport { UIViewModes } from '@egt/ui-view';\nimport { VideosModes } from '@egt/videos';\nimport { injectable } from 'tsyringe';\nimport SlotGameLayouts from '../SlotGameLayouts';\nimport SlotComponents from '../components/enums/SlotComponents';\nimport Features from '../components/feature/Features';\nimport SingleProgressiveAutoplayPopupComponentConfigurationFactoryDefault from '../configurations/single-progressive/SingleProgressiveAutoplayPopupComponentConfigurationDefault';\nimport SingleProgressiveAutoplayPopupComponentConfigurationFactoryExtended from '../configurations/single-progressive/SingleProgressiveAutoplayPopupComponentConfigurationExtended';\nimport SingleProgressiveAutoplayPopupComponentConfigurationFactoryNumeric from '../configurations/single-progressive/SingleProgressiveAutoplayPopupComponentConfigurationNumeric';\nimport SingleProgressiveBetButtonsComponentConfigurationFactoryDefault from '../configurations/single-progressive/SingleProgressiveBetButtonsComponentConfigurationDefault';\nimport SingleProgressiveBetButtonsComponentConfigurationFactoryOneDenom from '../configurations/single-progressive/SingleProgressiveBetButtonsComponentConfigurationOneDenom';\nimport SingleProgressiveBetCalculatorComponentConfigurationFactoryDefault from '../configurations/single-progressive/SingleProgressiveBetCalculatorComponentConfigurationDefault';\nimport SingleProgressiveClockComponentConfigurationFactoryDefault from '../configurations/single-progressive/SingleProgressiveClockComponentConfigurationDefault';\nimport SingleProgressiveDenominationPopupComponentConfigurationFactoryExtended from '../configurations/single-progressive/SingleProgressiveDenominationPopupComponentConfigurationExtended';\nimport SingleProgressiveMessageBarComponentConfigurationFactory from '../configurations/single-progressive/SingleProgressiveMessageBarComponentConfiguration';\nimport SingleProgressiveSettingsPopupComponentConfigurationFactory from '../configurations/single-progressive/SingleProgressiveSettingsPopupComponentConfiguration';\nimport SingleProgressiveTitleComponentConfigurationFactory from '../configurations/single-progressive/SingleProgressiveTitleComponentConfiguration';\nimport SingleProgressiveUIMainPanelComponentConfigurationFactoryDefault from '../configurations/single-progressive/SingleProgressiveUIMainPanelComponentConfigurationDefault';\nimport SingleProgressiveGambleFeatureConfigurationFactoryDefault from '../override-feature-configurations/single-progressive/SingleProgressiveGambleFeatureConfigurationFactoryDefault';\nimport SlotTemplate, { getComponentModeByLayout, getFeatureModeByLayout } from './SlotTemplate';\n@injectable()\nexport default class SingleProgressiveTemplate extends SlotTemplate {\n    constructor(\n        templateOverrides: ISlotTemplateConstructorProps = {},\n        layout: SlotGameLayouts = SlotGameLayouts.EXTENDED,\n    ) {\n        const isPrizePopsEnabled = Core.flags.isActive(FeatureFlags.ALLOW_PRIZE_POPS);\n\n        super(\n            {\n                components: [\n                    // [SlotComponents.UI_MAIN_PANEL],\n                    [\n                        SlotComponents.UI_MAIN_PANEL,\n                        {\n                            modeType: UIMainPanelModes.DEFAULT,\n                            configuration: {\n                                [UIMainPanelModes.DEFAULT]:\n                                    SingleProgressiveUIMainPanelComponentConfigurationFactoryDefault,\n                            },\n                        },\n                    ],\n                    [SlotComponents.FOOTER_BACKGROUND, { modeType: FooterBackgroundModes.DEFAULT }],\n                    [SlotComponents.PORTRAIT_GRADIENT],\n                    [SlotComponents.UI_VIEW, { modeType: UIViewModes.DEFAULT }],\n                    [\n                        SlotComponents.CLOCK,\n                        {\n                            modeType: ClockModes.DEFAULT,\n                            configuration: {\n                                [ClockModes.DEFAULT]: SingleProgressiveClockComponentConfigurationFactoryDefault,\n                            },\n                        },\n                    ],\n                    [SlotComponents.REELS],\n                    [SlotComponents.REELS_OVERLAY],\n                    [SlotComponents.MESSAGE_BAR, SingleProgressiveMessageBarComponentConfigurationFactory],\n                    [SlotComponents.MESSAGE_ALERT],\n                    [SlotComponents.MATCH_ID],\n                    // [SlotComponents.AUTOPLAY_POPUP, SingleProgressiveAutoplayPopupComponentConfigurationFactory],\n                    // [SlotComponents.DENOMINATION_POPUP],\n                    // [SlotComponents.BET_CALCULATOR, SingleProgressiveBetCalculatorComponentConfigurationFactory],\n                    [\n                        SlotComponents.BET_CALCULATOR,\n                        {\n                            configuration: {\n                                [BetCalculatorModes.DEFAULT]:\n                                    SingleProgressiveBetCalculatorComponentConfigurationFactoryDefault,\n                            },\n                            modeType: BetCalculatorModes.DEFAULT,\n                        },\n                    ],\n                    // [\n                    //     SlotComponents.AUTOPLAY_NUMERIC_INPUT_POPUP,\n                    //     SingleProgressiveAutoplayPopupComponentConfigurationFactoryNumeric,\n                    // ],\n                    // [\n                    //     SlotComponents.EXTENDED_AUTOPLAY_POPUP,\n                    //     SingleProgressiveAutoplayPopupComponentConfigurationFactoryExtended,\n                    // ],\n                    [\n                        SlotComponents.AUTOPLAY_POPUP,\n                        {\n                            configuration: {\n                                [AutoplayPopupModes.DEFAULT]:\n                                    SingleProgressiveAutoplayPopupComponentConfigurationFactoryDefault,\n                                [AutoplayPopupModes.EXTENDED]:\n                                    SingleProgressiveAutoplayPopupComponentConfigurationFactoryExtended,\n                                [AutoplayPopupModes.NUMERIC]:\n                                    SingleProgressiveAutoplayPopupComponentConfigurationFactoryNumeric,\n                            },\n                            modeType: getComponentModeByLayout(SlotComponents.AUTOPLAY_POPUP, layout),\n                        },\n                    ],\n                    // [\n                    //     SlotComponents.EXTENDED_DENOMINATION_POPUP,\n                    //     SingleProgressiveDenominationPopupComponentConfigurationFactoryExtended,\n                    // ],\n                    [\n                        SlotComponents.DENOMINATION_POPUP,\n                        {\n                            // TODO: When TURTLE is supported, we need to add a new configuration for MAX_BET mode\n                            // with 'public useNonLinearBetTitles = true', and mirror it in the SETTINGS_POPUP\n                            // config's helpViewProps.useNonLinearBetTitles - ON-144659.\n                            configuration: {\n                                [DenominationPopupModes.EXTENDED]:\n                                    SingleProgressiveDenominationPopupComponentConfigurationFactoryExtended,\n                            },\n                            modeType: getComponentModeByLayout(SlotComponents.DENOMINATION_POPUP, layout),\n                        },\n                    ],\n                    [SlotComponents.SETTINGS_POPUP, SingleProgressiveSettingsPopupComponentConfigurationFactory],\n                    [SlotComponents.GAME_LOGO],\n                    // [SlotComponents.DEMO_MODE],\n                    [SlotComponents.MODAL_LAYER],\n                    [SlotComponents.GAME_TITLE, SingleProgressiveTitleComponentConfigurationFactory],\n                    [SlotComponents.LINE_BUTTON],\n                    // [SlotComponents.BACKGROUND],\n                    [SlotComponents.BACKGROUND, { modeType: BackgroundModes.DEFAULT }],\n                    [SlotComponents.STAGE_MASK],\n                    // [SlotComponents.BET_BUTTONS, SingleProgressiveBetButtonsComponentConfigurationFactory],\n                    [\n                        SlotComponents.BET_BUTTONS,\n                        {\n                            configuration: {\n                                [BetButtonsModes.DEFAULT]:\n                                    SingleProgressiveBetButtonsComponentConfigurationFactoryDefault,\n                                [BetButtonsModes.ONE_DENOM]:\n                                    SingleProgressiveBetButtonsComponentConfigurationFactoryOneDenom,\n                            },\n                            modeType: getComponentModeByLayout(SlotComponents.BET_BUTTONS, layout),\n                        },\n                    ],\n                    [SlotComponents.HOME_BUTTON, { modeType: HomeButtonModes.DEFAULT }],\n                    [SlotComponents.STAGE_BLOCKER],\n                ],\n                gameFeatures: [\n                    [Features.VIDEOS, { modeType: VideosModes.DEFAULT }],\n                    [Features.LINES, { modeType: LinesModes.DEFAULT }],\n                ],\n                externalFeatures: [\n                    [\n                        Features.GAMBLE,\n                        {\n                            modeType: getFeatureModeByLayout(Features.GAMBLE, layout),\n                            configuration: {\n                                [GambleModes.DEFAULT]: SingleProgressiveGambleFeatureConfigurationFactoryDefault,\n                            },\n                        },\n                    ],\n                    [Features.GIFT_SPINS],\n                    [Features.MAX_WIN_LIMIT],\n                    [Features.TOURNAMENTS],\n                    ...(isPrizePopsEnabled ? [[Features.PRIZE_POPS]] : []),\n                    [Features.REPLAYER],\n                ],\n            },\n            layout,\n            templateOverrides,\n        );\n    }\n}\n","import { AutoplayPopupModes } from '@egt/autoplay-popup';\nimport { BackgroundModes } from '@egt/background';\nimport { BetCalculatorModes } from '@egt/bet-calculator';\nimport Core, { BaseTemplate, ISlotTemplateConstructorProps, ITemplate, FeatureFlags } from '@egt/core';\nimport { DenominationPopupModes } from '@egt/denomination-popup';\nimport { FooterBackgroundModes } from '@egt/footer-background';\nimport { GambleModes } from '@egt/gamble';\nimport { HomeButtonModes } from '@egt/home-button';\nimport { pipe } from '@egt/ui-lib';\nimport { UIMainPanelModes } from '@egt/ui-main-panel';\nimport { UIViewModes } from '@egt/ui-view';\nimport { BetButtonsModes } from 'components/slot/bet-buttons/src/egt/BetButtonsModeFactory';\nimport { DependencyContainer } from 'tsyringe';\nimport SlotGameLayouts from '../SlotGameLayouts';\nimport SlotComponents from '../components/enums/SlotComponents';\nimport Features from '../components/feature/Features';\nimport { FreeSpinModes } from '@egt/features/slot/free-spins';\nimport { BackgroundAnimationModes } from '@egt/bg-animation';\n\nexport default class SlotTemplate extends BaseTemplate implements ITemplate {\n    public featuresMap: Map<Features, any> = new Map<Features, any>();\n    protected componentsMap: Map<SlotComponents, any> = new Map<SlotComponents, any>();\n    protected defaultTemplateComponents;\n\n    protected defaultTemplateFeatures: any[];\n    protected externalTemplateFeatures: any[];\n\n    constructor(\n        template: ISlotTemplateConstructorProps,\n        layout: string,\n        templateOverrides?: ISlotTemplateConstructorProps,\n    ) {\n        super();\n        Core.gameLayout = layout;\n        const mergedTemplate = this.mergeTemplates(template, templateOverrides);\n        const { components, gameFeatures = [], externalFeatures = [] } = mergedTemplate;\n        this.defaultTemplateComponents = components;\n        this.defaultTemplateFeatures = gameFeatures;\n        this.externalTemplateFeatures = externalFeatures;\n\n        this.downloadComponentConfiguration();\n        this.setComponentsMap(this.defaultTemplateComponents);\n        this.setFeaturesMap(this.defaultTemplateFeatures.concat(this.externalTemplateFeatures));\n        this.componentsRestrictions();\n    }\n\n    public downloadComponentConfiguration(): void {\n        if (Core.configuration.devTools) {\n            // @ts-ignore\n            // Core.game.components = Core.game.components.concat(new DownloadComponent());\n            this.defaultTemplateComponents.push([SlotComponents.DOWNLOAD]);\n        }\n    }\n\n    public componentsRestrictions(): void {\n        Core.flags.all?.forEach((flag) => {\n            if (flag.isActive && flag?.removeComponents) {\n                this.removeComponents([flag.removeComponents]);\n            }\n        });\n    }\n\n    public mergeTemplates(\n        mainTemplate: ISlotTemplateConstructorProps,\n        templateOverrides?: ISlotTemplateConstructorProps,\n    ): ISlotTemplateConstructorProps {\n        return ['components', 'gameFeatures', 'externalFeatures'].reduce<ISlotTemplateConstructorProps>((acc, curr) => {\n            const templateArray = mainTemplate?.[curr] || [];\n            const currentOverride = templateOverrides?.[curr] || [];\n            const notIncluded =\n                currentOverride.filter(\n                    (mod) => templateArray.findIndex((additionalMod) => additionalMod[0] === mod[0]) === -1,\n                ) || [];\n\n            acc[curr] = templateArray\n                .map((templateArr: any[]) => {\n                    const overridedTemplate: [Features, any] = currentOverride.find(\n                        (o) => o && o[0] === templateArr[0],\n                    );\n                    if (overridedTemplate) {\n                        if (overridedTemplate[1] && templateArr[1]) {\n                            // TODO: delete this typecheck when all configs are merged\n                            if (typeof overridedTemplate[1] === 'function' && typeof templateArr[1] === 'function') {\n                                overridedTemplate[1] = pipe(templateArr[1], overridedTemplate[1]);\n                            }\n                            if (\n                                typeof overridedTemplate[1]?.configuration === 'function' &&\n                                typeof templateArr[1]?.configuration === 'function'\n                            ) {\n                                overridedTemplate[1].configuration = pipe(\n                                    templateArr[1].configuration,\n                                    overridedTemplate[1].configuration,\n                                );\n                            }\n\n                            if (typeof overridedTemplate[1] !== 'function') {\n                                // console.log('configuration for component: ', overridedTemplate[0]);\n                                // console.log('component mode: ', overridedTemplate[1]?.modeType);\n                                const templateComponentConfiguration = templateArr[1];\n                                const gameComponentConfiguration = overridedTemplate[1];\n                                //  default, blurred, numeric etc.\n                                const mode = gameComponentConfiguration.modeType;\n\n                                if (mode) {\n                                    const propsToOverride = [\n                                        'view',\n                                        'desktopView',\n                                        'secondView',\n                                        'controller',\n                                        'secondController',\n                                        'desktopController',\n                                    ] as const;\n\n                                    propsToOverride.forEach((prop) => {\n                                        // object -> {default: SomeClass, blurred: SomeClass} or undefined\n                                        const gamePropConfigObject = gameComponentConfiguration[prop];\n                                        const templatePropConfigObject = templateComponentConfiguration[prop];\n                                        if (!gamePropConfigObject && !templatePropConfigObject) return;\n\n                                        // the game is overriding the template( pass controller or view for running mode)\n                                        if (gamePropConfigObject?.[mode]) return;\n                                        // game dose`t have dedicated class for this mode but template have\n                                        if (templatePropConfigObject?.[mode]) {\n                                            if (!gameComponentConfiguration[prop]) {\n                                                gameComponentConfiguration[prop] = {} as any;\n                                            }\n                                            gameComponentConfiguration[prop][mode] = templatePropConfigObject?.[mode];\n                                        }\n                                    });\n                                }\n                                // merge sub configs look up IModeConfig\n                                for (const configKey of ['configuration', 'secondConfiguration'] as const) {\n                                    const templateConfig = templateComponentConfiguration[configKey];\n                                    const gameConfig = gameComponentConfiguration[configKey];\n\n                                    if (!gameConfig && templateConfig) {\n                                        gameComponentConfiguration[configKey] = templateConfig;\n                                        continue;\n                                    }\n\n                                    if (mode && templateConfig && gameConfig) {\n                                        if (!gameConfig[mode] && templateConfig[mode]) {\n                                            gameConfig[mode] = templateConfig[mode];\n                                        } else if (\n                                            typeof gameConfig[mode] === 'function' &&\n                                            typeof templateConfig[mode] === 'function'\n                                        ) {\n                                            gameConfig[mode] = pipe(templateConfig[mode], gameConfig[mode]);\n                                        }\n                                    }\n                                }\n                            }\n\n                            // if (overridedTemplate[1]?.configuration) {\n                            //     if (\n                            //         overridedTemplate[1]?.modeType &&\n                            //         !overridedTemplate[1]?.configuration?.[overridedTemplate[1]?.modeType] &&\n                            //         templateArr[1]?.configuration[overridedTemplate[1]?.modeType]\n                            //     ) {\n                            //         overridedTemplate[1].configuration[overridedTemplate[1].modeType] =\n                            //             templateArr[1].configuration[overridedTemplate[1].modeType];\n                            //     }\n                            //     if (\n                            //         typeof overridedTemplate[1]?.configuration?.[overridedTemplate[1]?.modeType] ===\n                            //             'function' &&\n                            //         typeof templateArr[1]?.configuration?.[overridedTemplate[1]?.modeType] ===\n                            //             'function'\n                            //     ) {\n                            //         overridedTemplate[1].configuration[overridedTemplate[1].modeType] = pipe(\n                            //             templateArr[1].configuration[overridedTemplate[1].modeType],\n                            //             overridedTemplate[1].configuration[overridedTemplate[1].modeType],\n                            //         );\n                            //     }\n                            // }\n                            // if (!overridedTemplate[1]?.configuration && templateArr[1]?.configuration) {\n                            //     overridedTemplate[1].configuration = templateArr[1].configuration;\n                            // }\n                        }\n                        return overridedTemplate;\n                    }\n                    return templateArr;\n                })\n                .concat(notIncluded);\n            return acc;\n        }, {});\n    }\n    public removeComponents(components: any[]): void {\n        for (const component of components) {\n            component.forEach((c) => {\n                this.componentsMap.delete(c);\n            });\n        }\n    }\n\n    public getTemplateComponents(): any[] {\n        const components: any[] = [];\n        this.componentsMap.forEach((value, key) => {\n            components.push([key].concat(value));\n        });\n        return components;\n    }\n\n    public getTemplateGameFeatures(): any[] {\n        const features: any[] = [];\n        this.featuresMap.forEach((value, key) => {\n            if (this.defaultTemplateFeatures.find((dtf) => dtf[0] === key)) {\n                features.push([key].concat(value));\n            }\n        });\n        return features;\n    }\n\n    public getTemplateExternalFeatures(): any[] {\n        const features: any[] = [];\n        this.featuresMap.forEach((value, key) => {\n            if (this.externalTemplateFeatures.find((etf) => etf[0] === key)) {\n                features.push([key].concat(value));\n            }\n        });\n        return this.externalTemplateFeatures;\n    }\n\n    public updateComponents(components: any[]): void {\n        for (const component of components) {\n            if (component.length > 1) {\n                if (this.componentsMap.has(component[0])) {\n                    this.setComponentsMap([component]);\n                }\n            } else {\n                if (this.componentsMap.has(component)) {\n                    this.setComponentsMap([component]);\n                }\n            }\n        }\n    }\n\n    public updateGameFeatures(features: any[]): void {\n        for (const feature of features) {\n            const gameFeatureIndex = this.defaultTemplateFeatures.findIndex((f) => f[0] === feature[0]);\n            if (gameFeatureIndex === -1) {\n                this.defaultTemplateFeatures.push(feature);\n            } else {\n                this.defaultTemplateFeatures[gameFeatureIndex] = feature;\n            }\n        }\n        this.setFeaturesMap(features);\n    }\n\n    public addExternalFeatures(features: any[]): void {\n        const externalFeatures: any[] = [];\n        for (const feature of features) {\n            const externalTemplateFeature = this.externalTemplateFeatures.find((f) => f[0] === feature);\n            externalFeatures.push(externalTemplateFeature || [feature]);\n        }\n        this.setFeaturesMap(externalFeatures);\n    }\n\n    public updateExternalFeatures(features: any[]): void {\n        for (const feature of features) {\n            if (this.featuresMap.has(feature[0])) {\n                if (feature.length > 1) {\n                    const params: any[] = [];\n                    for (let i: number = 1; i < feature.length; i++) {\n                        params.push(feature[i]);\n                    }\n                    this.featuresMap.set(feature[0], params);\n                } else {\n                    this.featuresMap.set(feature[0], undefined);\n                }\n\n                const localExternalTemplateFeature = this.externalTemplateFeatures.findIndex(\n                    (f) => f[0] === feature[0],\n                );\n                if (localExternalTemplateFeature !== -1) {\n                    this.externalTemplateFeatures[localExternalTemplateFeature] = feature;\n                } else {\n                    this.externalTemplateFeatures.push(feature);\n                }\n            }\n        }\n    }\n\n    public destroy(): void {\n        this.defaultTemplateFeatures = [];\n        this.externalTemplateFeatures = [];\n\n        // @ts-ignore\n        this.defaultTemplateFeatures = null;\n        // @ts-ignore\n        this.externalTemplateFeatures = null;\n\n        super.destroy();\n    }\n\n    public removeFeatures(features: any[]): void {\n        for (const feature of features) {\n            this.featuresMap.delete(feature[0]);\n        }\n    }\n\n    public extendComponents(components: any[]): void {\n        for (const component of components) {\n            if (this.componentsMap.has(component[0]) && component.length > 1) {\n                const originalComponent = this.componentsMap.get(component[0]);\n                if (originalComponent && originalComponent[0]) {\n                    if (typeof originalComponent[0] === 'function' && typeof component[1] === 'function') {\n                        originalComponent[0] = pipe(originalComponent[0], component[1]);\n                        continue;\n                    }\n\n                    if (originalComponent[0].modeType) {\n                        if (!originalComponent[0].configuration) {\n                            originalComponent[0].configuration = {};\n                        }\n                        if (!originalComponent[0].configuration?.[originalComponent[0].modeType]) {\n                            originalComponent[0].configuration[originalComponent[0].modeType] = (a) => a;\n                        }\n                    }\n\n                    if (typeof originalComponent[0].configuration?.[originalComponent[0].modeType] === 'function') {\n                        if (typeof component[1] === 'function') {\n                            originalComponent[0].configuration[originalComponent[0].modeType] = pipe(\n                                originalComponent[0].configuration[originalComponent[0].modeType],\n                                component[1],\n                            );\n                        } else if (typeof component[1].configuration?.[component[1].modeType] === 'function') {\n                            originalComponent[0].configuration[originalComponent[0].modeType] = pipe(\n                                originalComponent[0].configuration[originalComponent[0].modeType],\n                                component[1].configuration[component[1].modeType],\n                            );\n                        }\n                    }\n                } else {\n                    this.setComponentsMap([component]);\n                }\n            }\n        }\n    }\n\n    public setComponentsMap(components: any[]): void {\n        for (const component of components) {\n            if (component.length > 1) {\n                // this.componentsMap.set(component[0], component[1]);\n                const params: any[] = [];\n                for (let i: number = 1; i < component.length; i++) {\n                    params.push(component[i]);\n                }\n                this.componentsMap.set(component[0], params);\n            } else {\n                this.componentsMap.set(component[0], undefined);\n            }\n        }\n    }\n\n    public hasComponentWithActiveModeType(componentType: SlotComponents, modeType: any): boolean {\n        const component = this.getTemplateComponents().find((c) => c[0] === componentType);\n        if (!component) return false;\n\n        const componentMode = component[1]?.modeType ? component[1].modeType : 'default';\n\n        if (componentMode === modeType) {\n            return true;\n        }\n\n        return false;\n    }\n\n    protected setFeaturesMap(features: any[]): void {\n        for (const feature of features) {\n            if (feature.length > 1) {\n                const params: any[] = [];\n                for (let i: number = 1; i < feature.length; i++) {\n                    params.push(feature[i]);\n                }\n                this.featuresMap.set(feature[0], params);\n            } else {\n                this.featuresMap.set(feature[0], undefined);\n            }\n        }\n    }\n\n    public registerTemplateConfiguration(_dependencyContainer: DependencyContainer): void {\n        _dependencyContainer.register('ITemplateSlotConfiguration', { useValue: { templateOverrideSvgs: [] } });\n    }\n}\n\nexport function getComponentModeByLayout(component: SlotComponents, layout: SlotGameLayouts): string {\n    let mode: string = '';\n    switch (component) {\n        case SlotComponents.AUTOPLAY_POPUP:\n            if (layout === SlotGameLayouts.TURTLE) {\n                mode = AutoplayPopupModes.MAX_BET;\n            } else if (layout === SlotGameLayouts.CLASSIC) {\n                mode = AutoplayPopupModes.DEFAULT;\n            } else if (Core.flags.isActive(FeatureFlags.USE_NUMERIC_AUTOPLAY)) {\n                mode = AutoplayPopupModes.NUMERIC;\n            } else {\n                mode = AutoplayPopupModes.EXTENDED;\n            }\n            break;\n        case SlotComponents.DENOMINATION_POPUP:\n            if (layout === SlotGameLayouts.TURTLE) {\n                mode = DenominationPopupModes.MAX_BET;\n            } else if (layout === SlotGameLayouts.CLASSIC) {\n                mode = DenominationPopupModes.DEFAULT;\n            } else {\n                mode = DenominationPopupModes.EXTENDED;\n            }\n            break;\n        case SlotComponents.UI_VIEW:\n            if (layout === SlotGameLayouts.CLASSIC || layout === SlotGameLayouts.EXTENDED) {\n                mode = UIViewModes.DEFAULT;\n            } else {\n                mode = UIViewModes.TURTLE;\n            }\n            break;\n        case SlotComponents.FOOTER_BACKGROUND:\n            if (layout === SlotGameLayouts.CLASSIC) {\n                mode = FooterBackgroundModes.DEFAULT;\n            } else if (layout === SlotGameLayouts.EXTENDED) {\n                mode = FooterBackgroundModes.SIDED;\n            } else {\n                mode = FooterBackgroundModes.BLURRED;\n            }\n            break;\n        case SlotComponents.UI_MAIN_PANEL:\n            if (layout === SlotGameLayouts.CLASSIC) {\n                mode = UIMainPanelModes.DEFAULT;\n            } else if (layout === SlotGameLayouts.EXTENDED) {\n                mode = UIMainPanelModes.SIDED;\n            } else {\n                mode = UIMainPanelModes.BLURRED;\n            }\n            break;\n        case SlotComponents.BET_CALCULATOR:\n            mode = layout === SlotGameLayouts.TURTLE ? BetCalculatorModes.TURTLE : BetCalculatorModes.DEFAULT;\n            break;\n        case SlotComponents.BACKGROUND:\n            mode = layout === SlotGameLayouts.TURTLE ? BackgroundModes.BLURRED : BackgroundModes.DEFAULT;\n            break;\n        case SlotComponents.BG_ANIMATION:\n            mode =\n                layout === SlotGameLayouts.TURTLE\n                    ? BackgroundAnimationModes.DESKTOP_FOR_LANDSCAPE\n                    : BackgroundAnimationModes.DEFAULT;\n            break;\n        case SlotComponents.HOME_BUTTON:\n            if (layout === SlotGameLayouts.CLASSIC) {\n                mode = HomeButtonModes.DEFAULT;\n            } else if (layout === SlotGameLayouts.EXTENDED) {\n                mode = HomeButtonModes.SIDED;\n            } else {\n                mode = HomeButtonModes.BLURRED;\n            }\n            break;\n        case SlotComponents.BET_BUTTONS:\n            if (layout === SlotGameLayouts.TURTLE) {\n                mode = BetButtonsModes.TURTLE;\n            } else {\n                mode = Core.flags.isActive(FeatureFlags.USE_ONE_DENOM)\n                    ? BetButtonsModes.ONE_DENOM\n                    : BetButtonsModes.DEFAULT;\n            }\n            break;\n    }\n    return mode;\n}\n\nexport function getFeatureModeByLayout(feature: Features, layout: SlotGameLayouts): string {\n    let mode: string = '';\n    switch (feature) {\n        case Features.GAMBLE:\n            if (layout === SlotGameLayouts.TURTLE) {\n                mode = GambleModes.TURTLE;\n            } else {\n                mode = GambleModes.DEFAULT;\n            }\n            break;\n        case Features.BL_JACKPOT:\n            // BlJackpotModes is not imported due to circular dependencies.\n            if (layout === SlotGameLayouts.TURTLE) {\n                mode = 'turtle';\n                //mode = BlJackpotModes.TURTLE;\n            } else {\n                mode = 'default';\n                //mode = BlJackpotModes.DEFAULT;\n            }\n            break;\n        case Features.FREE_SPINS:\n            if (layout === SlotGameLayouts.CLASSIC) {\n                mode = FreeSpinModes.DEFAULT;\n            } else if (layout === SlotGameLayouts.EXTENDED) {\n                mode = FreeSpinModes.DEFAULT;\n            } else {\n                mode = FreeSpinModes.BLURRED;\n            }\n            break;\n    }\n    return mode;\n}\n\nexport function getSlotLayout(\n    serverGameUISetting: string,\n    supportedLayouts: string[],\n    defaultLayout: SlotGameLayouts,\n): SlotGameLayouts {\n    const layoutFromServer: SlotGameLayouts | undefined = serverGameUISetting\n        ? (serverGameUISetting.toUpperCase() as SlotGameLayouts)\n        : undefined;\n\n    const layoutFromUrlParam: SlotGameLayouts | undefined = Core.configuration.layoutType\n        ? (Core.configuration.layoutType.toUpperCase() as SlotGameLayouts)\n        : layoutFromServer;\n\n    if (layoutFromUrlParam && supportedLayouts.includes(layoutFromUrlParam)) {\n        return layoutFromUrlParam;\n    } else {\n        return defaultLayout;\n    }\n}\n","import { inject, injectable, singleton } from 'tsyringe';\nimport Core, { AnalyticsDispatcher } from './Core';\nimport ErrorTypes from './enums/ErrorTypes';\nimport { ICommunication } from './interfaces/ICommunication';\nimport { IConnectable } from './interfaces/IConnectable';\nimport { IErrorData } from './interfaces/IErrorData';\nimport Log from './utils/Log';\n@injectable()\n@singleton()\nexport default class Communication implements ICommunication {\n    private inReconnect: boolean = false;\n    private inVeryLongReconnect: boolean = false;\n    private offlineStartTime: number = 0;\n    private messRecievedTime: number = 0;\n\n    private _startBetTime: number;\n    private _endBetTime: number;\n    private _listOfEventsThatAreNotTracked = ['echo', 'ingress', 'balance', 'jpstats'];\n    /** if we go online after these seconds -  we are sure server will reject reconnection */\n\n    private reconnectInterval: number = 10000;\n\n    constructor(@inject('IConnectable') private socket: IConnectable) {\n        Log.client('Requesting connection with Websocket', this.constructor.name);\n        this.init();\n        window.addEventListener('offline', this.onBrowserOffline.bind(this));\n        window.addEventListener('online', this.onBrowserOnline.bind(this));\n    }\n\n    public init(): void {\n        this.socket.onopen = this.onConnectionOpened.bind(this);\n        this.socket.onmessage = this.onMessageReceived.bind(this);\n        this.socket.onclose = this.onConnectionClosed.bind(this);\n        this.socket.onerror = this.onErrorReceived.bind(this);\n    }\n\n    public destroy(): void {\n        // @ts-ignore\n        delete this.socket.onopen;\n        // @ts-ignore\n        delete this.socket.onmessage;\n        // @ts-ignore\n        delete this.socket.onclose;\n        // @ts-ignore\n        delete this.socket.onerror;\n    }\n\n    public onConnectionOpened(data): void {\n        if (this.inReconnect) {\n            const offlineTime = new Date().getTime() - this.messRecievedTime;\n            if (this.messRecievedTime > 0 && offlineTime > this.reconnectInterval) {\n                this.inVeryLongReconnect = true;\n            }\n            this.offlineStartTime = 0;\n            // do not start reconnect procedure if very long reconnect\n            if (this.inVeryLongReconnect) {\n                const errorData = {} as IErrorData;\n                errorData.code = '1006';\n                errorData.modal = true;\n                errorData.type = ErrorTypes.GAME_LOCK_ERROR;\n                Core.SHOW_ERROR.next(errorData);\n            } else {\n                Core.HIDE_ERROR.next();\n                this.inReconnect = false;\n                Core.ON_CONNECTION_RESTORED.next(data);\n            }\n        } else {\n            Core.ON_CONNECTION_OPENED.next(data);\n        }\n    }\n\n    public onMessageReceived(data): void {\n        this.messRecievedTime = new Date().getTime();\n        this._endBetTime = performance.now();\n\n        const msg = JSON.parse(data.data);\n        if ((window as any).__VRB) { (window as any).__VRB.incoming(msg); }\n        if (msg.event !== 'currentFactor') {\n            Log.server(JSON.stringify(msg), this.constructor.name);\n        }\n\n        if (!this._listOfEventsThatAreNotTracked.includes(msg.event)) {\n            const rt = Math.floor(this._endBetTime - this._startBetTime);\n            AnalyticsDispatcher.sendTimeMetricEvent(msg?.state, msg.event, rt);\n            AnalyticsDispatcher.recordServerResponseTime(rt, msg?.event);\n            // Log.debug(`Response time game:[${Core.configuration.gameKey}] state:[${msg?.state}] event: [${msg.event}]  time: [${rt} ms]` );\n        }\n\n        switch (msg.event) {\n            case 'echo':\n                this.socket.send(data.data);\n                Log.client(msg, this.constructor.name);\n                break;\n            case 'ingress':\n                if (msg.context) {\n                    Core.configuration.tempToken = msg.context.tempToken;\n                } else {\n                    Core.configuration.tempToken = msg.data.token;\n                    Core.ON_SERVER_RESPONSE.next(msg);\n                }\n                // do not return ingress command anymore\n                // this.socket.send(data.data);\n                // Log.client(msg);\n                break;\n            case 'loadGame':\n                if (msg.settings?.reconnectInterval) {\n                    this.reconnectInterval = msg.settings.reconnectInterval;\n                }\n                Core.ON_SERVER_RESPONSE.next(msg);\n                break;\n            // Uncomment below code for testing of jackpot increasement\n            // case 'jpstats':\n            //     if (!(window as any).jpStatIncreasement) {\n            //         (window as any).jpStatIncreasement = 0;\n            //     }\n            //     (window as any).jpStatIncreasement += 3000;\n            //     msg.jackpotStats[0].levelStats.forEach((level) => {\n            //         level.currentValue += (window as any).jpStatIncreasement;\n            //     });\n            case 'collect':\n            case 'balance':\n                Core.ON_SERVER_RESPONSE.next(msg);\n                if (Core.BLITZ_PLAY_OPEN.value) {\n                    Core.BLITZ_PLAY_ON_SERVER_RESPONSE.next(msg);\n                }\n                break;\n            case 'bet':\n                if (Core.BLITZ_PLAY_MODE.value) {\n                    Core.BLITZ_PLAY_ON_SERVER_RESPONSE.next(msg);\n                } else {\n                    Core.ON_SERVER_RESPONSE.next(msg);\n                }\n                break;\n            default:\n                // max win limit hit? set flag before all in Core in order all features can use\n                /* if (msg.game?.state) {\n                    this.rootStore.subjects.MAX_WIN_LIMIT_HIT.value = msg.game?.state?.limitHit === true;\n                } */\n                // Core.ON_SOCKET_MESSAGE.next(msg)\n\n                Core.ON_SERVER_RESPONSE.next(msg);\n        }\n    }\n\n    public onConnectionClosed(data): void {\n        Log.error(data, this.constructor.name, data);\n        // on first drop we recieve 1006, after unsesessful reconnect - 1002 (we skip it)\n        // 3000 is our custom close used for test disconnections\n        const internetDrop = [1006, 1001, 3000].indexOf(data.code) > -1 || (this.inReconnect && data.code === 1002);\n        // Case when connection to socket is not possible at all (wrong URL, server down, etc.)\n        if (!internetDrop && data.code === 1002) {\n            AnalyticsDispatcher.sendErrorEvent(ErrorTypes.SOCKET_ERROR, data.code, data.reason);\n        }\n        if (!this.inReconnect) {\n            if (internetDrop) {\n                if (Core.lobbyStore.defenceCodeReceived) {\n                    // https://jira.egt-digital.com/browse/ON-25198\n                    // The drop is caused by navigating trough the React Lobby with defence code\n                    return;\n                }\n                // TODO: remove skip reconnection for demo mode when task\n                // https://jira.egt-digital.com/browse/ON-5778 is done\n                if (Core.configuration.demo) {\n                    const errorData = {} as IErrorData;\n                    errorData.code = '1006';\n                    errorData.modal = true;\n                    errorData.type = ErrorTypes.GAME_LOCK_ERROR;\n                    Core.SHOW_ERROR.next(errorData);\n                } else {\n                    this.offlineStartTime = new Date().getTime();\n                    const errorData = {} as IErrorData;\n                    errorData.code = 'reconnecting';\n                    errorData.modal = true;\n                    errorData.type = internetDrop ? ErrorTypes.CONNECTION_ERROR : ErrorTypes.GAME_LOCK_ERROR;\n                    Core.SHOW_ERROR.next(errorData);\n                    this.inReconnect = true;\n                }\n            } else if (data.code !== 1002) {\n                const errorData = {} as IErrorData;\n                errorData.code = data.code;\n                errorData.modal = true;\n                errorData.type = internetDrop ? ErrorTypes.CONNECTION_ERROR : ErrorTypes.GAME_LOCK_ERROR;\n                Core.SHOW_ERROR.next(errorData);\n                this.inReconnect = false;\n            }\n        } else {\n            if (data.code !== 1002) {\n                const errorData = {} as IErrorData;\n                errorData.code = data.code.toString();\n                errorData.errorName = 'errorWhileReconnecting';\n                errorData.modal = true;\n                errorData.type = ErrorTypes.GAME_LOCK_ERROR;\n                Core.SHOW_ERROR.next(errorData);\n                this.inReconnect = false;\n                return;\n            }\n        }\n        if (internetDrop && !Core.configuration.demo) {\n            // try after 0.5 seconds to reconnect\n            setTimeout(() => {\n                Log.debug('reconnecting...', this.constructor.name);\n                this.destroy();\n                const offlineTime = new Date().getTime() - this.offlineStartTime;\n                if (this.offlineStartTime > 0 && offlineTime > this.reconnectInterval) {\n                    this.inVeryLongReconnect = true;\n                }\n                if (this.inVeryLongReconnect) {\n                    const errorData = {} as IErrorData;\n                    errorData.code = '1006';\n                    errorData.modal = true;\n                    errorData.type = ErrorTypes.GAME_LOCK_ERROR;\n                    Core.SHOW_ERROR.next(errorData);\n                } else {\n                    this.inReconnect = true;\n                    this.socket = Core.openConnection();\n                    this.init();\n                }\n            }, 500);\n        }\n    }\n\n    public onErrorReceived(data): void {\n        const errorData = {} as IErrorData;\n        errorData.code = data.code;\n        errorData.modal = true;\n        errorData.type = ErrorTypes.GAME_LOCK_ERROR;\n        Core.SHOW_ERROR.next(errorData);\n    }\n\n    public sendMessage(request): void {\n        if ((window as any).__VRB) { (window as any).__VRB.outgoing(request); }\n        const stringRequest = JSON.stringify(request);\n        if (this.inReconnect) {\n            Log.error('Attemt to send while the socket is not open: ' + stringRequest, this.constructor.name, request);\n            return;\n        }\n        AnalyticsDispatcher.sendMessage(request);\n        Core.SEND_MESSAGE_TO_SERVER.next(stringRequest);\n        Log.client(stringRequest, this.constructor.name);\n        this._startBetTime = performance.now();\n        this.socket.send(stringRequest);\n    }\n\n    private onBrowserOffline(event: any): void {\n        Log.error(event, this.constructor.name, event);\n        this.socket.close(3000, 'Browser Offline Disconnection');\n        // For mobile we already in reconnection and this.socket.close does not fired here\n        // in desktop chrome simulate no connection does not close sockets and there was used\n        // this.socket.close(3000, 'Browser Offline Disconnection');\n        // but after reconnection the spin return error 4801 probably because close 3000\n        // if (!this.inReconnect) {\n        //     this.onConnectionClosed({ code: 1006 });\n        //     // this.offlineStartTime = (new Date()).getTime();\n        //     // (Core.connection as SockJS)._transport.ws.close(3000, 'Browser Offline Disconnection');\n        //     // this.socket.close(3000, 'Browser Offline Disconnection');\n        //     // (Core.connection as SockJS)._transport.ws.close(3000, 'Browser Offline Disconnection');\n        // }\n    }\n\n    private onBrowserOnline(_event: any): void {\n        const offlineTime = new Date().getTime() - this.offlineStartTime;\n        if (this.offlineStartTime > 0 && offlineTime > this.reconnectInterval) {\n            this.inVeryLongReconnect = true;\n        }\n        this.offlineStartTime = 0;\n    }\n}\n","// extracted by mini-css-extract-plugin\nexport {};","// extracted by mini-css-extract-plugin\nexport {};","/**\n * @author renhongl\n * @email liangrenhong2017@gmail.com\n * @desc This lib is for render a pretty json data on browser\n */\n\nconst toString = Object.prototype.toString;\n\nfunction isString(val) {\n    return typeof val === 'string';\n}\n\nfunction isNumber(val) {\n    return typeof val === 'number';\n}\n\nfunction isBoolean(val) {\n    return typeof val === 'boolean';\n}\n\nfunction isUndefined(val) {\n    return typeof val === 'undefined';\n}\n\nfunction isArray(val) {\n    return toString.call(val) === '[object Array]';\n}\n\nfunction isObject(val) {\n    return toString.call(val) === '[object Object]';\n}\n\nfunction isNull(val) {\n    return toString.call(val) === '[object Null]';\n}\n\nfunction JsonViewer(options) {\n    const defaults = {\n        theme: 'light',\n        container: null,\n        data: '{}',\n        expand: false,\n    };\n    this.options = Object.assign(defaults, options);\n    if (isNull(options.container)) {\n        throw new Error('Container: dom element is required');\n    }\n    this.render();\n}\n\nJsonViewer.prototype.renderRight = function(theme, right, val) {\n    if (isNumber(val)) {\n        right.setAttribute('class', theme + 'rightNumber');\n    } else if (isBoolean(val)) {\n        right.setAttribute('class', theme + 'rightBoolean');\n    } else if (val === 'null') {\n        right.setAttribute('class', theme + 'rightNull');\n    } else {\n        right.setAttribute('class', theme + 'rightString');\n    }\n    right.innerText = val;\n};\n\nJsonViewer.prototype.renderChildren = function(theme, key, val, right, indent, left) {\n    let self = this;\n    let folder = this.createElement('span');\n    let rotate90 = this.options.expand ? 'rotate90' : '';\n    let addHeight = this.options.expand ? 'add-height' : '';\n    folder.setAttribute('class', theme + 'folder ' + rotate90);\n    folder.onclick = function(e) {\n        let nextSibling = e.target.parentNode.nextSibling;\n        self.toggleItem(nextSibling, e.target);\n    };\n    let len = 0;\n    let isObj = false;\n    if (isObject(val)) {\n        len = Object.keys(val).length;\n        isObj = true;\n    } else {\n        len = val.length;\n    }\n    left.innerHTML = isObj ? key + '&nbsp;&nbsp{' + len + '}' : key + '&nbsp;&nbsp[' + len + ']';\n    left.prepend(folder);\n    right.setAttribute('class', theme + 'rightObj ' + addHeight);\n    self.parse(val, right, indent + 0, theme);\n};\n\nJsonViewer.prototype.parse = function(dataObj, parent, indent, theme) {\n    const self = this;\n    this.forEach(dataObj, function(val, key) {\n        const { left, right } = self.createItem(indent, theme, parent, key, typeof val !== 'object');\n        if (typeof val !== 'object') {\n            self.renderRight(theme, right, val);\n        } else {\n            self.renderChildren(theme, key, val, right, indent, left);\n        }\n    });\n};\n\nJsonViewer.prototype.createItem = function(indent, theme, parent, key, basicType, style) {\n    let self = this;\n    let current = this.createElement('div');\n    let left = this.createElement('div');\n    let right = this.createElement('div');\n    let wrap = this.createElement('div');\n\n    current.style.marginLeft = indent * 2 + 'px';\n    left.innerHTML = `${key}<span class=\"jv-${theme}-symbol\">&nbsp;:&nbsp;</span>`;\n    if (style !== undefined) {\n        left.style = style;\n    }\n\n    if (basicType) {\n        current.appendChild(wrap);\n        wrap.appendChild(left);\n        wrap.appendChild(right);\n        parent.appendChild(current);\n        current.setAttribute('class', theme + 'current');\n        wrap.setAttribute('class', 'jv-wrap');\n        left.setAttribute('class', theme + 'left');\n    } else {\n        current.appendChild(left);\n        current.appendChild(right);\n        parent.appendChild(current);\n        current.setAttribute('class', theme + 'current');\n        left.setAttribute('class', theme + 'left jv-folder');\n        left.onclick = function(e) {\n            let nextSibling = e.target.nextSibling;\n            // self.toggleItem(nextSibling, e.target.querySelector('span'));\n        };\n    }\n\n    return {\n        left,\n        right,\n        current,\n    };\n};\n\nJsonViewer.prototype.render = function() {\n    let data = this.options.data;\n    let theme = 'jv-' + this.options.theme + '-';\n    let indent = 0;\n    let parent = this.options.container;\n    let key = 'gosho';\n    let dataObj;\n    let style;\n\n    parent.setAttribute('class', theme + 'con');\n    try {\n        dataObj = JSON.parse(data);\n    } catch (error) {\n        throw new Error('It is not a json format');\n    }\n    if (isArray(dataObj)) {\n        key = 'array';\n    }\n    key = dataObj.message;\n    style = dataObj.style;\n    dataObj = dataObj.value;\n    const { left, right } = this.createItem(indent, theme, parent, key, undefined, style);\n    this.renderChildren(theme, key, dataObj, right, indent, left);\n};\n\nJsonViewer.prototype.toggleItem = function(ele, target) {\n    ele.classList.toggle('add-height');\n    target.classList.toggle('rotate90');\n};\n\nJsonViewer.prototype.createElement = function(type) {\n    return document.createElement(type);\n};\n\nJsonViewer.prototype.forEach = function(obj, fn) {\n    if (isUndefined(obj) || isNull(obj)) {\n        return;\n    }\n    if (typeof obj === 'object' && isArray(obj)) {\n        for (let i = 0, l = obj.length; i < l; i++) {\n            fn.call(null, obj[i], i, obj);\n        }\n    } else {\n        for (key in obj) {\n            if (obj.hasOwnProperty(key)) {\n                fn.call(null, obj[key] || 'null', key, obj);\n            }\n        }\n    }\n};\n\nmodule.exports = JsonViewer;\n","var map = {\n\t\"./bg.json\": \"./packages/core/src/egt/core/replayer/translations/bg.json\",\n\t\"./cs.json\": \"./packages/core/src/egt/core/replayer/translations/cs.json\",\n\t\"./da.json\": \"./packages/core/src/egt/core/replayer/translations/da.json\",\n\t\"./de.json\": \"./packages/core/src/egt/core/replayer/translations/de.json\",\n\t\"./el.json\": \"./packages/core/src/egt/core/replayer/translations/el.json\",\n\t\"./en.json\": \"./packages/core/src/egt/core/replayer/translations/en.json\",\n\t\"./es.json\": \"./packages/core/src/egt/core/replayer/translations/es.json\",\n\t\"./et.json\": \"./packages/core/src/egt/core/replayer/translations/et.json\",\n\t\"./fr.json\": \"./packages/core/src/egt/core/replayer/translations/fr.json\",\n\t\"./hr.json\": \"./packages/core/src/egt/core/replayer/translations/hr.json\",\n\t\"./hu.json\": \"./packages/core/src/egt/core/replayer/translations/hu.json\",\n\t\"./it.json\": \"./packages/core/src/egt/core/replayer/translations/it.json\",\n\t\"./ka.json\": \"./packages/core/src/egt/core/replayer/translations/ka.json\",\n\t\"./ko.json\": \"./packages/core/src/egt/core/replayer/translations/ko.json\",\n\t\"./lt.json\": \"./packages/core/src/egt/core/replayer/translations/lt.json\",\n\t\"./lv.json\": \"./packages/core/src/egt/core/replayer/translations/lv.json\",\n\t\"./mk.json\": \"./packages/core/src/egt/core/replayer/translations/mk.json\",\n\t\"./nl.json\": \"./packages/core/src/egt/core/replayer/translations/nl.json\",\n\t\"./pl.json\": \"./packages/core/src/egt/core/replayer/translations/pl.json\",\n\t\"./pt-br.json\": \"./packages/core/src/egt/core/replayer/translations/pt-br.json\",\n\t\"./pt.json\": \"./packages/core/src/egt/core/replayer/translations/pt.json\",\n\t\"./ro.json\": \"./packages/core/src/egt/core/replayer/translations/ro.json\",\n\t\"./ru.json\": \"./packages/core/src/egt/core/replayer/translations/ru.json\",\n\t\"./sk.json\": \"./packages/core/src/egt/core/replayer/translations/sk.json\",\n\t\"./sl.json\": \"./packages/core/src/egt/core/replayer/translations/sl.json\",\n\t\"./sq.json\": \"./packages/core/src/egt/core/replayer/translations/sq.json\",\n\t\"./sr.json\": \"./packages/core/src/egt/core/replayer/translations/sr.json\",\n\t\"./sv.json\": \"./packages/core/src/egt/core/replayer/translations/sv.json\",\n\t\"./tr.json\": \"./packages/core/src/egt/core/replayer/translations/tr.json\",\n\t\"./uk.json\": \"./packages/core/src/egt/core/replayer/translations/uk.json\",\n\t\"./zh-cn.json\": \"./packages/core/src/egt/core/replayer/translations/zh-cn.json\"\n};\n\n\nfunction webpackContext(req) {\n\tvar id = webpackContextResolve(req);\n\treturn __webpack_require__(id);\n}\nfunction webpackContextResolve(req) {\n\tif(!__webpack_require__.o(map, req)) {\n\t\tvar e = new Error(\"Cannot find module '\" + req + \"'\");\n\t\te.code = 'MODULE_NOT_FOUND';\n\t\tthrow e;\n\t}\n\treturn map[req];\n}\nwebpackContext.keys = function webpackContextKeys() {\n\treturn Object.keys(map);\n};\nwebpackContext.resolve = webpackContextResolve;\nmodule.exports = webpackContext;\nwebpackContext.id = \"./packages/core/src/egt/core/replayer/translations sync recursive ^\\\\.\\\\/.*\\\\.json$\";","var map = {\n\t\"./errors/bg.json\": \"./packages/core/src/egt/core/errors/bg.json\",\n\t\"./errors/cs.json\": \"./packages/core/src/egt/core/errors/cs.json\",\n\t\"./errors/da.json\": \"./packages/core/src/egt/core/errors/da.json\",\n\t\"./errors/de.json\": \"./packages/core/src/egt/core/errors/de.json\",\n\t\"./errors/el.json\": \"./packages/core/src/egt/core/errors/el.json\",\n\t\"./errors/en.json\": \"./packages/core/src/egt/core/errors/en.json\",\n\t\"./errors/es-co.json\": \"./packages/core/src/egt/core/errors/es-co.json\",\n\t\"./errors/es.json\": \"./packages/core/src/egt/core/errors/es.json\",\n\t\"./errors/et.json\": \"./packages/core/src/egt/core/errors/et.json\",\n\t\"./errors/fr.json\": \"./packages/core/src/egt/core/errors/fr.json\",\n\t\"./errors/hr.json\": \"./packages/core/src/egt/core/errors/hr.json\",\n\t\"./errors/hu.json\": \"./packages/core/src/egt/core/errors/hu.json\",\n\t\"./errors/it.json\": \"./packages/core/src/egt/core/errors/it.json\",\n\t\"./errors/ka.json\": \"./packages/core/src/egt/core/errors/ka.json\",\n\t\"./errors/ko.json\": \"./packages/core/src/egt/core/errors/ko.json\",\n\t\"./errors/lt.json\": \"./packages/core/src/egt/core/errors/lt.json\",\n\t\"./errors/lv.json\": \"./packages/core/src/egt/core/errors/lv.json\",\n\t\"./errors/mk.json\": \"./packages/core/src/egt/core/errors/mk.json\",\n\t\"./errors/nl.json\": \"./packages/core/src/egt/core/errors/nl.json\",\n\t\"./errors/pl.json\": \"./packages/core/src/egt/core/errors/pl.json\",\n\t\"./errors/pt-br.json\": \"./packages/core/src/egt/core/errors/pt-br.json\",\n\t\"./errors/pt.json\": \"./packages/core/src/egt/core/errors/pt.json\",\n\t\"./errors/ro.json\": \"./packages/core/src/egt/core/errors/ro.json\",\n\t\"./errors/ru.json\": \"./packages/core/src/egt/core/errors/ru.json\",\n\t\"./errors/sk.json\": \"./packages/core/src/egt/core/errors/sk.json\",\n\t\"./errors/sl.json\": \"./packages/core/src/egt/core/errors/sl.json\",\n\t\"./errors/sq.json\": \"./packages/core/src/egt/core/errors/sq.json\",\n\t\"./errors/sr.json\": \"./packages/core/src/egt/core/errors/sr.json\",\n\t\"./errors/sv.json\": \"./packages/core/src/egt/core/errors/sv.json\",\n\t\"./errors/tr.json\": \"./packages/core/src/egt/core/errors/tr.json\",\n\t\"./errors/uk.json\": \"./packages/core/src/egt/core/errors/uk.json\",\n\t\"./errors/zh-cn.json\": \"./packages/core/src/egt/core/errors/zh-cn.json\",\n\t\"./replayer/translations/bg.json\": \"./packages/core/src/egt/core/replayer/translations/bg.json\",\n\t\"./replayer/translations/cs.json\": \"./packages/core/src/egt/core/replayer/translations/cs.json\",\n\t\"./replayer/translations/da.json\": \"./packages/core/src/egt/core/replayer/translations/da.json\",\n\t\"./replayer/translations/de.json\": \"./packages/core/src/egt/core/replayer/translations/de.json\",\n\t\"./replayer/translations/el.json\": \"./packages/core/src/egt/core/replayer/translations/el.json\",\n\t\"./replayer/translations/en.json\": \"./packages/core/src/egt/core/replayer/translations/en.json\",\n\t\"./replayer/translations/es.json\": \"./packages/core/src/egt/core/replayer/translations/es.json\",\n\t\"./replayer/translations/et.json\": \"./packages/core/src/egt/core/replayer/translations/et.json\",\n\t\"./replayer/translations/fr.json\": \"./packages/core/src/egt/core/replayer/translations/fr.json\",\n\t\"./replayer/translations/hr.json\": \"./packages/core/src/egt/core/replayer/translations/hr.json\",\n\t\"./replayer/translations/hu.json\": \"./packages/core/src/egt/core/replayer/translations/hu.json\",\n\t\"./replayer/translations/it.json\": \"./packages/core/src/egt/core/replayer/translations/it.json\",\n\t\"./replayer/translations/ka.json\": \"./packages/core/src/egt/core/replayer/translations/ka.json\",\n\t\"./replayer/translations/ko.json\": \"./packages/core/src/egt/core/replayer/translations/ko.json\",\n\t\"./replayer/translations/lt.json\": \"./packages/core/src/egt/core/replayer/translations/lt.json\",\n\t\"./replayer/translations/lv.json\": \"./packages/core/src/egt/core/replayer/translations/lv.json\",\n\t\"./replayer/translations/mk.json\": \"./packages/core/src/egt/core/replayer/translations/mk.json\",\n\t\"./replayer/translations/nl.json\": \"./packages/core/src/egt/core/replayer/translations/nl.json\",\n\t\"./replayer/translations/pl.json\": \"./packages/core/src/egt/core/replayer/translations/pl.json\",\n\t\"./replayer/translations/pt-br.json\": \"./packages/core/src/egt/core/replayer/translations/pt-br.json\",\n\t\"./replayer/translations/pt.json\": \"./packages/core/src/egt/core/replayer/translations/pt.json\",\n\t\"./replayer/translations/ro.json\": \"./packages/core/src/egt/core/replayer/translations/ro.json\",\n\t\"./replayer/translations/ru.json\": \"./packages/core/src/egt/core/replayer/translations/ru.json\",\n\t\"./replayer/translations/sk.json\": \"./packages/core/src/egt/core/replayer/translations/sk.json\",\n\t\"./replayer/translations/sl.json\": \"./packages/core/src/egt/core/replayer/translations/sl.json\",\n\t\"./replayer/translations/sq.json\": \"./packages/core/src/egt/core/replayer/translations/sq.json\",\n\t\"./replayer/translations/sr.json\": \"./packages/core/src/egt/core/replayer/translations/sr.json\",\n\t\"./replayer/translations/sv.json\": \"./packages/core/src/egt/core/replayer/translations/sv.json\",\n\t\"./replayer/translations/tr.json\": \"./packages/core/src/egt/core/replayer/translations/tr.json\",\n\t\"./replayer/translations/uk.json\": \"./packages/core/src/egt/core/replayer/translations/uk.json\",\n\t\"./replayer/translations/zh-cn.json\": \"./packages/core/src/egt/core/replayer/translations/zh-cn.json\"\n};\n\n\nfunction webpackContext(req) {\n\tvar id = webpackContextResolve(req);\n\treturn __webpack_require__(id);\n}\nfunction webpackContextResolve(req) {\n\tif(!__webpack_require__.o(map, req)) {\n\t\tvar e = new Error(\"Cannot find module '\" + req + \"'\");\n\t\te.code = 'MODULE_NOT_FOUND';\n\t\tthrow e;\n\t}\n\treturn map[req];\n}\nwebpackContext.keys = function webpackContextKeys() {\n\treturn Object.keys(map);\n};\nwebpackContext.resolve = webpackContextResolve;\nmodule.exports = webpackContext;\nwebpackContext.id = \"./packages/core/src/egt/core sync recursive ^.*\\\\.json$\";","/* (ignored) */","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\tid: moduleId,\n\t\tloaded: false,\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n\t// Flag the module as loaded\n\tmodule.loaded = true;\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n// expose the modules object (__webpack_modules__)\n__webpack_require__.m = __webpack_modules__;\n\n","var deferred = [];\n__webpack_require__.O = (result, chunkIds, fn, priority) => {\n\tif(chunkIds) {\n\t\tpriority = priority || 0;\n\t\tfor(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1];\n\t\tdeferred[i] = [chunkIds, fn, priority];\n\t\treturn;\n\t}\n\tvar notFulfilled = Infinity;\n\tfor (var i = 0; i < deferred.length; i++) {\n\t\tvar [chunkIds, fn, priority] = deferred[i];\n\t\tvar fulfilled = true;\n\t\tfor (var j = 0; j < chunkIds.length; j++) {\n\t\t\tif ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(__webpack_require__.O).every((key) => (__webpack_require__.O[key](chunkIds[j])))) {\n\t\t\t\tchunkIds.splice(j--, 1);\n\t\t\t} else {\n\t\t\t\tfulfilled = false;\n\t\t\t\tif(priority < notFulfilled) notFulfilled = priority;\n\t\t\t}\n\t\t}\n\t\tif(fulfilled) {\n\t\t\tdeferred.splice(i--, 1)\n\t\t\tvar r = fn();\n\t\t\tif (r !== undefined) result = r;\n\t\t}\n\t}\n\treturn result;\n};","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","var getProto = Object.getPrototypeOf ? (obj) => (Object.getPrototypeOf(obj)) : (obj) => (obj.__proto__);\nvar leafPrototypes;\n// create a fake namespace object\n// mode & 1: value is a module id, require it\n// mode & 2: merge all properties of value into the ns\n// mode & 4: return value when already ns object\n// mode & 16: return value when it's Promise-like\n// mode & 8|1: behave like require\n__webpack_require__.t = function(value, mode) {\n\tif(mode & 1) value = this(value);\n\tif(mode & 8) return value;\n\tif(typeof value === 'object' && value) {\n\t\tif((mode & 4) && value.__esModule) return value;\n\t\tif((mode & 16) && typeof value.then === 'function') return value;\n\t}\n\tvar ns = Object.create(null);\n\t__webpack_require__.r(ns);\n\tvar def = {};\n\tleafPrototypes = leafPrototypes || [null, getProto({}), getProto([]), getProto(getProto)];\n\tfor(var current = mode & 2 && value; typeof current == 'object' && !~leafPrototypes.indexOf(current); current = getProto(current)) {\n\t\tObject.getOwnPropertyNames(current).forEach((key) => (def[key] = () => (value[key])));\n\t}\n\tdef['default'] = () => (value);\n\t__webpack_require__.d(ns, def);\n\treturn ns;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.f = {};\n// This file contains only the entry chunk.\n// The chunk loading function for additional chunks\n__webpack_require__.e = (chunkId) => {\n\treturn Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => {\n\t\t__webpack_require__.f[key](chunkId, promises);\n\t\treturn promises;\n\t}, []));\n};","// This function allow to reference async chunks\n__webpack_require__.u = (chunkId) => {\n\t// return url for filenames based on template\n\treturn \"\" + chunkId + \".chunk.js?hash=\" + __webpack_require__.h() + \"\";\n};","// This function allow to reference async chunks\n__webpack_require__.miniCssF = (chunkId) => {\n\t// return url for filenames based on template\n\treturn \"\" + chunkId + \".css?hash=\" + __webpack_require__.h() + \"\";\n};","__webpack_require__.h = () => (\"e7a96fec4e323778f66f\")","__webpack_require__.g = (function() {\n\tif (typeof globalThis === 'object') return globalThis;\n\ttry {\n\t\treturn this || new Function('return this')();\n\t} catch (e) {\n\t\tif (typeof window === 'object') return window;\n\t}\n})();","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","var inProgress = {};\nvar dataWebpackPrefix = \"game-client-lerna:\";\n// loadScript function to load a script via script tag\n__webpack_require__.l = (url, done, key, chunkId) => {\n\tif(inProgress[url]) { inProgress[url].push(done); return; }\n\tvar script, needAttach;\n\tif(key !== undefined) {\n\t\tvar scripts = document.getElementsByTagName(\"script\");\n\t\tfor(var i = 0; i < scripts.length; i++) {\n\t\t\tvar s = scripts[i];\n\t\t\tif(s.getAttribute(\"src\") == url || s.getAttribute(\"data-webpack\") == dataWebpackPrefix + key) { script = s; break; }\n\t\t}\n\t}\n\tif(!script) {\n\t\tneedAttach = true;\n\t\tscript = document.createElement('script');\n\n\t\tscript.charset = 'utf-8';\n\t\tscript.timeout = 120;\n\t\tif (__webpack_require__.nc) {\n\t\t\tscript.setAttribute(\"nonce\", __webpack_require__.nc);\n\t\t}\n\t\tscript.setAttribute(\"data-webpack\", dataWebpackPrefix + key);\n\t\tscript.src = url;\n\t\tif (script.src.indexOf(window.location.origin + '/') !== 0) {\n\t\t\tscript.crossOrigin = \"anonymous\";\n\t\t}\n\t}\n\tinProgress[url] = [done];\n\tvar onScriptComplete = (prev, event) => {\n\t\t// avoid mem leaks in IE.\n\t\tscript.onerror = script.onload = null;\n\t\tclearTimeout(timeout);\n\t\tvar doneFns = inProgress[url];\n\t\tdelete inProgress[url];\n\t\tscript.parentNode && script.parentNode.removeChild(script);\n\t\tdoneFns && doneFns.forEach((fn) => (fn(event)));\n\t\tif(prev) return prev(event);\n\t};\n\tvar timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000);\n\tscript.onerror = onScriptComplete.bind(null, script.onerror);\n\tscript.onload = onScriptComplete.bind(null, script.onload);\n\tneedAttach && document.head.appendChild(script);\n};","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","__webpack_require__.nmd = (module) => {\n\tmodule.paths = [];\n\tif (!module.children) module.children = [];\n\treturn module;\n};","__webpack_require__.p = \"\";","if (typeof document === \"undefined\") return;\nvar createStylesheet = (chunkId, fullhref, oldTag, resolve, reject) => {\n\tvar linkTag = document.createElement(\"link\");\n\n\tlinkTag.rel = \"stylesheet\";\n\tlinkTag.type = \"text/css\";\n\tvar onLinkComplete = (event) => {\n\t\t// avoid mem leaks.\n\t\tlinkTag.onerror = linkTag.onload = null;\n\t\tif (event.type === 'load') {\n\t\t\tresolve();\n\t\t} else {\n\t\t\tvar errorType = event && (event.type === 'load' ? 'missing' : event.type);\n\t\t\tvar realHref = event && event.target && event.target.href || fullhref;\n\t\t\tvar err = new Error(\"Loading CSS chunk \" + chunkId + \" failed.\\n(\" + realHref + \")\");\n\t\t\terr.code = \"CSS_CHUNK_LOAD_FAILED\";\n\t\t\terr.type = errorType;\n\t\t\terr.request = realHref;\n\t\t\tlinkTag.parentNode.removeChild(linkTag)\n\t\t\treject(err);\n\t\t}\n\t}\n\tlinkTag.onerror = linkTag.onload = onLinkComplete;\n\tlinkTag.href = fullhref;\n\tif (linkTag.href.indexOf(window.location.origin + '/') !== 0) {\n\t\tlinkTag.crossOrigin = \"anonymous\";\n\t}\n\tif (oldTag) {\n\t\toldTag.parentNode.insertBefore(linkTag, oldTag.nextSibling);\n\t} else {\n\t\tdocument.head.appendChild(linkTag);\n\t}\n\treturn linkTag;\n};\nvar findStylesheet = (href, fullhref) => {\n\tvar existingLinkTags = document.getElementsByTagName(\"link\");\n\tfor(var i = 0; i < existingLinkTags.length; i++) {\n\t\tvar tag = existingLinkTags[i];\n\t\tvar dataHref = tag.getAttribute(\"data-href\") || tag.getAttribute(\"href\");\n\t\tif(tag.rel === \"stylesheet\" && (dataHref === href || dataHref === fullhref)) return tag;\n\t}\n\tvar existingStyleTags = document.getElementsByTagName(\"style\");\n\tfor(var i = 0; i < existingStyleTags.length; i++) {\n\t\tvar tag = existingStyleTags[i];\n\t\tvar dataHref = tag.getAttribute(\"data-href\");\n\t\tif(dataHref === href || dataHref === fullhref) return tag;\n\t}\n};\nvar loadStylesheet = (chunkId) => {\n\treturn new Promise((resolve, reject) => {\n\t\tvar href = __webpack_require__.miniCssF(chunkId);\n\t\tvar fullhref = __webpack_require__.p + href;\n\t\tif(findStylesheet(href, fullhref)) return resolve();\n\t\tcreateStylesheet(chunkId, fullhref, null, resolve, reject);\n\t});\n}\n// object to store loaded CSS chunks\nvar installedCssChunks = {\n\t\"index\": 0\n};\n\n__webpack_require__.f.miniCss = (chunkId, promises) => {\n\tvar cssChunks = {\"games/FHEBLBNSlot\":1,\"games/BFHEBLSlot\":1,\"games/TBHSlot\":1,\"games/FRDHSlot\":1,\"games/RSSlot\":1,\"games/EDSlot\":1,\"games/LHSlot\":1,\"games/EPSlot\":1,\"games/ABSlot\":1,\"games/FSHSlot\":1,\"games/TSHSlot\":1,\"features/blitz-play\":1,\"games/TSHPLSlot\":1,\"games/FHSlot\":1,\"games/FSHPLSlot\":1,\"games/BHSlot\":1,\"games/BHPLSlot\":1,\"games/FMCSlot\":1,\"games/SCSlot\":1,\"games/SCPLSlot\":1,\"games/SCDSlot\":1,\"games/FSCSlot\":1,\"games/FBHSlot\":1,\"games/FBHIBSlot\":1,\"games/VNABSlot\":1,\"games/VNSlot\":1,\"games/VNBLSlot\":1,\"games/SACBLSlot\":1,\"games/FHEIAGSlot\":1,\"games/FHESlot\":1,\"games/RORSlot\":1,\"games/RORPLSlot\":1,\"games/BHBLSlot\":1,\"games/FDCSlot\":1,\"games/TNDCSlot\":1,\"games/FDHSlot\":1,\"games/TNDHSlot\":1,\"games/TSHBLSlot\":1,\"games/FSHBLSlot\":1,\"games/FSHBLVKRSlot\":1,\"games/FSCBLSlot\":1,\"games/FSCBLSSlot\":1,\"games/FSCBLMSlot\":1,\"games/SCASlot\":1,\"games/SCSBSlot\":1,\"games/SCWSlot\":1,\"games/FHBLSlot\":1,\"games/FHEBLSlot\":1,\"games/BPFHEBLSlot\":1,\"games/FHEBLALBSlot\":1,\"games/FHEBLAMSlot\":1,\"games/FHEBLMCSlot\":1,\"games/FHEBLSSlot\":1,\"games/FHEBLGBSlot\":1,\"games/FHEBLGRSlot\":1,\"games/FHEBLKSlot\":1,\"games/SCBLSlot\":1,\"games/FDHBLSlot\":1,\"games/FBHBLSlot\":1,\"games/FBHBLVRBSlot\":1,\"games/FBHBLABSlot\":1,\"games/FBHBLLSlot\":1,\"games/FBHBLBBSlot\":1,\"games/DRHCSlot\":1,\"games/PCHCSlot\":1,\"games/LTHCSlot\":1,\"games/MSHCSlot\":1,\"games/FCHJSlot\":1,\"games/VGSlot\":1,\"games/THSFSlot\":1,\"games/TBSlot\":1,\"games/OLHSlot\":1,\"games/TCWSlot\":1,\"games/TWGSlot\":1,\"games/TDHSlot\":1,\"games/TBHRSlot\":1,\"games/FBHRSlot\":1,\"games/MDSlot\":1,\"games/OSHSlot\":1,\"games/BORSlot\":1,\"games/OBHSlot\":1,\"games/FLKSlot\":1,\"games/STSlot\":1,\"games/STHWSASlot\":1,\"games/FHBSlot\":1,\"games/ZWSlot\":1,\"games/BCSlot\":1,\"games/BCBSlot\":1,\"games/TCHSlot\":1,\"games/TCHGRSlot\":1,\"games/TWCHSlot\":1,\"games/TCHJSlot\":1,\"games/TSDSlot\":1,\"games/TSDTWSlot\":1,\"games/TSDTBSlot\":1,\"games/TSPCSlot\":1,\"games/FBHSSlot\":1,\"games/VGSASlot\":1,\"games/VGPLSlot\":1,\"games/TSHSASlot\":1,\"games/FSHSASlot\":1,\"games/FSHGBSlot\":1,\"games/BHSASlot\":1,\"games/BESlot\":1,\"games/RORSASlot\":1,\"games/UHSlot\":1,\"games/UFSlot\":1,\"games/OSFSlot\":1,\"games/OHSRSlot\":1,\"games/OHSHRSlot\":1,\"games/OHSRSSlot\":1,\"games/SRSHRSlot\":1,\"games/FCHSlot\":1,\"games/FRSHRSlot\":1,\"games/OHCHSlot\":1,\"multiplayer\":1,\"games/TBCSlot\":1,\"games/SJSlot\":1,\"games/OBCSlot\":1,\"games/FBCSlot\":1,\"games/FSFSlot\":1,\"games/FRSRSlot\":1,\"games/FSFBLSlot\":1,\"games/TSFSlot\":1,\"games/TSFBLSlot\":1,\"games/OSHSSlot\":1,\"games/FBCSSlot\":1,\"games/HFSlot\":1,\"games/PVHRSlot\":1,\"games/BCHRSlot\":1,\"games/FBRHRSlot\":1,\"games/TCHHRSlot\":1,\"games/TSDHRSlot\":1,\"games/TNSHRHRSlot\":1,\"games/SRSSlot\":1,\"games/TNSHHRSlot\":1,\"games/BORHRSlot\":1,\"games/BOSHHRSlot\":1,\"games/FCHJHRSlot\":1,\"games/PVSlot\":1,\"games/GVSlot\":1,\"games/OVSlot\":1,\"games/GVHRSlot\":1,\"games/TVSlot\":1,\"games/MFICTSlot\":1,\"games/OTPVSlot\":1,\"games/OTPVHRSlot\":1,\"games/TVHRSlot\":1,\"games/HFCSlot\":1,\"games/SBSlot\":1,\"games/TSSSlot\":1,\"games/KTSlot\":1,\"games/THBSlot\":1,\"games/TADSlot\":1,\"games/DRHCVSlot\":1,\"games/PCHCVSlot\":1,\"games/LTHCVSlot\":1,\"games/PROSlot\":1,\"games/SDSlot\":1,\"games/STOTSlot\":1,\"games/BHESlot\":1,\"games/DWSlot\":1,\"games/FXSJSSlot\":1,\"games/ZWBLSlot\":1,\"games/ZWXBLSlot\":1,\"games/ZWXBLVSlot\":1,\"games/TFWSlot\":1,\"games/VHSlot\":1,\"games/VHHRSlot\":1,\"games/SUCSlot\":1,\"games/FZWBLSlot\":1,\"games/FLKBLSlot\":1,\"games/FLKBLPSlot\":1,\"games/FLKBLGBSlot\":1,\"games/SMCSlot\":1,\"games/FBHBLPBVSlot\":1,\"games/FBHBLCRSlot\":1,\"games/FBHBLBNSlot\":1,\"games/FBHBLCSlot\":1,\"games/FBHBLGOBSlot\":1,\"games/FBHBLPBLSlot\":1,\"games/FBHBLMRSlot\":1,\"games/FBHBLBGSlot\":1,\"games/FBHBLVGOBSlot\":1,\"games/FBHBLSRSlot\":1,\"games/FBHBLALBSlot\":1,\"games/FBHBLPUSlot\":1,\"games/FBHBLCRCSlot\":1,\"games/FBHBLSSlot\":1,\"games/BOSHBLSBSlot\":1,\"games/FBHBLSRBSlot\":1,\"games/FBHBLOSlot\":1,\"games/FBHBOSlot\":1,\"games/FBHOSlot\":1,\"games/FBHBLVBSlot\":1,\"games/FRLKEBLLSlot\":1,\"games/FRLKEBLVJSlot\":1,\"games/TDCSlot\":1,\"games/FVSFSlot\":1,\"games/FVSRSlot\":1,\"games/TNSFSlot\":1,\"games/CRSlot\":1,\"games/BORJWSlot\":1,\"games/SWSSSlot\":1,\"games/SWSSHRSlot\":1,\"games/TNBCSlot\":1,\"games/FVCHSlot\":1,\"games/FVSHRSlot\":1,\"games/FVBPSlot\":1,\"games/FVBPSSlot\":1,\"games/FVCHTSlot\":1,\"games/FVCHTFBSlot\":1,\"games/JWSlot\":1,\"games/FXSFSSlot\":1,\"games/FSAWSlot\":1,\"games/ARSlot\":1,\"games/TWLHSlot\":1,\"games/TNLHSlot\":1,\"games/OHLHSlot\":1,\"games/OHCHTSlot\":1,\"games/FRLHSlot\":1,\"games/FRCHTSlot\":1,\"games/FTBRSlot\":1,\"games/BOSHSlot\":1,\"games/BGSlot\":1,\"games/FRBPSlot\":1,\"games/BGWBSlot\":1,\"games/BGIBSlot\":1,\"games/BGJSlot\":1,\"games/WGSlot\":1,\"games/BGPSSlot\":1,\"games/BGTCSlot\":1,\"games/BGBCSlot\":1,\"games/BGCSlot\":1,\"games/BGHBSlot\":1,\"games/BGSBSlot\":1,\"games/BGABSlot\":1,\"games/BGLBSlot\":1,\"games/OHDHSlot\":1,\"games/FRDCSlot\":1,\"games/GAGKLSlot\":1,\"games/GAGKLVSlot\":1,\"games/GAGKLBSlot\":1,\"games/FRSPSlot\":1,\"games/OHDCSlot\":1,\"games/OHSPSlot\":1,\"games/FVCLHSlot\":1,\"games/FVSPSlot\":1,\"games/BOSHJWSlot\":1,\"games/SCWMSlot\":1,\"games/SCCHSlot\":1,\"games/SCCHCSSlot\":1,\"games/SCCHBSlot\":1,\"games/SCCHBTSlot\":1,\"games/SCCHZSlot\":1,\"games/SCCHSBSlot\":1,\"games/SCCHPSlot\":1,\"games/SCCHPDSlot\":1,\"games/SCCHHSlot\":1,\"games/TWBHCHSlot\":1,\"games/OHSHSlot\":1,\"games/FRSHSlot\":1,\"games/FYHBSlot\":1,\"games/EWCHSlot\":1,\"games/TNCLHSlot\":1,\"games/TNBPSlot\":1,\"games/TWCLHSlot\":1,\"games/TWBPSlot\":1,\"games/TWSPSlot\":1,\"games/TWSRSlot\":1,\"games/TSDIBSlot\":1,\"games/FRCLHSlot\":1,\"games/OHCLHSlot\":1,\"games/OHBPSlot\":1,\"games/FVSHSlot\":1,\"games/TNSHRSlot\":1,\"games/TNSHSlot\":1,\"games/TNCHTSlot\":1,\"games/FSHBLBVSlot\":1,\"games/TWSHSlot\":1,\"games/TWSHRSlot\":1,\"games/TWCHTSlot\":1,\"games/FSHBLVSlot\":1,\"games/FSHBLCSlot\":1,\"games/FSHBLBSlot\":1,\"games/FSHBLMAKSlot\":1,\"games/FSHBLBPSlot\":1,\"games/FSHBLVLSlot\":1,\"games/FSHBLSBSlot\":1,\"games/FSHBLNBHSlot\":1,\"games/FSHBLOBSlot\":1,\"games/FSHBLVBSlot\":1,\"games/FRVHBLSlot\":1,\"games/FSHBLOXSlot\":1,\"games/FSHBLVOXSlot\":1,\"games/FRSCBLBTSlot\":1,\"games/FRSCBLBSlot\":1,\"games/FRSCBLCBSlot\":1,\"games/FRSCBLMRSlot\":1,\"games/FRSCBLMDSlot\":1,\"games/TSHBLVSlot\":1,\"games/VNBLVSlot\":1,\"games/FDHBLVSlot\":1,\"games/FHEBLVSlot\":1,\"games/FHEBLPNSlot\":1,\"games/FHEBLVCSlot\":1,\"games/FHEBLVDSlot\":1,\"games/FHEBLBYSlot\":1,\"games/FHEBLCCSlot\":1,\"games/FHEBLBCSlot\":1,\"games/FHEBLBFSlot\":1,\"games/FHEBLKNSlot\":1,\"games/FHEBLKBSlot\":1,\"games/FHEBLVMKSlot\":1,\"games/FHEBLVVDCSlot\":1,\"games/FHEBLVBSlot\":1,\"games/CBLOVSlot\":1,\"games/BCBLVKRSlot\":1,\"games/BCBLMBVSlot\":1,\"games/BCBLVBCSlot\":1,\"games/BCBLVABSlot\":1,\"games/FHEBLHBVSlot\":1,\"games/FHEBLJBSlot\":1,\"games/FHEBLBPSlot\":1,\"games/FHEBLVHSlot\":1,\"games/FHEBLSTSlot\":1,\"games/FHEBLFSlot\":1,\"games/FHEBLCSlot\":1,\"games/FSHBLLSlot\":1,\"games/FSHBLGSlot\":1,\"games/FSHBLFPSlot\":1,\"games/SCBLMSlot\":1,\"games/SCBLTPSlot\":1,\"games/FHEBLNSlot\":1,\"games/FHBLVSlot\":1,\"games/FSCBLVSlot\":1,\"games/FSCBLVCSlot\":1,\"games/FSCBLVBOSlot\":1,\"games/FSCBLVGBSlot\":1,\"games/PFSCBLSlot\":1,\"games/FFSCBLSlot\":1,\"games/FRSCBLMBSlot\":1,\"games/FSCBLPNSlot\":1,\"games/FSCBLMBSlot\":1,\"games/FRSCBLBHSlot\":1,\"games/FSCBLVPBSlot\":1,\"games/FRSCBLUSlot\":1,\"games/FRSCBLSSSlot\":1,\"games/SCBLVSlot\":1,\"games/FBHBLVSlot\":1,\"games/FBRSlot\":1,\"games/OHBRSlot\":1,\"games/TWBRSlot\":1,\"games/TNBRSlot\":1,\"games/FBHBLMBVSlot\":1,\"games/BHBLVSlot\":1,\"games/FSFBLVSlot\":1,\"games/TSFBLVSlot\":1,\"games/SACBLVSlot\":1,\"games/SACBLPUSlot\":1,\"games/ZWBLVSlot\":1,\"games/FZWBLVSlot\":1,\"games/FLKBLVSlot\":1,\"games/TNSPSlot\":1,\"games/FRLKEBLSlot\":1,\"games/FBHBLPBSlot\":1,\"games/PRCJWSlot\":1,\"games/PRRJWSlot\":1,\"games/ODJWSlot\":1,\"games/SVSlot\":1,\"games/OTSVSlot\":1,\"games/OTSVSSlot\":1,\"games/SMSlot\":1,\"games/TNJHSlot\":1,\"games/TNSRSlot\":1,\"games/ALGKLSlot\":1,\"games/ALGKLVSlot\":1,\"games/MHSlot\":1,\"games/FRLKEBLVSlot\":1,\"games/FVJHSlot\":1,\"games/TNJRSlot\":1,\"games/FVJRSlot\":1,\"games/TWJHSlot\":1,\"games/FRJHSlot\":1,\"games/OHJHSlot\":1,\"games/OHJRSlot\":1,\"games/FRJRSlot\":1,\"games/TWJRSlot\":1,\"games/BOSHBLSlot\":1,\"games/PGASlot\":1,\"games/OTPGASlot\":1,\"games/FYHBWSlot\":1,\"games/BOSHBLVSlot\":1,\"games/MDBLSlot\":1,\"games/FBHBLBSlot\":1,\"games/FBHBLZSlot\":1,\"games/MDBLVSlot\":1,\"games/FHEBLMSlot\":1,\"games/RORGKLSlot\":1,\"games/TCHBSlot\":1,\"games/SXSFSSlot\":1,\"games/RORGKLVSlot\":1,\"games/QASlot\":1,\"games/FBHSPSlot\":1,\"games/FSHBLMKSlot\":1,\"games/FBCBSlot\":1,\"games/TSHBLSSlot\":1,\"games/OGGKLSlot\":1,\"games/CCGKLSlot\":1,\"games/CKHGKLSlot\":1,\"games/LKHGKLSlot\":1,\"games/SCBLHSlot\":1,\"games/FBHBLGPBVSlot\":1,\"games/TNLRSlot\":1,\"games/FVLRSlot\":1,\"games/TWLRSlot\":1,\"games/FRLRSlot\":1,\"games/OHLRSlot\":1,\"games/FRLKEBLCSlot\":1,\"games/FHBLVPSlot\":1,\"games/OTSRSlot\":1,\"games/OGGKLVSlot\":1,\"games/SCBLTSlot\":1,\"games/SCBLVPSlot\":1,\"games/FRLKEBLVBMSlot\":1,\"games/EITHSlot\":1,\"games/EITHHRSlot\":1,\"games/EITRSlot\":1,\"games/EITRHRSlot\":1,\"games/ORSlot\":1,\"games/BCBLSlot\":1,\"games/BCBLNBSlot\":1,\"games/BCSSlot\":1,\"games/BCSHRSlot\":1,\"games/SCSSlot\":1,\"games/SCSHRSlot\":1,\"games/MFTDSlot\":1,\"games/BCBLVSlot\":1,\"games/FBHBLBWSlot\":1,\"games/FHEBLBSlot\":1,\"games/SBBLSlot\":1,\"games/BHBLSSlot\":1,\"games/FHBLVJSlot\":1,\"games/FHBLGSlot\":1,\"games/FHBLGGSlot\":1,\"games/FHBLLSlot\":1,\"games/FSHBLMSlot\":1,\"games/SBBLVSlot\":1,\"games/SBBLESlot\":1,\"games/FRSCBLKSlot\":1,\"games/FVDRSlot\":1,\"games/FRDRSlot\":1,\"games/OHDRSlot\":1,\"games/TNDRSlot\":1,\"games/TWDRSlot\":1,\"games/OTSDSlot\":1,\"games/BPBLBSlot\":1,\"games/SPBLBSlot\":1,\"games/FRSRBSlot\":1,\"games/BDBLSlot\":1,\"games/BDBLVMBSlot\":1,\"games/BDMBLVSlot\":1,\"games/BDBLVSlot\":1,\"games/TNTJSlot\":1,\"games/TNTJHRSlot\":1,\"games/BFCSlot\":1,\"games/BFCHRSlot\":1,\"games/HFTTSlot\":1,\"games/HFTTHRSlot\":1,\"games/HFMSSlot\":1,\"games/HFMSHRSlot\":1,\"games/HRFMSSlot\":1,\"games/AVRSlot\":1,\"games/KPBSPSlot\":1,\"games/KPBSPHRSlot\":1,\"games/SSSPSlot\":1,\"games/RVSlot\":1,\"games/RVHRSlot\":1,\"games/LWHWTXTSlot\":1,\"games/FRSRBHRSlot\":1,\"games/SACRSlot\":1,\"games/PRRJWHRSlot\":1,\"games/ARMSSlot\":1,\"games/BSBLSlot\":1,\"games/BSBLVSlot\":1,\"games/JCCSlot\":1,\"games/JCESlot\":1,\"games/ORHRSlot\":1,\"games/TLBLSlot\":1,\"games/TLBLVSlot\":1,\"games/TSDPWSlot\":1,\"games/SPBLBVSlot\":1,\"games/BPBLBVSlot\":1,\"games/QAHRSlot\":1,\"games/OTSDHRSlot\":1,\"games/BLCBLSlot\":1,\"games/FRSHBLBSlot\":1,\"games/FRSHBLBVSlot\":1,\"games/MSPBLBSlot\":1,\"games/MSPBLBVSlot\":1,\"games/JCCHRSlot\":1,\"games/MBPBLBSlot\":1,\"games/MBPBLBVSlot\":1,\"games/FRSDBLSlot\":1,\"games/BLHIBBLSlot\":1,\"games/BLJBLSlot\":1,\"games/GKBLCSlot\":1,\"games/GKBLKSlot\":1,\"games/GKBLMKSlot\":1,\"games/GKBLBSlot\":1,\"games/GKBLMSlot\":1,\"games/GKBLGSlot\":1,\"games/GKBLMBSlot\":1,\"games/GKBLSSlot\":1,\"games/GKBLSlot\":1,\"games/IGKBLSlot\":1,\"games/WGKBLSlot\":1,\"games/PGAASlot\":1,\"games/BLCBLVSlot\":1,\"games/LWHWTXTHRSlot\":1,\"games/FRBRSSlot\":1,\"games/FRBRSHRSlot\":1,\"games/GKBLVSlot\":1,\"games/IGKBLVSlot\":1,\"games/WGKBLVSlot\":1,\"games/JCHWSlot\":1,\"games/STOTHRSlot\":1,\"games/FRSDBLVSlot\":1,\"games/OTPGAHRSlot\":1,\"games/GKBBLSlot\":1,\"games/BGKBLVSlot\":1,\"games/BLBLSlot\":1,\"games/BLIBLSlot\":1,\"games/BLIBLVSlot\":1,\"games/BLWBLSlot\":1,\"games/BLWBLVSlot\":1,\"games/GKBLHBSlot\":1,\"games/GKBLVHBSlot\":1,\"games/FRSHCBLBSlot\":1,\"games/FRSHCBLBVSlot\":1,\"games/BLHIBBLVSlot\":1,\"games/BLHBLSlot\":1,\"games/BLBLVSlot\":1,\"games/OHSCSlot\":1,\"games/BLHBLVSlot\":1,\"games/ARMSHRSlot\":1,\"games/BLCCBLSlot\":1,\"games/JCHWHRSlot\":1,\"games/BLSBLSlot\":1,\"games/BLSBLVSlot\":1,\"games/BLCCBLVSlot\":1,\"games/JCSHSlot\":1,\"features/gakl-jackpot-v1\":1,\"features/gakl-jackpot-base\":1,\"features/replayer\":1,\"features/high-cash-slot\":1,\"features/prize-pops\":1,\"features/scratch-prize-pops\":1,\"components/scratch-modal-popups-background\":1,\"components/scratch-general-settings\":1,\"features/gamble-styles\":1,\"features/custom-result-styles\":1,\"features/bl-jackpot-styles\":1,\"packages_slot-components_jackpot-stats_src_egt_view_react_index_tsx\":1,\"features/premium-link-jackpot-styles\":1,\"features/gift-spins-styles\":1,\"features/mystery-jackpot-styles\":1,\"features/gakl-jackpot-styles\":1,\"features/bl-boost-jackpot-styles\":1,\"packages_slot-games_sacrslot_src_egt_features_hold-and-win_src_egt_hold-and-win_styles_js\":1,\"packages_slot-games_tsdpwslot_src_egt_features_pick-and-win_src_egt_pick-and-win_styles_js\":1,\"features/cash-heat-styles\":1,\"packages_scratch-components_scratch-jackpot-stats_src_egt_view_react_index_tsx\":1};\n\tif(installedCssChunks[chunkId]) promises.push(installedCssChunks[chunkId]);\n\telse if(installedCssChunks[chunkId] !== 0 && cssChunks[chunkId]) {\n\t\tpromises.push(installedCssChunks[chunkId] = loadStylesheet(chunkId).then(() => {\n\t\t\tinstalledCssChunks[chunkId] = 0;\n\t\t}, (e) => {\n\t\t\tdelete installedCssChunks[chunkId];\n\t\t\tthrow e;\n\t\t}));\n\t}\n};\n\n// no hmr","// no baseURI\n\n// object to store loaded and loading chunks\n// undefined = chunk not loaded, null = chunk preloaded/prefetched\n// [resolve, reject, Promise] = chunk loading, 0 = chunk loaded\nvar installedChunks = {\n\t\"index\": 0\n};\n\n__webpack_require__.f.j = (chunkId, promises) => {\n\t\t// JSONP chunk loading for javascript\n\t\tvar installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined;\n\t\tif(installedChunkData !== 0) { // 0 means \"already installed\".\n\n\t\t\t// a Promise means \"currently loading\".\n\t\t\tif(installedChunkData) {\n\t\t\t\tpromises.push(installedChunkData[2]);\n\t\t\t} else {\n\t\t\t\tif(!/^(games\\/(B(C(|BL|S)Slot|L(C|CC|S)BLSlot|O(SH(|BL)Slot|RSlot)|([DHS]BL|FC|G|PBLB)Slot)|EIT[HR]Slot|F(B(H(|BL|S)Slot|[CR]Slot)|H((|E)BL|B|E)Slot|R(S((H(|C)BL|R)B|DBL)Slot|(BRS|LKEBL)Slot)|S([CFH]BL|HSA)Slot|((DH|LK|ZW)BL|CHJ|VBP|VCHT|XSFS)Slot)|G(AGKL|KBL|V)Slot|HF(|MS|TT)Slot|JC(C|HW)Slot|M([BS]PBLB|DBL)Slot|O(T(PGA|PV|SD|SV)Slot|(GGKL|R)Slot)|P(CHC|RRJW|V)Slot|S(C(|BL|CH|S)Slot|((AC|B)BL|M|PBLB|RS|T|TOT|WSS)Slot)|T(N(SH(|R)Slot|TJSlot)|S([FH]BL|D)Slot|(CH|LBL|V)Slot)|V(H|N|NBL)Slot|ZW(|X)BLSlot|((AL|ROR)GKL|(DR|LT)HC|ARMS|KPBSP|LWHWTXT|QA|RV)Slot)|components\\/scratch\\-general\\-settings|features\\/replayer)$/.test(chunkId)) {\n\t\t\t\t\t// setup Promise in chunk cache\n\t\t\t\t\tvar promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject]));\n\t\t\t\t\tpromises.push(installedChunkData[2] = promise);\n\n\t\t\t\t\t// start chunk loading\n\t\t\t\t\tvar url = __webpack_require__.p + __webpack_require__.u(chunkId);\n\t\t\t\t\t// create error before stack unwound to get useful stacktrace later\n\t\t\t\t\tvar error = new Error();\n\t\t\t\t\tvar loadingEnded = (event) => {\n\t\t\t\t\t\tif(__webpack_require__.o(installedChunks, chunkId)) {\n\t\t\t\t\t\t\tinstalledChunkData = installedChunks[chunkId];\n\t\t\t\t\t\t\tif(installedChunkData !== 0) installedChunks[chunkId] = undefined;\n\t\t\t\t\t\t\tif(installedChunkData) {\n\t\t\t\t\t\t\t\tvar errorType = event && (event.type === 'load' ? 'missing' : event.type);\n\t\t\t\t\t\t\t\tvar realSrc = event && event.target && event.target.src;\n\t\t\t\t\t\t\t\terror.message = 'Loading chunk ' + chunkId + ' failed.\\n(' + errorType + ': ' + realSrc + ')';\n\t\t\t\t\t\t\t\terror.name = 'ChunkLoadError';\n\t\t\t\t\t\t\t\terror.type = errorType;\n\t\t\t\t\t\t\t\terror.request = realSrc;\n\t\t\t\t\t\t\t\tinstalledChunkData[1](error);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t\t__webpack_require__.l(url, loadingEnded, \"chunk-\" + chunkId, chunkId);\n\t\t\t\t} else installedChunks[chunkId] = 0;\n\t\t\t}\n\t\t}\n};\n\n// no prefetching\n\n// no preloaded\n\n// no HMR\n\n// no HMR manifest\n\n__webpack_require__.O.j = (chunkId) => (installedChunks[chunkId] === 0);\n\n// install a JSONP callback for chunk loading\nvar webpackJsonpCallback = (parentChunkLoadingFunction, data) => {\n\tvar [chunkIds, moreModules, runtime] = data;\n\t// add \"moreModules\" to the modules object,\n\t// then flag all \"chunkIds\" as loaded and fire callback\n\tvar moduleId, chunkId, i = 0;\n\tif(chunkIds.some((id) => (installedChunks[id] !== 0))) {\n\t\tfor(moduleId in moreModules) {\n\t\t\tif(__webpack_require__.o(moreModules, moduleId)) {\n\t\t\t\t__webpack_require__.m[moduleId] = moreModules[moduleId];\n\t\t\t}\n\t\t}\n\t\tif(runtime) var result = runtime(__webpack_require__);\n\t}\n\tif(parentChunkLoadingFunction) parentChunkLoadingFunction(data);\n\tfor(;i < chunkIds.length; i++) {\n\t\tchunkId = chunkIds[i];\n\t\tif(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {\n\t\t\tinstalledChunks[chunkId][0]();\n\t\t}\n\t\tinstalledChunks[chunkId] = 0;\n\t}\n\treturn __webpack_require__.O(result);\n}\n\nvar chunkLoadingGlobal = self[\"webpackChunkgame_client_lerna\"] = self[\"webpackChunkgame_client_lerna\"] || [];\nchunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));\nchunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));","","// startup\n// Load entry module and return exports\n// This entry module depends on other loaded chunks and execution need to be delayed\nvar __webpack_exports__ = __webpack_require__.O(undefined, [\"vendors\"], () => (__webpack_require__(\"./packages/client/src/egt/index.ts\")))\n__webpack_exports__ = __webpack_require__.O(__webpack_exports__);\n",""],"names":[],"sourceRoot":""}